Vymazat strom binárního vyhledávání?

hlasů
0

Čtu prostřednictvím binárního stromu odstranit algoritmus uzlu použité v knize Datové struktury a algoritmy: Komentovaný reference s příklady

na straně 34, pouzdro 4 (Odstranit uzel, který má obě pravé a levé dílčí stromů), následující algoritmus je popsán v knize vypadá nefunguje, pravděpodobně Možná se mýlím, že mi někdo pomoci, co jsem chybí.

//Case 4
get largestValue from nodeToRemove.Left
FindParent(largestValue).Right <- 0
nodeToRemove.Value<-largestValue.Value

Jak následující řádek odstraní největší hodnotu z podstromu FindParent(largestValue).Right <- 0

Položena 29/06/2010 v 21:09
zdroj uživatelem
V jiných jazycích...                            


5 odpovědí

hlasů
1

Myšlenka je prostě vzít hodnotu od největšího uzlu na levé straně a přesunout ji do uzlu, který je odstraněn, tj neodstraňujte uzel vůbec, stačí vyměnit jeho obsah. Pak jste prořezávat se uzel s hodnotou jste přesunuli do „maže“ uzlu. To udržuje strom pořadí s hodnotou každého uzlu je větší než to všechno zbylo děti a menší, než to všechno je pravda děti.

Odpovězeno 29/06/2010 v 21:16
zdroj uživatelem

hlasů
1

Mám-li porozumět pseudo-kódu, funguje to v obecném případě, ale selhává v „jednom uzlu v levém podstromu“ případ. Dobrý postřeh.

Efektivně nahradí node_to_remove s largest_value ze je to left subtree (také vynuluje starý largest_value uzel).

Všimněte si, že v BST, levý podstrom node_to_remove bude všechno být menší než node_to_remove. Správná podstrom node_to_remove všechno bude větší než node_to_remove. Takže pokud budete mít největší uzel v levém podstromu, bude zachovávat invariant.

