Proč std :: mapa implementován jako červeno-černý strom ?
Existuje několik vyvážené binární vyhledávací stromy (BSTs) venku. Jaké byly designové kompromisy ve výběru červeno-černý strom?
Proč std :: mapa implementován jako červeno-černý strom ?
Existuje několik vyvážené binární vyhledávací stromy (BSTs) venku. Jaké byly designové kompromisy ve výběru červeno-černý strom?
Asi dvě nejvíce obyčejné algoritmy vlastní vyrovnávací stromů jsou Red-Black stromy a AVL stromy . Vyvážit strom po vložení / aktualizace oba algoritmy používat pojem rotací, kde se otáčí uzly stromu provést opětovné vyrovnání.
Zatímco v obou algoritmů vložku / odstranění operací jsou O (log n), v případě, že Red-Black strom obnovení rovnováhy otáčení je O (1) provozu, zatímco se AVL je to O (log n) provoz, čímž se Red-Black strom efektivnější v tomto aspektu fázi re-vyrovnávání a jedním z možných důvodů, že to je více běžně používané.
Červeno-černé stromy jsou používány ve většině sběrných knihoven, včetně nabídek od Java a Microsoft .NET Framework.
Je to jen volba implementace - by mohly být realizovány jako každý vyvážený strom. Různé možnosti jsou srovnatelné s drobnými rozdíly. Proto jakákoliv je stejně dobrý jako kterýkoli.
AVL stromy mají maximální výšku 1.44logn, zatímco RB stromy mají maximálně 2logn. Vložení prvku do AVL může znamenat rebalance na jednom místě ve stromu. Obnovení rovnováhy ukončí vkládání. Po vložení nového listu, aktualizaci předky tohoto listu, musí být provedeno až ke kořenu, nebo až do bodu, kdy se obě podstromy jsou na stejné hloubky. Pravděpodobnost, že bude muset aktualizovat K uzlů je 1/3 ^ k. Vyvažování je O (1). Odstranění prvek může znamenat více než jeden vyvážení (až do poloviny hloubky stromu).
RB-stromy B-stromy řádu 4 reprezentován jako binární vyhledávací stromy. A 4-uzel ve výsledcích B-stromu ve dvou úrovních v ekvivalentním BST. V nejhorším případě se všechny uzly stromu jsou 2-uzly, pouze s jedním řetězem 3 uzlů dolů na list. Že list bude ve vzdálenosti 2logn od kořene.
Šel z kořene do bodu vložení, je nutné změnit 4-uzly do 2-uzlů, aby se ujistil, jakýkoli vložení nedojde k nasycení list. Návratu z vkládání, všechny tyto uzly mají být analyzovány, aby se ujistil, že správně představují 4-uzly. To lze provést také jít dolů ve stromu. Globální cena bude stejná. Neexistuje žádný oběd zdarma! Odebrání prvku ze stromu je stejného řádu.
Všechny tyto stromy vyžadují, aby uzly nesou informaci o výšce, hmotnosti, barvy apod pouze rozevírá stromy jsou bez takového další potřebné informace. Ale většina lidí se bojí splay strom, protože ramdomness jejich struktury!
A konečně, stromy mohou také nést údaje o hmotnosti do uzlů, což umožňuje vyvážení hmotnosti. Různá schémata mohou být použity. Je třeba vyvážit, pokud podstromu obsahuje více než 3 krát počet prvků druhé podstromu. Vyvažování je opět provádí buď throuh jednoduché nebo dvojité otáčení. To znamená, že nejhorší případ 2.4logn. Jeden může dostat pryč s 2 krát namísto 3, mnohem lepší poměr, ale může to znamenat opuštění trochu méně Thanta 1% podstromy nevyvážená sem a tam. Tricky!
Jaký druh stromu je nejlepší? AVL pro jistotu. Jedná se o nejjednodušší kód, a mají nejhorší výšku nejblíže logn. Pro dřevo 1000000 prvků také AVL bude maximálně výšky 29, a RB 40, a hmotnost je dáno 36 nebo 50 v závislosti na poměru.
Existuje mnoho dalších proměnných: náhodnost, poměr dodává, odstraní vyhledávání, atd.
To opravdu záleží na způsobu používání. AVL strom má obvykle větší rotace vyvážení. Takže pokud vaše aplikace nemá příliš mnoho vložení a vymazání operace, ale závaží do značné míry na vyhledávání, pak AVL strom pravděpodobně je to dobrá volba.
std::map používá červeno-černý strom, jak to bude přiměřené kompromis mezi rychlostí uzlu vložení / smazání a vyhledávání.
Aktualizovat 2017-06-14: webbertiger upravit její odpověď poté, co jsem uvedl. Měl bych zdůraznit, že jeho odpověď je teď mnohem lepší oči. Ale pořád jsem svou odpověď, stejně jako další informace ...
Vzhledem k tomu, že si myslím, že první odpověď je špatně (oprava: ne oba už) a třetí má špatnou potvrzení. Mám pocit, že jsem k objasnění věci ...
Je 2 nejoblíbenější strom jsou AVL a Red Black (RB). Hlavní rozdíl lež ve využití:
Hlavní rozdíl pochází z zbarvení. Ty mají menší akci re-rovnováhu v RB stromu než AVL, protože zbarvení umožní někdy přeskočit nebo zkrátit re-vyvážení akce, které mají relativní hi náklady. Vzhledem k barvení, RB strom mají také vyšší úroveň uzlů, protože by to mohlo přijmout červené uzly mezi ty černé (o možnostech ~ 2x více úrovních), což je trochu méně efektivní vyhledávání (čtení) ... ale proto, že se jedná o konstanta (2x), pak pobyt v O (log n).
Máte-li v úvahu hit výkon pro modifikaci dřeva (náznakový) versus výkon hit konzultaci stromu (téměř bezvýznamnou), to stane přirozeným preferovat RB nad AVL pro obecný případ.
Předchozí odpovědi týkat pouze strom alternativy a červená černá pravděpodobně zůstane pouze z historických důvodů.
Proč ne hash tabulky?
Na stromě typ vyžaduje pouze částečné uspořádání (<srovnání), který bude použit jako klíč v mapě. Nicméně, hashovací tabulky vyžadují, aby každý typ klíče má hash funkce definována. Udržet tyto požadavky typu na minimum je pro druhové programování velmi důležité.
Projektování dobrý hash tabulky vyžaduje dokonalou znalost kontextu, který se bude používat. Měla by používat otevřenou adresování nebo propojený zřetězení? Jaké úrovně zátěže by mělo přijmout ještě před velikosti? By mělo používat drahé hash, který se vyhýbá kolizím, nebo ten, který je tvrdý a rychlý?
(C ++ 11 dělal přidat hash tabulky s unordered_map. Můžete vidět z dokumentace to vyžaduje nastavení zásad konfigurovat mnoho z těchto možností.)
Vzhledem k tomu, STL nemůže předvídat, který je tou nejlepší volbou pro vaši aplikaci, výchozí musí být pružnější. Stromy „prostě fungovat“ a měřítko dobře.
A co ostatní stromy?
Červeno-černý strom Nabídka rychlé vyhledávání a vlastní vyvážení rozdíl BSTs. Jiný uživatel poukázal na to své výhody nad samovyvažující AVL stromu.
Alexander Stepanov (Tvůrce STL), řekl, že bude používat B * Strom místo červeno-černý strom, jestli napsal std::mapznovu. Je to proto, že uzly mohou uložit libovolný počet prvků, souvisle, což je šetrnější pro moderní paměti cache.
Jednou z největších změn od té doby byl růst cache. Cache mine jsou velmi nákladné, takže lokalita odkazu je mnohem důležitější teď. Uzel na bázi datových struktur, které mají nízkou lokalitě reference, dávají mnohem méně smyslu. Kdybych dnes navrhování STL, tak bych mít jinou sadu kontejnerů. Například v paměti B * -tree je mnohem lepší volbou než v červeno-černém dřeva pro provádění asociativní kontejner. - Alexander Stepanov
Si můžete přečíst více zde
Červená černá strom nebo B * vždy tím nejlepším?
Na jiných příležitostech Alex uvedl, že std::vectorje téměř vždy nejlepší seznam kontejner z podobných důvodů. To zřídka dává smysl používat std::list, nebo std::dequedokonce pro tyto situace jsme se učili ve škole (například odstraněním prvek ze středu seznamu). std::vectorje tak rychlý, že se bije ty struktury na všechno, ale velký n.
Použitím tohoto stejnými úvahami, pokud máte jen malý počet prvků (stovky?) S použitím std::vectorlineární vyhledávání a mohou být účinnější než implementace stromem std::map. V závislosti na frekvenci vkládání, seřazený std::vectorv kombinaci s std::binary_searchmůže být nejrychlejší volbou.