本文內容爲前天寫的AVL樹模板的C++代碼實現。本想把二叉搜索樹設計成基類(SearchTree),然後由AVL樹和紅黑樹分別對其繼承,因爲作爲搜索樹,它們在查找、插入和刪除元素時都用到了相同的節點查找方法,因此這種繼承機制可以很好地利用繼承機制的優點。但是在類的具體實現時,卻遇到了一些問題。
首先,我定義了二叉搜索樹的樹節點類:BTNode。它只是普通的二叉樹節點:數據成員包括value和兩個指針lchild、rchild分別指向左右孩子。但是這裏的指針只能定義爲指向基類(BTNode)的指針。然後定義了SearchTree類。該類沒有自己的數據成員,僅爲子類提供接口。共有兩個虛函數:
virtual BTNode<T>* root_insert(const T& elem, BTNode<T> *root) ;
virtual BTNode<T>* root_find(const T& elem, BTNode<T> *root);
分別用於定位元素的父節點和定位元素。函數的參數以及返回值包含指向樹節點的指針,在該類的實現中,指針也只能是指向基類(BTNode)節點的指針。
然後定義AVL樹的節點類AVLTNode,繼承BTNode,擴充了兩個數據成員:指向父節點的指針parent(爲派生類指針)和表示平衡因子的整數BF。
接下來定義了AVL樹,數據成員爲指向AVLTNode的指針root表示樹根。問題就出現在AVLTree的實現中。在實現插入和刪除時用到了基類的成員函數實現節點查找,找到的是指向基類節點的指針;節點的左右子節點指針均爲指向基類的指針。在這裏就需要用到大量的數據類型轉換以實現指向基類的指針爲指向派生類的指針的賦值。還好在這裏我們可以保證AVL中的樹節點均爲派生類節點而不至於引起派生類指針指向基類對象所引發的不可預知的結果。下面的代碼中可以發現大量的static_cast關鍵字,原因就在這裏。。。爲了減少static_cast的使用,可以再派生類中實現一個內聯函數來實現。
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
以下就是具體的代碼實現:
// BTNode類的定義
template<typename T>
class BTNode
{
public:
BTNode():lchild(0), rchild(0){}
BTNode(T elem):data(elem), lchild(0), rchild(0){}
virtual ~BTNode()
{
}
protected:
BTNode<T> *lchild;
BTNode<T> *rchild;
T data;
private:
template<typename T1>
friend class SearchTree;
template <typename T1>
friend class AVLTree;
};
// AVLTNode類的定義
template <typename T>
class AVLTNode : public BTNode<T>
{
public:
AVLTNode():parent(0), BF(0){}
AVLTNode(T elem) : BTNode<T>(elem), parent(0), BF(0){}
AVLTNode<T>* right_rotate();
AVLTNode<T>* left_rotate();
private:
AVLTNode<T> *parent;
int BF;
private:
template <typename T1>
friend class AVLTree;
};
template <typename T>
AVLTNode<T>* AVLTNode<T>::right_rotate() // 右旋,僅實現了子樹內部父子關係的改變以及BF值的更新,子樹與外部節點之間的父子關係還未更新
{
AVLTNode<T> *p(static_cast<AVLTNode<T>*>(this->lchild));
if(!p)
{
return this;
}
this->lchild = p->rchild;
if(p->rchild)
{
static_cast<AVLTNode<T>*>(p->rchild)->parent = this;
}
p->rchild = this;
BF -= (p->BF > 0 ? 1 + p->BF : 1);
p->BF -= (BF < 0 ? 1 - BF : 1);
return p;
}
template <typename T>
AVLTNode<T>* AVLTNode<T>::left_rotate()
{
AVLTNode<T> *p(static_cast<AVLTNode<T>*>(this->rchild));
if(!p)
{
return this;
}
this->rchild = p->lchild;
if(p->lchild)
{
static_cast<AVLTNode<T>*>(p->lchild)->parent = this;
}
p->lchild = this;
BF += (p->BF < 0 ? 1 - p->BF : 1);
p->BF += (BF > 0 ? 1 + BF : 1);
return p;
}
template <typename T>
class SearchTree
{
public:
SearchTree() {}
virtual ~SearchTree() {}
protected:
virtual BTNode<T>* root_insert(const T& elem, BTNode<T> *root);
virtual BTNode<T>* root_find(const T& elem, BTNode<T> *root);
private:
};
template <typename T>
BTNode<T>* SearchTree<T>::root_insert(const T& elem, BTNode<T> *root)
{
BTNode<T> *p(root);
while(p)
{
root = p;
p = (root->data < elem ? root->rchild : root->lchild);
}
return root;
}
template<typename T>
BTNode<T>* SearchTree<T>::root_find(const T& elem, BTNode<T> *root)
{
while(root)
{
if(root->data == elem)
{
break;
}
else if(root->data < elem)
{
root = root->rchild;
}
else
{
root = root->lchild;
}
}
return root;
}
// 以下爲AVLTree模板的代碼實現:
template <typename T>
class AVLTree : public SearchTree<T>
{
public:
AVLTree() : root(0) {}
virtual ~AVLTree() {}
virtual void insert(const T& elem);
virtual void erase(const T& elem);
virtual bool find(const T& elem);
protected:
private:
AVLTNode<T> *root;
};
// 插入操作,也許會改變父節點的BF值,自新插入節點向上追溯並更新相應節點的BF值直到根節點,若某個節點BF變爲2或-2,則需要旋轉以達到平衡,且向上的追溯止於此。
template <typename T>
void AVLTree<T>::insert(const T& elem)
{
AVLTNode<T> *p = static_cast<AVLTNode<T>*>(SearchTree<T>::root_insert(elem, root));
AVLTNode<T> *node = new AVLTNode<T>(elem);
node->parent = p;
if(!p)
{
root = node;
return;
}
if(p->data >= elem)
{
p->lchild = node;
}
else
{
p->rchild = node;
}
while(p)
{
if(node == p->lchild)
{
++p->BF;
if(p->BF == 0)
{
break;
}
if(p->BF == 2)
{
if(node->BF == -1)
{
AVLTNode<T> *q = node->left_rotate();
q->parent = p;
node->parent = q;
p->lchild = q;
node = q;
}
node = p->right_rotate();
node->parent = p->parent;
p->parent = node;
if(!node->parent)
{
root = node;
}
else
{
AVLTNode<T> *q = node->parent;
if(q->lchild == p)
{
q->lchild = node;
}
else
{
q->rchild = node;
}
}
break;
}
node = p;
p = p->parent;
}
else
{
--p->BF;
if(p->BF == 0)
{
break;
}
if(p->BF == -2)
{
if(node->BF == 1)
{
AVLTNode<T> *q = node->right_rotate();
q->parent = p;
node->parent = q;
p->rchild = q;
node = q;
}
node = p->left_rotate();
node->parent = p->parent;
p->parent = node;
if(!node->parent)
{
root = node;
}
else
{
AVLTNode<T> *q = node->parent;
if(q->lchild == p)
{
q->lchild = node;
}
else
{
q->rchild = node;
}
}
break;
}
node = p;
p = p->parent;
}
}
}
// 刪除操作,父節點的BF會變化,故同樣需要向上追溯。若BF由非0變爲0,則樹高減小,繼續向上追溯;否則停止追溯。
template <typename T>
void AVLTree<T>::erase(const T& elem)
{
BTNode<T> *fp = SearchTree<T>::root_find(elem, root);
if(!fp)
{
return;
}
BTNode<T> *fnode = fp->lchild;
if(!fnode)
{
fnode = (fp->rchild ? fp->rchild : fp);
}
else
{
while(fnode->rchild)
{
fnode = fnode->rchild;
}
}
fp->data = fnode->data;
AVLTNode<T> *p = static_cast<AVLTNode<T>*>(fnode);
AVLTNode<T> *q = p->parent;
AVLTNode<T> *node = static_cast<AVLTNode<T>*>(p->lchild);
if(root == p)
{
delete p;
root = 0;
return;
}
if(node)
{
node->parent = q;
}
bool Left(true);
if(p == q->lchild)
{
q->lchild = node;
}
else
{
Left = false;
q->rchild = node;
}
delete p;
p = node;
while(q)
{
if(Left)
{
int BF = --q->BF;
if(BF == -1)
{
break;
}
else if(BF == -2)
{
node = static_cast<AVLTNode<T>*>(q->rchild);
if(node->BF == 1)
{
AVLTNode<T> *temp = node->right_rotate();
temp->parent = q;
node->parent = temp;
q->rchild = temp;
}
p = q->left_rotate();
p->parent = q->parent;
q->parent = p;
node = p->parent;
if(!node)
{
root = p;
break;
}
if(q == node->lchild)
{
node->lchild = p;
}
else
{
node->rchild = p;
}
q = node;
}
else
{
p = q;
q = q->parent;
}
}
else
{
int BF = ++q->BF;
if(BF == 1)
{
break;
}
else if(BF == 2)
{
node = static_cast<AVLTNode<T>*>(q->lchild);
if(node->BF == -1)
{
AVLTNode<T> *temp = node->left_rotate();
temp->parent = q;
node->parent = temp;
q->lchild = temp;
}
p = q->right_rotate();
p->parent = q->parent;
q->parent = p;
node = p->parent;
if(!node)
{
root = p;
break;
}
if(q == node->lchild)
{
node->lchild = p;
}
else
{
node->rchild = p;
}
q = node;
}
else
{
p = q;
q = q->parent;
}
}
if(q)
{
Left = (p == q->lchild);
}
}
}
template <typename T>
bool AVLTree<T>::find(const T& elem)
{
return SearchTree<T>::root_find(elem, root) != NULL;
}