二叉搜尋樹及AVL平衡二叉搜尋樹
阿新 • • 發佈:2019-01-10
二叉搜尋樹
二叉搜尋樹是二叉樹的的一種,只不過多了個限制條件,即左子樹節點的值都小於該點,右子樹節點的值都大於該點。
定義:
// 樹節點
template <typename T>
class Node
{
public:
T key;
Node* parent;
Node* left;
Node* right;
Node(T k, Node* p = nullptr, Node* l = nullptr, Node* r = nullptr) :
key(k), parent(p), left(l), right(r) {}
};
// 二叉搜尋樹
template <typename T>
class BSTree
{
private:
Node<T>* root_;
public:
BSTree();
~BSTree();
Node<T>* Search(T key);
Node<T>* Insert(T key);
void Remove(T key);
private:
void Destroy(Node<T>* &head);
};
這裡只實現了最關鍵的三個操作:查詢、插入和刪除。
查詢自然不必多說,類似於二分查詢,從根節點開始判斷往左往右還是命中。
插入也簡單,類似查詢,找到要插入的位置即可,注意新插入的節點必為葉子節點。
刪除節點就麻煩一些了,需要分情況進行處理。
(1)刪除的節點為葉子節點,直接刪除即可。
(2)刪除的節點只有一個孩子,把這個孩子提上來代替自己即可。
(3)刪除的節點左右孩子皆有,這種情況需要先找到右子樹最左節點,然後把這個節點跟要刪除的節點交換,這樣就變成了刪除右子樹最左節點了,而該最左節點必定無左孩子,這樣刪除就變成上面兩種情況之一了。
這裡還要注意的一點是當刪除的節點為根節點時,要維護好根節點的更新。
實現:
template <typename T>
BSTree<T>::BSTree() : root_(nullptr) {}
template < typename T>
BSTree<T>::~BSTree()
{
Destroy(root_);
}
template <typename T>
Node<T>* BSTree<T>::Search(T key)
{
Node<T>* cur = root_;
while (cur && cur->key != key)
{
if (key < cur->key)
cur = cur->left;
else
cur = cur->right;
}
return cur;
}
template <typename T>
Node<T>* BSTree<T>::Insert(T key)
{
Node<T>* cur = root_;
Node<T>* pre = nullptr;
// 找到插入位置
while (cur)
{
pre = cur;
if (key == cur->key)
return cur;
else if (key < cur->key)
cur = cur->left;
else
cur = cur->right;
}
Node<T>* new_node = new Node<T>(key);
new_node->parent = pre;
// 插入為根節點
if (pre == nullptr)
root_ = new_node;
// 插入為左孩子
else if (key < pre->key)
pre->left = new_node;
// 插入為右孩子
else
pre->right = new_node;
}
template <typename T>
void BSTree<T>::Remove(T key)
{
Node<T>* remove;
// 不存在該節點
if ((remove = Search(key)) == nullptr)
return;
// 為葉子節點,直接刪除
if (remove->left == nullptr && remove->left == nullptr)
{
if (remove->parent == nullptr) // 刪除節點為根節點的情況
root_ = nullptr;
else if (remove->parent->left == remove)
remove->parent->left = nullptr;
else
remove->parent->right = nullptr;
delete remove;
return;
}
// 左孩子為空,直接把右孩子提上來後刪除自己
if (remove->left == nullptr)
{
if (remove->parent == nullptr)
{
remove->right->parent = nullptr;
root_ = remove->right;
}
else if (remove->parent->left == remove)
{
remove->right->parent = remove->parent;
remove->parent->left = remove->right;
}
else
{
remove->right->parent = remove->parent;
remove->parent->right = remove->right;
}
delete remove;
return;
}
// 右孩子為空,直接把左孩子提上來後刪除自己
if (remove->right == nullptr)
{
if (remove->parent == nullptr)
{
remove->left->parent = nullptr;
root_ = remove->left;
}
else if (remove->parent->left == remove)
{
remove->left->parent = remove->parent;
remove->parent->left = remove->left;
}
else
{
remove->left->parent = remove->parent;
remove->parent->right = remove->left;
}
delete remove;
return;
}
// 左右孩子均不為空的情況,把該節點跟右子樹最小節點交換後,轉換為刪除右子樹最小節點
Node<T>* right_min = remove->right;
while (right_min->left) // 找到右子樹最小節點
{
right_min = right_min->left;
}
remove->key = right_min->key; // 與要刪除的節點交換
if (right_min->right) // 有右孩子,轉換為第三種情況
{
right_min->right->parent = right_min->parent;
right_min->parent->left = right_min->right;
}
else // 無右孩子,轉換為第二種情況
{
if (right_min->parent->left == right_min)
right_min->parent->left = nullptr;
else
right_min->parent->right = nullptr;
}
delete right_min;
return;
}
template <typename T>
void BSTree<T>::Destroy(Node<T>* &head)
{
if (head == nullptr)
return;
if (head->left)
Destroy(head->left);
if (head->right)
Destroy(head->right);
delete head;
head = nullptr;
}
AVL 自平衡二叉搜尋樹
AVL樹在二叉搜尋樹的基礎上加了平衡的限制條件,即對於每個節點,左右子樹的高度差不能超過1,這樣對於某些情況,該搜尋樹的效能就不至於下降。
AVL樹的定義於普通的二叉搜尋樹大同小異,不過受限於平衡條件,插入和刪除節點的操作就變得複雜起來,在每次插入或刪除節點後,都要判斷是否失衡並恢復平衡。
定義:
template <typename T>
class Node
{
public:
T key;
int height;
Node* left;
Node* right;
Node(T k, Node* l = nullptr, Node* r = nullptr) :
key(k), height(0), left(l), right(r) {}
};
template <typename T>
class AVLTree
{
private:
Node<T>* root_;
public:
AVLTree();
~AVLTree();
int Height(Node<T>* head);
Node<T>* Search(T key);
void Insert(T key);
void Remove(T key);
private:
Node<T>* LLRotation(Node<T>* head);
Node<T>* RRRotation(Node<T>* head);
Node<T>* LRRotation(Node<T>* head);
Node<T>* RLRotation(Node<T>* head);
Node<T>* Insert(Node<T>* &head, T key);
Node<T>* Remove(Node<T>* &head, Node<T>* r);
void Destroy(Node<T>* &head);
};
四種失衡狀態及其恢復
(1)LL
(2)RR
(3)LR
(4)RL
有了四種失衡情況調整後就可以實現插入、刪除了,這裡插入刪除都是用遞迴來寫,比如插入,判斷要往左子樹還是右子樹插入,遞迴下去,返回時就要判斷左右子樹是否出現了失衡,如果出現就判斷是哪種情況並進行處理。
實現:
template <typename T>
AVLTree<T>::AVLTree() : root_(nullptr) {}
template <typename T>
AVLTree<T>::~AVLTree()
{
Destroy(root_);
}
template <typename T>
int AVLTree<T>::Height(Node<T>* head)
{
if (head)
return head->height;
return -1;
}
template <typename T>
Node<T>* AVLTree<T>::Search(T key)
{
Node<T>* cur = root_;
while (cur && cur->key != key)
{
if (key < cur->key)
cur = cur->left;
else
cur = cur->right;
}
return cur;
}
template <typename T>
Node<T>* AVLTree<T>::LLRotation(Node<T>* head)
{
Node<T>* tmp = head->left;
head->left = tmp->right;
tmp->right = head;
head->height = max(Height(head->left), Height(head->right)) + 1;
tmp->height = max(Height(tmp->left), Height(tmp->right)) + 1;
return tmp;
}
template <typename T>
Node<T>* AVLTree<T>::RRRotation(Node<T>* head)
{
Node<T>* tmp = head->right;
head->right = tmp->left;
tmp->left = head;
head->height = max(Height(head->left), Height(head->right)) + 1;
tmp->height = max(Height(tmp->left), Height(tmp->right)) + 1;
return tmp;
}
template <typename T>
Node<T>* AVLTree<T>::LRRotation(Node<T>* head)
{
head->left = RRRotation(head->left);
return LLRotation(head);
}
template <typename T>
Node<T>* AVLTree<T>::RLRotation(Node<T>* head)
{
head->right = LLRotation(head->right);
return RRRotation(head);
}
template <typename T>
Node<T>* AVLTree<T>::Insert(Node<T>* &head, T key)
{
// 插入為根節點
if (head == nullptr)
{
head = new Node<T>(key);
}
// 往左子樹插入
else if (key < head->key)
{
head->left = Insert(head->left, key);
// 判斷是否失衡
if (Height(head->left) - Height(head->right) == 2)
{
if (key < head->left->key)
head = LLRotation(head);
else
head = LRRotation(head);
}
}
// 往右子樹插入
else if (key > head->key)
{
head->right = Insert(head->right, key);
if (Height(head->right) - Height(head->left) == 2)
{
if (key > head->right->key)
head = RRRotation(head);
else
head = RLRotation(head);
}
}
// 更新高度
head->height = max(Height(head->left), Height(head->right)) + 1;
// 返回插入後的根節點
return head;
}
template <typename T>
void AVLTree<T>::Insert(T key)
{
Insert(root_, key);
}
template <typename T>
Node<T>* AVLTree<T>::Remove(Node<T>* &head, Node<T>* r)
{
// 找不到要刪除的節點
if (head == nullptr || r == nullptr)
return nullptr;
// 待刪除的節點在左子樹中
if (r->key < head->key)
{
head->left = Remove(head->left, r);
// 判斷是否失衡
if (Height(head->right) - Height(head->left) == 2)
{
if (Height(head->right->left) > Height(head