Binární strom Rotation

hlasů
3

Jsem pracující na realizaci AVL vyhledávací strom. Zatím jsem dokončil kódovací část a já jsem začal testovat to pro chyby. Zjistil jsem, že moje uzel metody rotace jsou odposlouchávány a proboha nemohu pochopit, v čem je problém.

Algoritmus pracuje tak, jak má na papíře, ale když je vykonáván na stroji je dobře ... nevrací uzly stromu.

Tato metoda používá k otočení uzlu doleva: http://pastebin.com/mPHj29Af

bool avl_search_tree::avl_tree_node::rotate_left()
{
    if (_right_child != NULL) {
        avl_tree_node *new_root = _right_child;
 
        if (_parent != NULL) {
            if (_parent->_left_child == this) {
                _parent->_left_child = new_root;
            } else {
                _parent->_right_child = new_root;
            }
        }
 
        new_root->_parent = _parent;
        _parent = new_root;
 
        _right_child = new_root->_left_child;
        new_root->_left_child = this;
 
        if (_right_child != NULL) {
            _right_child->_parent = this;
        }
 
        //update heights
        update_height();
        new_root->update_height();
 
        return true;
    }
 
    return false;
}

V mém způsobu vkládání I komentoval AVL vyrovnávání část a místo toho jsem prostě se snaží otočit nově vložený uzel doleva. Výsledek pro vkládání celých čísel ve vzestupném pořadí: můj strom obsahuje pouze prvotní kořen (první uzel vložen) a všechny ostatní uzly jsou unikly.

Jakákoli pomoc při identifikaci problému je vysoce ceněn jako já začínám zbláznit.

Pro připomenutí: v případě, že nepoužívám žádné střídání strom nebude úniku uzlů a funguje jako normální nevyváženého binárního vyhledávacího stromu (pro vkládání a vyhledávání).

Edit: Vzhledem k AJG85 komentáři Přidám pozorování:

Přidal jsem printf ‚kontroly‘ metody destruktor avl_search_tree :: avl_tree_node který vytiskne hodnotu klíče (v mém případě 32 bitová celá čísla) před vyčištění a do vložky způsobu avl_search_tree který bude tisknout tlačítko právě vložili.

Pak v EntryPoint programu I přidělit avl_search_tree na haldě a přidat klíče k ní ve vzestupném pořadí a poté jej odstraňte.

Se zapnutým AVL Vyrovnávání se mi zobrazí následující výstup v terminálu:

bool avl_search_tree::insert(const int&) : 1
bool avl_search_tree::insert(const int&) : 2
bool avl_search_tree::insert(const int&) : 3
bool avl_search_tree::insert(const int&) : 4
bool avl_search_tree::insert(const int&) : 5
bool avl_search_tree::insert(const int&) : 6
bool avl_search_tree::insert(const int&) : 7
bool avl_search_tree::insert(const int&) : 8
avl_search_tree::avl_tree_node::~avl_tree_node() : 1

Což znamená, že thatall inzercí byly úspěšné, ale jen kořen byl odstraněn.

S AVL Vyvažování vyjádřil se, že to funguje jako normální binární vyhledávací strom. Terminál výstup je:

bool avl_search_tree::insert(const int&) : 1
bool avl_search_tree::insert(const int&) : 2
bool avl_search_tree::insert(const int&) : 3
bool avl_search_tree::insert(const int&) : 4
bool avl_search_tree::insert(const int&) : 5
bool avl_search_tree::insert(const int&) : 6
bool avl_search_tree::insert(const int&) : 7
bool avl_search_tree::insert(const int&) : 8
avl_search_tree::avl_tree_node::~avl_tree_node() : 1
avl_search_tree::avl_tree_node::~avl_tree_node() : 2
avl_search_tree::avl_tree_node::~avl_tree_node() : 3
avl_search_tree::avl_tree_node::~avl_tree_node() : 4
avl_search_tree::avl_tree_node::~avl_tree_node() : 5
avl_search_tree::avl_tree_node::~avl_tree_node() : 6
avl_search_tree::avl_tree_node::~avl_tree_node() : 7
avl_search_tree::avl_tree_node::~avl_tree_node() : 8

Což znamená, že vše je řádně vyčištěna.

A teď ... jak jsem dospěl k závěru, že metody rotace jsou problémy? Podle komentovaného vyváženosti AVL podprogram jsem přidal řádek, který se otáčí každý nově vložený uzel doleva. Výsledek? Stejně jako v případě, že AVL Balancing podprogram byl povolen.

A pokud jde o metodu update_height (), to nic nemění strukturu stromu v žádném případě.

Doufám, že to bude to objasnit.

Edit 2:

Vyjasnit některé další věci, jeho je, jak je implementována avl_tree_node destruktor:

avl_search_tree::avl_tree_node::~avl_tree_node()
{
    printf(%s : %d\n, __PRETTY_FUNCTION__, *_key);

    if (_left_child != NULL) {
        delete _left_child;
    }

    if (_right_child != NULL) {
        delete _right_child;
    }

    if (_key != NULL) {
        delete _key;
    }
}

_left_child a _right_child jsou ukazatele na avl_tree_node objekty na haldě.

Edit 3:

