C # Binární stromy a slovníky

hlasů
15

Jsem potýká s konceptem, kdy použít binární vyhledávací stromy a kdy používat slovníky.

V mé žádosti jsem udělal malý experiment, který použil knihovnu C5 TreeDictionary(které podle mého názoru je červeno-černý strom binárního vyhledávání) a C # slovníku. Slovník byl vždy rychlejší při add / najít operace a také vždy používá méně místa v paměti. Například na 16809 <int, float>záznamů, slovník použitý 342 KiB, zatímco strom použitý 723 KiB.

Myslel jsem, že BST je měli být více paměti efektivnější, ale zdá se, že jeden uzel stromu vyžaduje více bytů než jednu položku v slovníku. Co dává? Existuje bod, ve kterém je BST jsou lepší než slovníky?

Také, jako vedlejší otázka, má někdo vědět, jestli tam je rychlejší + více paměti efektivnější datová struktura pro ukládání <int, float>dvojic pro slovníku přístup typu, než některý z uvedených struktur?

Položena 28/01/2010 v 02:46
zdroj uživatelem
V jiných jazycích...                            


6 odpovědí

hlasů
1

Zdá se mi, že děláš předčasné optimalizace.

Co bych navrhnout, aby vám je vytvořit rozhraní pro izolaci, která struktura jste vlastně používáte, a pak implementovat rozhraní pomocí slovníku (který vypadá, že fungují nejlépe).

Pokud mi paměť / výkon se stává problém (což asi nebude pro 20k- čísel), pak si můžete vytvořit další implementace rozhraní a zkontrolovat, který z nich pracuje nej. Nebudete muset změnit ve zbytku kódu (s výjimkou, kdy zavedení, který používáte) téměř cokoliv.

Odpovězeno 28/01/2010 v 03:26
zdroj uživatelem

hlasů
1

Nemá smysl, aby strom uzel by vyžadovalo více úložného prostoru než slovníkového hesla. Binární strom node potřebuje pro uložení hodnoty a obě levé a pravé podstromy. Generická Dictionary<TKey, TValue>je implementována jako hashovací tabulky, které - Jsem za předpokladu, - buď používá propojeného seznamu pro každý segment (hodnota plus jedna ukazatel / odkaz) nebo jakési přemapování (jen hodnoty). Budu mít nahlédnout do reflektoru být jistý, ale pro účely této otázce si nemyslím, že je to tak důležité.

Rozptýlenější hash tabulky, tím méně efektivní, pokud jde o skladovací / paměti. Pokud vytvoříte hash tabulky (slovník) a inicializovat jeho kapacitu na 1 milion, a naplňte ji jen s 10.000 elementy, pak jsem si jistý, že by se sníst mnohem více paměti než BST s 10.000 uzlů.

Přesto bych se starat o nic z toho, pokud je množství uzlů / klíčů je pouze v tisících. Že se bude měřit v kilobajtů, v porovnání s gigabajtů fyzické paměti RAM.


V případě, že otázka zní: „Proč by se chcete použít binární strom namísto hash tabulky?“ Pak je nejlepší odpovědí IMO je, že binární stromy jsou uspořádány vzhledem k tomu, hashovací tabulky nejsou. Můžete vyhledávat pouze hash tabulku pro klíče, které jsou přesně rovny něčemu; se stromem, můžete vyhledávat rozsah hodnot, nejbližší hodnota, atd To je docela důležitý rozdíl, pokud jste vytvořením indexu nebo něco podobného.

Odpovězeno 28/01/2010 v 03:39
zdroj uživatelem

hlasů
0

Rozhraní pro strom a Hash tabulky (které Hádám, je to, co váš slovník je založen jeden) by měla být velmi podobná. Vždy se točí kolem zadaných vyhledávání.

Vždycky jsem si myslel, že slovník je lepší pro vytvoření věci jednou a pak se pak dělá hodně vyhledáváními na něm. Zatímco Tree bylo lepší, kdyby jste jej úpravou výrazně. Nicméně, já nevím, kde jsem si vybral ten nápad se z.

(Funkční jazyky často používají stromy jako základ pro oni sbírek, můžete znovu použít většinu ze stromu, když se provést drobné úpravy na něj).

Odpovězeno 28/01/2010 v 03:40
zdroj uživatelem

hlasů
0

Nejste srovnávání „jablka s jablky“, je BST vám dá objednané reprezentaci, zatímco slovník vám umožní udělat vyhledávání na pár klíčových hodnot (ve vašem případě).

Nečekal bych moc velikost v paměti stopy mezi 2, ale slovník vám poskytne mnohem rychlejší vyhledávání. Chcete-li najít položku v BST vy (potenciálně) musí projít celý strom. Ale dělat dictnary vyhledávání stačí vyhledávání založené na klíči.

Odpovězeno 28/01/2010 v 04:05
zdroj uživatelem

hlasů
8

Myslel jsem, že BST je měli být více paměti efektivnější, ale zdá se, že jeden uzel stromu vyžaduje více bytů než jednu položku v slovníku. Co dává? Existuje bod, ve kterém je BST jsou lepší než slovníky?

Osobně jsem nikdy neslyšel o takové zásady. Dokonce i přesto, jeho jediná obecná zásada, není kategorické fakt vyrytý ve struktuře vesmíru.

Obecně platí, že slovníky jsou opravdu jen ozdobný obal kolem pole spojových seznamů. Vložit do slovníku něco jako:

LinkedList<Tuple<TKey, TValue>> list =
    internalArray[internalArray % key.GetHashCode()];
