二叉樹(binary tree)和雜湊表(hash table)都是很基本的資料結構,但是我們要怎麼從兩者之間進行選擇呢?他們的不同是什麼?優缺點分別是什麼?
回答這個問題不是一兩句話可以說清楚的,原因是在不同的情況下,選擇的依據肯定也不同。首先來回顧一下這兩個資料結構:
雜湊表使用hash function來對輸入的資料分配index到雜湊表對應的槽中。假設有乙個雜湊表的size是100,而我們輸入的資料是從0~99,我們要把輸入資料儲存到雜湊表中。理論上來說,該雜湊表插入和查詢操作的時間複雜度都是o(1)。
二叉樹遵循右子樹大於根節點,左子樹小於根節點的原則進行資料的插入和儲存。如果這個樹的平衡的,那麼,對於每個元素的插入和查詢操作的時間複雜度是o(log(n)),n是樹的節點個數,log(n)通常是樹的深度。當然,對於不平衡的情況,那就需要更複雜的資料結構的樹(紅黑樹等)進行處理。
上文似乎得出結論雜湊表要好於二叉樹,但是it is not always the case。雜湊表有以下幾個突出的缺點:
當更多的數插入時,雜湊表衝突的可能性就更大。對於衝突,雜湊表通常有兩種解決方案:第一種是線性探索,相當於在衝突的槽後建立乙個單鏈表,這種情況下,插入和查詢以及刪除操作消耗的時間會達到o(n),且該雜湊表需要更多的空間進行儲存。第二種方法是開放定址,他不需要更多的空間,但是在最壞的情況下(例如所有輸入資料都被map到了乙個index上)的時間複雜度也會達到o(n)。
所以,在決定建立雜湊表之前,最好可以估計輸入的資料的size。否則,resize雜湊表的過程將會是乙個非常消耗時間的過程。例如,如果現在你的雜湊表的長度是100,但是現在有第101個數要插入。這時,不僅雜湊表的長度可能要擴充套件到150,且擴充套件之後所有的數都需要重新rehash。
雜湊表中的元素是沒有被排序的。然而,有些情況下,我們希望儲存的資料是有序的。
另一方面,我們討論二叉樹:
二叉樹不會有衝突(collision),這意味著我們能夠保證二叉樹的插入和查詢操作一直都是o(log(n))的時間複雜度。
二叉樹的空間占用跟輸入的輸入資料一致。所以我們不需要為二叉樹預先分配固定的空間。所以,你也不需要預先知道輸入資料的size。
所有的元素在樹中是排序好的。
如果你預先知道輸入資料的大小,而且有足夠的空間儲存雜湊表,且不需要對資料進行排序,那麼雜湊表總是好的。因為雜湊表在插入,查詢和刪除操作中只需要常數時間。
另一方面,如果資料是持續的加入,你預先不知道資料的大小,那麼二叉樹是乙個折中的選擇。
reference:
hash table vs binary search tree
查詢技術 平衡二叉樹 雜湊表
1 平衡二叉樹 或者是一棵空的二叉排序樹,或者是具有下列性質的二叉排序樹 根結點的左子樹和右子樹的深度最多相差1 根結點的左子樹和右子樹也都是平衡二叉樹。平衡因子 結點的平衡因子是該結點的左子樹的深度與右子樹的深度之差。在平衡樹中,結點的平衡因子可以是1,0,1。最小不平衡子樹 在平衡二叉樹的構造過...
鍊錶和二叉樹
1.鍊錶 鍊錶是一種物理儲存單元上非連續 非順序的儲存結構,資料元素的邏輯順序是通過鍊錶中的指標鏈結次序實現的。相比於線性表順序結構,鍊錶比較方便插入和刪除操作。a.單向鍊錶 單向鍊錶的每乙個結點由儲存資料元素的資料域和指向下乙個結點的指標域組成。b.雙向鍊錶 雙向鍊錶是單鏈表的改進。雙向鍊錶中,結...
鍊錶和二叉樹
鍊錶是離散儲存性結構 常用鍊錶有3類 單鏈表 雙向鍊錶 迴圈鍊錶 陣列是一種連續儲存線性結構,元素型別相同,大小相等。鍊錶和陣列各自的優缺點 鍊錶優點 空間沒有限制 插入刪除元素很快 缺點 訪問速度慢 陣列優點 訪問速度快 缺點 必須事先知道陣列的長度 插入刪除元素很慢 空間有限制 單鏈表由各個記憶...