Obsah / Utility / RBTREE / Vložení položky do RB-stromu
Zdrojový kód: INCLUDE\UTIL\RBTREE.INC, UTIL\RBTREE.ASM
|
Funkce RBTreeInsert vloží novou položku do RB-stromu. Vstupními parametry funkce jsou v registru EAX ukazatel na nově vkládanou položku s vyplněnými uživatelskými daty, v registru EDX ukazatel na kořen stromu a v registru ESI ukazatel na porovnávací callback funkci. Je-li položka úspěšně vložena, je navrácen vynulovaný příznak CF a v registru EBX je navrácen ukazatel na novou položku, jeho obsah tedy odpovídá obsahu registru EAX. Pokud již existuje položka se stejnými daty (ve stromu se nesmí vyskytovat dvě stejné položky), je navrácen příznak chyby CY (nastavený příznak CF) a registr EBX ukazuje na nalezenou položku se stejnými daty.
Porovnávací callback funkce má jako vstupní parametr v registru EAX ukazatel na nově vkládanou položku a v registru EBX ukazatel na testovanou položku. Porovnávací funkce navrací nastavené příznaky tak, jako by to udělala porovnávací instrukce - jsou-li položky shodné, navrátí nastavený příznak ZF a vynulovaný příznak CF. Je-li třídicí klíč nové položky menší než porovnávaná položka, navrátí vynulovaný příznak ZF a nastavený příznak CF. Je-li třídicí klíč nové položky větší, navrátí vynulovaný příznak ZF i příznak CF.
Na začátku funkce RBTreeInsert je nově vkládaná položka inicializována - je nastavena na červenou barvu, vypnut příznak kořene stromu, vynulován levý a pravý potomek.
Před vložením nové položky je nejdříve potřeba vyhledat místo, kam bude položka vložena. Do registru ECX se načte ukazatel na výchozí položku stromu z kořene stromu v EDX.
Je-li ukazatel nulový, není ve stromu žádná položka, nová položka bude první položkou stromu (funkce pokračuje na návěští RBTreeInsert3). Nová položka se přidá do seznamu položek připojením položky ke kořeni stromu pomocí funkce ListAdd. Ukazatel na položku se nastaví do kořene jako ukazatel na výchozí položku stromu. Rodič nové položky se vynuluje (rodičem je kořen). Její barva se změní na černou barvu (kořenová položka stromu má vždy černou barvu). Do registru EBX se uloží ukazatel na novou položku, zvýší se čítač položek ve stormu a funkce se úspěšně ukončí s vynulovaným příznakem chyby CF.
Je-li ukazatel na výchozí položku v registru ECX platný, uloží se do registru EBX jako ukazatel na aktuální prohledávanou položku.
Nová položka v registru EAX se porovná s testovaným uzlem v registru EBX voláním porovnávací callback funkce, jejíž adresa je v registru ESI, a vyhodnotí se navrácené příznaky výsledku porovnání. Jsou-li data nové položky shodná s daty testované položky, nastaví se příznak chyby a funkce se předčasně ukončí. V tom případě bude registr EBX obsahovat ukazatel na uzel s nalezenými shodnými daty.
Jsou-li data nové položky větší než data testované položky, bude hledání dále pokračovat pravou větví. Do registru ECX se načte ukazatel na pravého potomka a pokud je platný (tj. není nulový) použije se ukazatel v ECX jako nový ukazatel na aktuální položku a pokračuje se testem další položky. Není-li ukazatel platný (tj. je nulový), bude nová položka novým pravým potomkem. Ukazatel na novou položku se uloží jako ukazatel na pravého potomka a nová položka se přidá funkcí ListAfter do tříděného seznamu položek za aktuální položku v EBX a pokračuje se částí společnou pro oba směry.
Jsou-li data nové položky menší než data testované položky, bude hledání dále pokračovat levou větví (návěští RBTreeInsert4). Do registru ECX se načte ukazatel na levého potomka a pokud je platný (tj. není nulový) použije se ukazatel v ECX jako nový ukazatel na aktuální položku a pokračuje se testem další položky. Není-li ukazatel platný (tj. je nulový), bude nová položka novým levým potomkem. Ukazatel na novou položku se uloží jako ukazatel na levého potomka a nová položka se přidá funkcí ListBefore do tříděného seznamu položek před aktuální položku v EBX a pokračuje se částí společnou pro oba směry.
Dále v případě obou směrů se ukazatel na aktuální položku v EBX uloží jako rodič do nově vkládané položky v EAX. Funkcí RBTreeInsCol (viz dále) se vloží na pozici nové položky červená barva s obsluhou vyvážení stromu, zvýší se čítač položek ve stromu a funkce se úspěšně ukončí s vynulovaným příznakem chyby CF. Registr EBX bude v tomto případě obsahovat ukazatel na novou položku a bude shodný s registrem EAX.
|
Funkce RBTreeInsCol je pomocnou funkcí pro funkci RBTreeInsert. Zajišťuje vyvážení stromu po vložení nové položky do stromu. Vstupními parametry funkce jsou v registru EBX ukazatel na nově vloženou položku stromu (barva nové položky byla nastavena na červenou) a v registru EDX ukazatel na kořen stromu. Funkce RBTreeInsCol a makro RBTreeInsC (viz dále) používají namísto jmen registrů jejich symbolická označení: RBGr (EAX) označuje prarodiče (tj. rodič rodiče), RBNo (EBX) je aktuální položka, RBUn (ECX) je "strýc" neboli bratr rodiče neboli sousední položka patřící ke stejnému prarodiči, RBRo (EDX) je kořen stromu a RBPa (ESI) je rodič.
Uvnitř funkce probíhá cyklus přes uzly stromu. Ukazatelem aktuálního uzlu je registr RBNo, který na začátku funkce obsahuje ukazatel na nově vloženou položku. Aktuální uzel je výchozí uzel větve, jejíž váha se díky vložení nové položky zvýšila. Aktuální uzel má červenou barvu. Pokud měla větev již předtím větší váhu a po vložení nové položky by délka narostla na více než dvojnásobnou hloubku, provede se vyvážení větve - rotace. Pokračuje se dále k nižšímu uzlu, dokud se nenarazí na uzel, který již nepotřebuje vyvážení (posledním uzlem je kořen, který má vždy černou barvou a tím dojde k přerušení iterace).
Do registru rodiče RBPa (ESI) je z aktuálního uzlu RBNo (EBX) načten ukazatel na rodiče. Je-li rodičem kořen stromu (tj. ukazatel na rodiče je nulový), funkce se ukončí s nastavením kořene stromu na černou barvu (pomocí makra SETBLK). Jinak se pomocí makra CMPRED provede test, zda má rodič červenou barvu a pokud ne, není třeba větev vyvažovat a funkce se ukončí opět s nastavením černé barvy kořene.
Je-li rodič červený, je nutné provést vyvážení větve a opravu barev - aktuální uzel je také červený a to by bylo porušení pravidla RB-stromu. Do registru prarodiče RBGr (EAX) se z rodiče načte ukazatel na prarodiče. Vzhledem k tomu, že rodič je červený, není třeba testovat platnost prarodiče, protože může být neplatný jen v případě kořenového uzlu a ten má vždy černou barvu. Porovnáním rodiče s ukazatelem na levého potomka prarodiče se rozliší, zda je rodič levým nebo pravým potomkem prarodiče a podle toho se vyvolá makro pro vyvážení větve stromu RBTreeInsC (viz dále) - s parametry Left/Right nebo obráceně.
|
Makro RBTreeInsC zajistí vyvážení větve stromu pro daný aktuální uzel (uzel má červenou barvu a jeho rodič také, což je příznak nevyváženého stavu). Makro má dva parametry - texty názvů přilehlé a protilehlé strany. Pro vložení barvy pro levý směr jsou parametry Left a Right, pro vložení barvy pro pravý směr jsou parametry Right a Left. První parametr představuje směr, ve kterém leží rodič v uzlu prarodiče, druhý parametr představuje smět opačný. Parametry jsou v makru dosazeny do jmen proměnných (např. RBN_%2 se nahradí textem RBN_Left).
Na vstupu makra jsou platné obsahy položek RBGr (EAX, prarodič), RBPa (ESI, rodič) a RBNo (EBX, aktuální položka).
Na začátku makra je nejdříve získán strýc - tedy protější položka k rodiči, patřící ke stejnému prarodiči. Je-li aktuálním směrem směr vlevo (tj. rodič je levým potomkem prarodiče), načte se strýc z proměnné RBN_Right prarodiče. Je-li aktuálním směrem směr vpravo, načte se strýc z proměnné RBN_Left prarodiče. Je-li strýc neplatná položka, tj. ukazatel je NULL, pokračuje se dále návěštím %%L2 jakoby měl strýc černou barvu. Je-li strýc platný, provede se makrem CMPRED test, zda má strýc červenou barvu. Nemá-li červenou barvu, pokračuje se dále návěštím %%L2 stejně jako v případě neplatného ukazatele na strýce.
Má-li strýc červenou barvu, provede se oprava barev. V této chvíli má aktuální položka červenou barvu a její rodič a strýc také. Znamená to, že větev s aktuálním uzlem je stejně dlouhá nebo delší než sousední větev, ale ještě ne na tolik, aby se větev rotovala. Provede se tedy pouze oprava barev nastavením barvy strýce a rodiče na černou barvu pomocí makra SETBLK a změnou barvy prarodiče na červenou barvu pomocí makra SETRED. Prarodič bude nová aktuální položka a provede se pro ni nový test a vyvážení větve.
Má-li strýc černou barvu, provede se test, zda je nově vložená položka na stejné straně jako je strýc, tj. zda se nachází na "vnitřní" straně rodiče, směrem ke strýci. V tom případě se stal uzel nevyváženým a je potřeba ho vyvážit rotací opačným směrem tak, aby se aktuální uzel stal novým rodičem a jeho původní rodič aby se stal jeho potomkem na vnější straně. Tím se zkrátí větev s aktuální položkou. Pokud se tedy koriguje rodič v levém směru, aktuální položka se nachází v pravém směru od rodiče, provede se rotace vlevo, původní rodič se stane nyní levým potomkem aktuální položky. A obráceně. Rodič se stane novou aktuální položkou a původní aktuální položka se stává novým rodičem.
Po případné rotaci větve následuje vyvážení uzlu prarodiče. Barva rodiče se pomocí makra SETBLK nastaví na černou, barva prarodiče pomocí makra SETRED na červenou a uzel s prarodičem se rotuje v obráceném směru než je směr rodiče, tím se rodič dostane na místo prarodiče a větev se dostane do vyváženého stavu.
|
Funkce RBTreeInsAddr vloží do RB-stromu novou položku, strom bude tříděn podle adresy položek. Takový strom je nutné prohledávat pomocí funkce RBTreeSrcAddr. Vstupními parametry funkce jsou v registru EAX ukazatel na novou položku stromu a v registru EDX ukazatel na kořen stromu.
Je-li položka úspěšně vložena, je navrácen vynulovaný příznak CF a v registru EBX je navrácen ukazatel na novou položku. Jeho obsah tedy odpovídá obsahu registru EAX. Pokud již existuje položka se stejnou adresou (ve stromu se nesmí vyskytovat dvě stejné položky), je navrácen příznak chyby CY (nastavený příznak CF) a registr EBX ukazuje na nalezenou položku se stejnou adresou.
Funkce volá obsluhu funkce RBTreeInsert a předává jí ukazatel na vlastní porovnávací funkci RBTreeInsAddr4, která porovnává adresy položek.
|
Funkce RBTreeInsertW vloží do RB-stromu novou položku s vyplněnými uživatelskými daty v proměnné RB_DataW bez znaménka, strom bude tříděn podle obsahu této položky. Takový strom je nutné prohledávat pomocí funkce RBTreeSrcW. Vstupními parametry funkce jsou v registru EAX ukazatel na novou položku stromu (s vyplněnými daty v RB_DataW) a v registru EDX ukazatel na kořen stromu.
Je-li položka úspěšně vložena, je navrácen vynulovaný příznak CF a v registru EBX je navrácen ukazatel na novou položku. Jeho obsah tedy odpovídá obsahu registru EAX. Pokud již existuje položka se stejnými daty (ve stromu se nesmí vyskytovat dvě stejné položky), je navrácen příznak chyby CY (nastavený příznak CF) a registr EBX ukazuje na nalezenou položku se stejnými daty.
Funkce volá obsluhu funkce RBTreeInsert a předává jí ukazatel na vlastní porovnávací funkci RBTreeInsertW4, která porovnává obsahy položky RB_DataW bez znaménka.
|
Funkce RBTreeInsertWS je obměnou funkce RBTreeInsertW. Vloží do RB-stromu novou položku s vyplněnými uživatelskými daty v proměnné RB_DataW se znaménkem, strom bude tříděn podle obsahu této položky. Takový strom je nutné prohledávat pomocí funkce RBTreeSrcWS. Vstupními parametry funkce jsou v registru EAX ukazatel na novou položku stromu (s vyplněnými daty v RB_DataW) a v registru EDX ukazatel na kořen stromu.
Je-li položka úspěšně vložena, je navrácen vynulovaný příznak CF a v registru EBX je navrácen ukazatel na novou položku. Jeho obsah tedy odpovídá obsahu registru EAX. Pokud již existuje položka se stejnými daty (ve stromu se nesmí vyskytovat dvě stejné položky), je navrácen příznak chyby CY (nastavený příznak CF) a registr EBX ukazuje na nalezenou položku se stejnými daty.
Funkce volá obsluhu funkce RBTreeInsert a předává jí ukazatel na vlastní porovnávací funkci RBTreeInsertWS4, která porovnává obsahy položky RB_DataW se znaménkem.
|
Funkce RBTreeInsertDW vloží do RB-stromu novou položku s vyplněnými uživatelskými daty (dvojslovo bez znaménka) na offsetu RBN_Data, strom bude tříděn podle obsahu těchto dat. Takový strom je nutné prohledávat pomocí funkce RBTreeSrcDW. Vstupními parametry funkce jsou v registru EAX ukazatel na novou položku stromu (s vyplněnými daty v RBN_Data) a v registru EDX ukazatel na kořen stromu.
Je-li položka úspěšně vložena, je navrácen vynulovaný příznak CF a v registru EBX je navrácen ukazatel na novou položku. Jeho obsah tedy odpovídá obsahu registru EAX. Pokud již existuje položka se stejnými daty (ve stromu se nesmí vyskytovat dvě stejné položky), je navrácen příznak chyby CY (nastavený příznak CF) a registr EBX ukazuje na nalezenou položku se stejnými daty.
Funkce volá obsluhu funkce RBTreeInsert a předává jí ukazatel na vlastní porovnávací funkci RBTreeInsertDW4, která porovnává obsahy položky RBN_Data bez znaménka.
|
Funkce RBTreeInsertDWS je obměnou funkce RBTreeInsertDW. Vloží do RB-stromu novou položku s vyplněnými uživatelskými daty (dvojslovo se znaménkem) na offsetu RBN_Data, strom bude tříděn podle obsahu této položky. Takový strom je nutné prohledávat pomocí funkce RBTreeSrcDWS. Vstupními parametry funkce jsou v registru EAX ukazatel na novou položku stromu (s vyplněnými daty v RBN_Data) a v registru EDX ukazatel na kořen stromu.
Je-li položka úspěšně vložena, je navrácen vynulovaný příznak CF a v registru EBX je navrácen ukazatel na novou položku. Jeho obsah tedy odpovídá obsahu registru EAX. Pokud již existuje položka se stejnými daty (ve stromu se nesmí vyskytovat dvě stejné položky), je navrácen příznak chyby CY (nastavený příznak CF) a registr EBX ukazuje na nalezenou položku se stejnými daty.
Funkce volá obsluhu funkce RBTreeInsert a předává jí ukazatel na vlastní porovnávací funkci RBTreeInsertDS4, která porovnává obsahy položky RBN_Data se znaménkem.
Obsah / Utility / RBTREE / Vložení položky do RB-stromu