二叉平衡樹(BST)
BST 是一種資料結構,用於快速查詢資料。
二叉平衡樹有一個非常明顯的特性:對於每一個節點 \(u\),在其左邊的數都比它小,在其右邊待數都比它大。
每個點都有一個權值 cnt
,用於儲存這個數出現了幾次。
在二叉平衡樹上的每一個操作的時間與其樹高成正比,約為 \(O(\log n)\)。
BST的基本操作
插入
根據二叉平衡樹的性質,新加入的數分為以下幾種情況:
- 比當前節點小,則將他下放到左兒子。
- 等於這個節點,則將這個節點的 \(cnt+1\)。
- 否則則下放到右兒子。
最後如果沒有節點就新建一個節點,並且根據大小關係歸在父親節點的左或右兒子,將節點的 \(cnt\) 設為 \(1\)。
刪除
和插入是相反操作,規則同插入操作,但當等於當前結點值的時候,要分兩種情況:
- 當前結點的 \(cnt\) 值\(>1\),即當前節點存在不止一個數,直接將 \(cnt-1\) 即可。
- 當前結點 \(cnt\) 為 \(1\),即只有一個這樣的節點,這時候如果這個點是葉子節點(下面沒有兒子,直接將這個點的 \(cnt\) 設成 \(0\),編號直接刪除。如果這個節點下面還有兒子,就把下面兩個元素中的任意一個元素所有變數賦值到這個位置,並且遞迴刪除下面的點,操作同上。
查詢排名為 \(x\) 的元素
根節點的排名取決於左子樹的大小。
- 當左子樹大小大於等於 \(x\),則這個元素位於左子樹
- 當左子樹大小位於 \([x-cnt, x-1]\) 之間,則這個元素位於根節點
- 否則,這個元素位於右子樹
查詢元素 \(x\) 的排名
相當於搜尋 \(x\),在遍歷右子樹時需要加上左子樹以及根節點的大小。
BST 的時間複雜度約為 \(O(\log n)\),但是由於其特殊的性質,最壞情況下可以退化成一條鏈,這時候,複雜度將會退化成 \(O(n)\),有超時風險。這時候就需要最佳化,最佳化方法有 Treap 和 Splay 等。