Díky AGJ85 je 2. komentáři jsem našel problém. V mých otáčet metod jsem zapomněla, že jsem vlastně muset aktualizovat kořenový ukazatel stromový do nové kořeni, když byl kořen posunut.

V podstatě kořen stromu byla vždy ukazoval na první vloženou uzlu a bez aktualizace ukazatel v případě potřeby, moji Otočení metody by unikat kořen nové větve, která byla ve skutečnosti nakonfigurován správně. :)

Děkuji AGJ85!

Položena 02/08/2011 v 18:19
zdroj uživatelem
V jiných jazycích...                            


3 odpovědí

hlasů
2

EDIT - Damn - neviděl jsem, že problém je již vyřešen (odpověď na otázku). Přesto, možná tam je nějaký non-odpověď tipů v této hodnotě zachraňování.

Nemám pečlivě kontrolovány, ale myslím, že špatně na tomto řádku ...

_right_child = new_root->_left_child;

a že problém je, že jste již přepsán new_root->_left_childv řadě ...

_parent->_left_child = new_root;

Co myslím, že byste měli udělat, je na začátku, mají blok místních definic, jako je ...

avl_tree_node *orig_parent      = _parent;
avl_tree_node *orig_this        = this;
avl_tree_node *orig_left_child  = _left_child;
avl_tree_node *orig_right_child = _right_child;

Pak pomocí orig_lokální proměnné jako zdroje pro pozdější úkoly. Tím se ušetří určité množství obav o toku dat pomocí různých ukazatelů v průběhu otáčení. Optimalizátor by měla zbavit jakékoliv nadbytečné práce v hodnotě starostí v tomto, a tam není moc tak jako tak.

Pár extra body ...

Za prvé, C ++ (A a C) normy rezervní identifikátory s předními podtržítka, a s dvojitými podtržítka. Je to tvrdil, že se můžete dostat překvapení interakce se standardními a překladače dodané knihovny, pokud nechcete respektovat - Myslím, že by musel být makro-související pro členské identifikátory, ačkoli. Koncové podtržítka jsou v pořádku - mám tendenci používat je na patří stráže.

Běžným konvence členských proměnných je přidat předním mnebo m_. Ještě častější, pravděpodobně nebude mít žádný speciální předponu nebo příponu vůbec.

Za druhé, může (ale nemusí) být snadnější realizaci AVL stromy, které nemají nadřazených odkazy uložené v uzlech. Jsem zatím není implementován AVL stromy sám, ale já realizovat červeno-černém stromy jednou. Řada algoritmů je třeba zahrnout rekurzivní vyhledávání jako první krok - nemůžete prostě standardní vyhledávání, které pamatuje na nalezený uzel, ale zahodí cestu dolů do tohoto uzlu. Nicméně, rekurzivní implementace není příliš špatný, a tam je méně ukazatelů žonglovat.

Konečně, obecný tip - snaží „nanečisto“ algoritmus takhle snadno zakopnout vás, pokud přísně pracovat přes to krok za krokem, a nechte si zobrazit všechny zdroje informací, které jsou relevantní (jsem již upravený to?) Na každý krok. Je velmi snadné se dostat do zvyk přeskakování některých detailů na rychlost. Užitečná stroj asistované nanečisto je spustit kód krok za krokem v debugger, a uvidíme, jestli se výsledky na každém kroku souhlasit s papírovou nanečisto.

EDIT - ještě jedna poznámka - nebudu říkat to tip, protože jsem si jistý, v tomto kontextu. I obvykle implementovat datovou strukturu uzlů s jednoduchými structs - žádná data úkrytu, málo-li kterýkoli člen funkcí. Většina kódu je vedena odděleně od datové struktury, často ve třídě „nástroj“. Vím, že to zlomí starého „tvar kreslí sebe“ princip OOP, ale IMO to funguje lépe v praxi.

Odpovězeno 02/08/2011 v 20:34
zdroj uživatelem

hlasů
3

Díky AGJ85 je 2. komentáři jsem našel problém. V mých otáčet metod jsem zapomněla, že jsem vlastně muset aktualizovat kořenový ukazatel stromový do nové kořeni, když byl kořen posunut.

V podstatě kořen stromu byla vždy ukazoval na první vloženou uzlu a bez aktualizace ukazatel v případě potřeby, moji Otočení metody by unikat kořen nové větve, která byla ve skutečnosti nakonfigurován správně. :)

Odpovězeno 03/08/2011 v 10:03
zdroj uživatelem

hlasů
1

Vidím, že jste našli chybu, které jste hledali v kódu. (Jak říkáte, jste nebyli aktualizaci kořenový strom ukazatel na nový kořenový adresář, když kořen změnila. Je to společný vzor pro seznamy a strom Vložit / Smazat metody vrátit ukazatel čele seznamu nebo kořen stromu, a je-li Pamatujete si, že paradigma neudělá chybu znovu.)

Na vyšší úrovni pohledu, techniku jsem použil, aby se předešlo problémům s AVL strom nebo Red-Black Tree kód je místo toho použít aa strom , který má podobný výkon k nim, za použití O (n) prostoru a O (log n) čas pro Insert, Delete, a vyhledávání. Nicméně, AA stromy jsou podstatně jednodušší kód.

Odpovězeno 04/08/2011 v 16:55
zdroj uživatelem

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