二叉搜索樹的操作都需要建立在二叉搜索樹上,所以我打算先談一下樹的建立。與之前講到的堆不同,二叉搜索樹的建立需要的是不斷插入。
插入部分代碼:
void Tree_Insert(Tree *root,Tree *z)
{
Tree *x,*y;
y=NULL;
x=root;
while (x!=NULL)
{
y=x;
if (x->key>z->key)
{
x=x->left;
}
else if (x->key<z->key)
{
x=x->right;
}
else
{
return ; //說明樹中已經存在一樣的結點,不用再插入
}
}
z->parent=y;
if (y==NULL)
{
root=z;
}
else if (z->key<y->key)
{
y->left=z;
}
else
{
y->right=z;
}
}
二叉搜索樹的遍歷有三種:先序遍歷,中序遍歷,後續遍歷。根據當前結點輸出,考察先後定義。先序:在其左右子結點之前輸出,考察;中序:在左結點,右結點之間輸出,考察;後序:在其左右子結點考察,輸出後再考察。
先序:
void Print_Tree(Tree *x)
{
if (x!=NULL)
{
cout<<x->key<<endl;
Print_Tree(x->left);
Print_Tree(x->right);
}
}
中序:
void Print_Tree(Tree *x)
{
if (x!=NULL)
{
Print_Tree(x->left);
cout<<x->key<<endl;
Print_Tree(x->right);
}
}
後序:
void Print_Tree(Tree *x)
{
if (x!=NULL)
{
Print_Tree(x->left);
Print_Tree(x->right);
cout<<x->key<<endl;
}
}
查找依照key值進行查找,找到對應之後返回,若沒有對應值將會返回NULL
Tree* Search(Tree *x,key)
{
while (x!=NULL||key==x->key)
{
if (x->key>key)
x=x->left;
else if (x->key<key)
x=x->right;
}
return x;
}
MAX()函數用於返回key值最大的結點,MIN()返回key值最小的結點。因爲這兩個函數以及二叉搜索樹的特徵使得能夠使用二叉搜索樹來實現優先隊列,但似乎效果沒有堆的好。
堆:http://blog.csdn.net/hermit_inwind/article/details/50413255
Tree* MIN(Tree *x)
{
while (x->left!=NULL)
x=x->left;
return x;
}
Tree* MAX(Tree *x)
{
while (x->right!=NULL)
x=x.right;
return x;
}
Transplant(Tree *root,Tree *u,Tree *v)
{
if (u->parent==NULL)
root=v;
else if (u->parent->left==u)
u->parent->left=v;
else
u->parent->right=v;
if (v!=NULL)
v->parent=u->parent;
}
顯然,當u沒有前驅結點的時候,u就爲root結點,將root替換爲v即可。除開這種情況,先判斷u爲其雙親結點的左結點還是右結點,然後將v指向的雙親結點替換爲u指向的雙親結點即可。
接下來在實現刪除的時候使用到Transplant()函數會然代碼看上去更精簡,更美觀。
void Delet(Tree *root,Tree *x)
{
if (x->left==NULL)
Transplant(root,x,x->right);
else if (x->right==NULL)
Transplant(root,x,x-left);
else
{
Tree *y=MIN(x->right);
if (y->parent!=x)
{
Transplant(root,y,y->right);
y->right=x->right;
y->right->parent=y;
}
Transplant(root,x,y);
y->left=x->left;
y->left->parent=y;
}
free(x); //需要返還動態申請的內存
}
Delete實現:先判斷需要刪除的子樹的根結點是否存在子結點中的一個,若不存在左結點,那麼只需要將當前結點的右結點爲根的子樹替換當前子樹即可。簡單來說就是將刪除結點的右節點的雙親結點更新爲刪除結點的雙親結點,刪除結點的雙親結點的右結點更新爲刪除結點的右結點。若刪除結點的右孩子不存在,則將刪除結點與其左孩子替換。若刪除結點的左右子樹均存在,那麼先求出刪除結點右子樹中的最小值,顯然該結點的key值大於所有刪除結點左子樹中的結點,小於除開該結點以外所有刪除結點右子樹中的結點。當求出的key值最小結點就是刪除結點的右結點時,只需要將該結點與刪除結點替換即可,否則需要將該結點與其右結點替換(此時之前求出的結點的指向的右結點爲刪除結點的右子結點),然後將求出結點與刪除結點替換,注意需要調整刪除結點左子結點與替換結點之間的指向關係。最後,由於之前結點的內存是動態申請的,在刪除後注意使用free()函數返還申請的內存。