if (list.Exists(x => x.Key == key))
    throw new Exception("Key already exists");
list.AddLast(Tuple.Create(key, value));

Takže jeho téměř O (1) provozu. Slovník používá O (internalArray.Length + n) paměti, kde n je počet předmětů ve sbírce.

Obecně BSTs může být implementován jako:

  • propojené seznamy, které využívají O (n) prostor, ve kterém n je číslo položky ve sbírce.
  • pole , které používají O (2 h - n) prostoru, kde h je výška stromu a n je počet předmětů ve sbírce.
    • Vzhledem k tomu, červeno-černé stromy mají ohraničený výšku O (1,44 * n), implementace pole by měla mít ohraničený využití paměti o O (2 1.44n - n)

Kurzy jsou, C5 TreeDictionary je realizován pomocí polí, což je pravděpodobně zodpovědný za nevyužité místo.

Co dává? Existuje bod, ve kterém je BST jsou lepší než slovníky?

Slovníky mají některé nežádoucí vlastnosti:

  • Tam nemusí být dost continugous bloky paměti držet slovníku, i když její paměťové nároky jsou mnohem méně než než celkové dostupné paměti RAM.

  • Vyhodnocování hashovací funkci může trvat libovolně dlouhou dobu. Řetězce, například použít reflektor zkoumat System.String.GetHashCodemetody - všimněte si, hash řetězec vždy trvá O (n), což znamená, že může trvat značné množství času pro velmi dlouhé řetězce. Na straně porovnávání řetězců pro nerovnosti téměř vždy rychlejší než zatřiďování, neboť mohou vyžadovat při pohledu na jen několik prvních znaků. Jeho zcela možné, aby strom vložky být rychlejší než slovníkové vložek v případě vyhodnocení hash kód trvá příliš dlouho.

    • Int32 je GetHashCodemetoda je doslova return this, takže byste se hardpressed najít případ, kdy HashTable s int kláves je pomalejší než stromu slovníku.

RB stromy mají některé žádoucí vlastnosti:

  • Najdete / odstranit prvky min a max O (log n), ve srovnání s O (n) čas s použitím slovníku.

  • Je-li strom je implementován jako spojový seznam, spíše než pole, strom je obvykle více prostoru účinnější než slovníku.

  • Stejně tak jeho směšné snadné psát neměnné verze stromů, které podporují insert / vyhledávání / mazat v O (log n). Slovníky nejsou dobře adaptovat na neměnnosti, protože je třeba zkopírovat celý vnitřní pole pro každou operaci (ve skutečnosti jsem ještě viděl některé implementace založená na poli z neměnných prstů stromy, jakési všeobecné účely slovníku datové struktury, ale realizace je velmi komplex).

  • Můžete procházet všechny prvky ve stromu v seřazeném pořadí v konstantním prostoru a O (n) čas, zatímco si musíte hodit hash tabulky do pole a třídit to získat stejný efekt.

Takže volba datové struktury opravdu záleží na tom, jaké vlastnosti budete potřebovat. Pokud chcete jen neuspořádané tašku a může zaručit, že vaše hash funkce zhodnotit rychle, jít s .Net slovníku. Potřebujete-li objednaný tašku nebo máte pomalý běh hash funkce, jít s TreeDictionary.

Odpovězeno 28/01/2010 v 04:16
zdroj uživatelem

hlasů
0

Vyvážená BST je výhodné, když je potřeba chránit datovou strukturu z latence hrotů a hash kolize útoky.

První z nich se stane, když strukturu pole opěradlem roste dostane změně velikosti, druhý je nevyhnutelný vlastnost přerušovacího algoritmu jako výstupek z nekonečného prostoru do omezeného rozsahu celé číslo.

Dalším problémem v .NET je, že neexistuje LOH, a s dostatečně velkým slovníkem narazíte na fragmentaci LOH. V tomto případě můžete použít BST, platí cenu větších algoritmického třídy složitosti.

Stručně řečeno, s BST couval přidělení haldy dostanete nejhorším případě O (log (N)) času, s Hashtable dostanete O (n) nejhorší čas.

BST přichází v ceně O (log (N)) průměrná doba, horší vyrovnávací lokality a další přidělení haldy, ale má latenci záruky a je chráněna před slovníkových útoků a fragmentace paměti.

Stojí za zmínku, že BST je rovněž předmětem fragmentace paměti na jiných platformách, a to pomocí stlačování garbage collector.

Pokud jde o velikost paměti, třída .NET Dictionary`2 je více paměti efektivnější, protože to ukládá data jako off-haldy propojeného seznamu, který jen ukládá hodnoty a informace o offsetu. BST má pro uložení záhlaví objekt (jako každý uzel je instance třídy na haldě), dva ukazatele a některé údaje rozšířený strom pro vyvážené stromy. Například, červeno-černý strom bude potřebovat boolean vykládat tak, že barva (červená nebo černá). To je minimálně 6 stroje slova, pokud se nepletu. Takže, každý uzel v červeno-černém strom na 64-bitovém systému je minimálně:

3 slova pro hlavičkových = 24 bytů 2 slova pro podřízené ukazatele = 16 bytů 1 slovo pro barvu = 8 bajtů alespoň 1 slovo pro hodnotu 8+ bajtů = 24 + 16 + 8 + 8 = 56 bajtů (+8 bytů v případě, že strom používá ukazatel nadřazeného uzlu).

Ve stejné době, minimální velikost vstupu slovníku by bylo jen 16 bajtů.

Odpovězeno 10/12/2018 v 13:18
zdroj uživatelem

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