Pokud se jedná o „jeden uzel v případě podstromu“, bude to zničí pravý podstrom místo. Lame :(

Jako Vivin poukazuje na to, že také nepodaří znovu připojit levé děti largestNode.

Odpovězeno 29/06/2010 v 21:16
zdroj uživatelem

hlasů
6

Při odstraňování uzel se dvěma dětmi, můžete si vybrat buď svůj v pořadí následníků uzlu nebo její in-pořadí předchůdce uzlu. V tomto případě je to najít největší hodnotu v levém podstromu (to znamená nejvíce vpravo dítě jejím levém podstromu), což znamená, že je najít uzlu v objednávku předchůdce uzlu.

Jakmile najdete náhradní uzel, nemáte skutečně odstranit uzel, které mají být odstraněny. Namísto toho budete mít hodnotu od nástupnické uzlu a uloží tuto hodnotu do uzlu, který chcete odstranit. Potom odstraňte uzel následníka. Tím zvýšíte binární vlastnost search-tree, protože si můžete být jisti, že uzel jste vybrali bude mít hodnotu, která je nižší než hodnoty ze všech dětí v původní uzel v levém podstromu, a vyšší než než hodnoty ze všech dětí v původní uzel v pravém podstromu.

UPRAVIT

Po přečtení svůj dotaz trochu víc, myslím, že jsem našel problém.

Obvykle to, co máte vedle deletefunkce je replacefunkce, která nahradí uzel v otázce. Myslím, že je třeba změnit tento řádek kódu:

FindParent(largestValue).Right <- 0

na:

FindParent(largestValue).Right <- largestValue.Left

V případě, že largestValueuzel nemá levé dítě, můžete jednoduše dostat nullnebo 0. Pokud tomu tak má levý dítě, že dítě se stane náhradou za largestValueuzlu. Takže máte pravdu; Kód nebere v úvahu scénář, že largestValueuzel může mít levé dítě.

Další EDIT

Vzhledem k tomu, že jste zaslali jen úryvek, nejsem si jistý, co kontext kódu. Ale úryvek as vykázala nezdá se, že mají problém, navrhnout (nahrazení špatně uzel). Obvykle existují tři případy, ale všiml jsem si, že poznámka ve fragmentu říká //Case 4(takže možná tam je nějaký jiný kontext).

Dříve, zmiňoval jsem se k tomu, že deleteobvykle přichází s replace. Takže pokud se vám zdá largestValueuzlu, jej odstranit podle dvou jednoduchých případech (uzel bez dětí, a uzel s jedním dítětem). Takže pokud se díváte na pseudokódem odstranit uzel se dvěma dětmi, to je to, co budete dělat:

get largestValue from nodeToRemove.Left
nodeToRemove.Value <- largestValue.Value

//now replace largestValue with largestValue.Left    

if largestValue = largestValue.Parent.Left then   
   largestValue.Parent.Left <- largestValue.Left //is largestValue a left child?
else //largestValue must be a right child
   largestValue.Parent.Right <- largestValue.Left

if largestValue.Left is not null then
   largestValue.Left.Parent <- largestValue.Parent

Připadá mi divné, že datové struktury a algoritmy kniha by vynechat tuhle část, takže se přikláním k názoru, že kniha má dále rozdělit vypuštění do několika dalších případech (protože tam jsou tři standardní případy), aby bylo snazší rozumět.

Dokázat, že výše uvedený kód funguje, zvažte následující stromu:

  8
 / \
7   9

Řekněme, že chcete smazat 8. Při pokusu najít largestValueod nodeToRemove.Left. To vám dává 7, protože levá sub-strom má jen jedno dítě.

Pak můžete udělat:

nodeToRemove.Value <- largestValue.Value

Což znamená:

8.value <- 7.Value

nebo

8.Value <- 7

Takže teď váš strom vypadá takto:

  7
 / \
7   9

Musíte se zbavit náhradního uzlu, a tak budete nahradit largestValues largestValue.Left(což je null). Takže nejprve zjistit, jaké dítě 7je:

if largestValue = largestValue.Parent.Left then

Což znamená:

if 7 = 7.Parent.Left then

nebo:

if 7 = 8.Left then

Vzhledem k tomu, 7je 8levé dítěte, je třeba nahradit 8.Lefts 7.Right( largestValue.Parent.Left <- largestValue.Left). Vzhledem k tomu 7nemá žádné děti, 7.Leftje nulová. Tak largestValue.Parent.Leftdostane přiděleno na null (který účinně odstraňuje jeho levé dítě). Takže to znamená, že jste skončili s tímto stromem:

  7
   \
    9
Odpovězeno 29/06/2010 v 21:17
zdroj uživatelem

hlasů
0

Může to větší smysl, když se podíváte na Wikipedii vzít na tu část algoritmu:

Odstranění uzlu se dvěma dětmi : Volání uzel, které mají být smazány „N“. Neodstraňujte N. Místo toho, zvolit její in-pořadí následníků uzlu nebo její in-pořadí předchůdce uzel, „R“. Nahradit hodnotu N s hodnotou R, odstranit R. (Poznámka: R sám má až jedno dítě.)

Všimněte si, že vzhledem k tomu, algoritmus vybere předchůdce uzel v-pořadí.

Edit: to, co se zdá, že chybí možnost, že R (k použití Wikipedie terminologii) má jedno dítě. Rekurzivní smazat lepší by mohlo fungovat.

Odpovězeno 29/06/2010 v 21:20
zdroj uživatelem

hlasů
1

Myslím, že budete muset vyjasnit, co nefunguje.

Pokusím se vysvětlit pojem vypuštění do binárního stromu v případě, že to pomůže.

Umožňuje předpokládat, že máte uzel ve stromu, který má dva podřízené uzly, které chcete odstranit. Ve stromu pod řekněme, že chcete smazat uzel B
           je
         / \
       b c
     / \ / \
   d e f g

Když jsme se odstranit uzel musíme znovu připojit jeho závislé uzly.

tj. Když jsme se odstranit b musíme znovu připojit uzly D a E.

Víme, že levá uzly jsou menší než správných uzlů v hodnotě a že mateřské uzly jsou mezi levými a pravými uzlu s hodnoty. V tomto případě d <b a b <e. Toto je část definice binárního stromu.

Co je to o něco méně zřejmé, je, že e <a. Takže to znamená, že můžeme nahradit b s e. Nyní jsme reattached e musíme znovu připojit d.

Jak již bylo řečeno d <e, takže můžeme připojit e jako levé uzlu e.

Vypuštění je nyní kompletní.

(Btw Proces přesunutí uzlu na strom a přeskupit Závislé uzly v této módě je známá jako podpora uzel. Můžete také podporovat uzel bez vymazání další uzly).



         / \
       d c
         \ / \
          e f g

Všimněte si, že tam je další naprosto legitimní výsledek deleteing uzlu b. Pokud bychom se rozhodli podpořit uzlu D namísto uzlu e strom bude vypadat takto.



         / \
       e c
     / / \
   d f g

Odpovězeno 29/06/2010 v 21:44
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more