原理
二叉排序樹的查找過程和次優二叉樹類似,通常採取二叉鍊表作為二叉排序樹的存儲結構。中序遍歷二叉排序樹可得到一個關鍵字的有序序列,一個無序序列可以通過構造一棵二叉排序樹變成一個有序序列,構造樹的過程即為對無序序列進行排序的過程。每次插入的新的結點都是二叉排序樹上新的葉子結點,在進行插入操作時,不必移動其它結點,只需改動某個結點的指針,由空變為非空即可。搜尋,插入,刪除的複雜度等於樹高,O(log(n)).
算法實現
1 二叉排序樹的查找算法
2 在二叉排序樹插入結點的算法
3 在二叉排序樹刪除結點的算法
4 二叉排序樹性能分析
查找算法
在二叉排序樹b中查找x的過程為:
若b是空樹,則搜尋失敗,否則:
若x等於b的根結點的數據域之值,則查找成功;否則:
若x小於b的根結點的數據域之值,則搜尋左子樹;否則:
查找右子樹。
Status SearchBST(BiTree T, KeyType key, BiTree f, BiTree &*p){
//在根指針T所指二叉排序樹中遞歸地查找其關鍵字等於key的數據元素,若查找成功,
//則指針p指向該數據元素結點,並返回TRUE,否則指針指向查找路徑上訪問的最後
//一個結點並返回FALSE,指針f指向T的雙親,其初始調用值為NULL
if(!T){ p=f; return FALSE;} //查找不成功
else if EQ(key, T->data.key) {P=T; return TRUE;} //查找成功
else if LT(key,T->data.key)
return SearchBST(T->lchild, key, T, p); //在左子樹中繼續查找
else return SearchBST(T->rchild, key, T, p); //在右子樹中繼續查找
pascal語言實現
type
Link = ^tree;
Tree = record
D :longint;
Left :link;
Right :link;
End;
function search(n :longint;t :link):boolean;
Begin
If t^.d < n then begin
If t^.right = nil then exit(false) else exit(search(n,t^.right));
End;
If t^.d > n then begin
If t^.left = nil then exit(false) else exit(search(n,t^.left));
End;
Exit(true);
End;
插入算法
向一個二叉排序樹b中插入一個結點s的算法,過程為:
若b是空樹,則將s所指結點作為根結點插入,否則:
若s->data等於b的根結點的數據域之值,則返回,否則:
若s->data小於b的根結點的數據域之值,則把s所指結點插入到左子樹中,否則:
把s所指結點插入到右子樹中。
/*當二叉排序樹T中不存在關鍵字等於e.key的數據元素時,插入e並返回TRUE,否則返回FALSE*/
Status InsertBST(BiTree &T, ElemType e)
{
if(!SearchBST(T, e.key, NULL,p)
{
s=(BiTree *)malloc(sizeof(BiTNode));
s->data = e; s->lchild = s->rchild = NULL;
if(!p) T-s;
//被插結點*s為新的根結點
else if LT(e.key, p->data.key) p->lchld = s;
//被子插結點*s為左孩子
else ->rchild = s;
//被插結點*s為右孩子
return TRUE;
}
else
return FALSE;
//樹中已有關鍵字相同的結點,不再插入
}
pascal代碼:
procedure push(n :longint;var t:link);
Var P,q :link;
Begin
If t^.d < n then begin
If t^.right = nil then begin
New(p);
P^.d := n;
P^.right := nil;
P^.left := nil;
T^.right := p;
End else push(n,t^.right);
End else begin
If t^.left = nil then begin
New(p);
P^.d := n;
P^.right := nil;
P^.left := nil;
T^.left := p;
End else push(n,t^.left);
End;
End;
情況討論
在二叉排序樹刪去一個結點,分三種情況討論:
若*p結點為葉子結點,即PL(左子樹)和PR(右子樹)均為空樹。由於刪去葉子結點不破壞整棵樹的結構,則只需修改其雙親結點的指針即可。
若*p結點只有左子樹PL或右子樹PR,此時只要令PL或PR直接成為其雙親結點*f的左子樹或右子樹即可,作此修改也不破壞二叉排序樹的特性。
若*p結點的左子樹和右子樹均不空。在刪去*p之後,為保持其它元素之間的相對位置不變,可按中序遍歷保持有序進行調整,可以有兩種做法:其一是令*p的左子樹為*f的左子樹,*s為*f左子樹的最右下的結點,而*p的右子樹為*s的右子樹;其二是令*p的直接前驅(或直接後繼)替代*p,然後再從二叉排序樹中刪去它的直接前驅(或直接後繼)。在二叉排序樹上刪除一個結點的算法如下:
Status DeleteBST(BiTree &T, KeyType key){
//若二叉排序樹T中存在關鍵字等於key的數據元素時,則刪除該數據元素,並返回
//TRUE;否則返回FALSE
if(!T) return FALSE; //不存在關鍵字等於key的數據元素
else{
if(EQ(key, T->data.key)) {return Delete(T)}; 找到關鍵字等於key的數據元素
else if(LT(key, T->data.key)) return DeleteBST(T->lchild, key);
else return DeleteBST(T->rchild, key);
}
}
Status Delete(BiTree &p){
//從二叉排序樹中刪除結點p,並重接它的左或右子樹
if(!p->rchild){ //右子樹空則只需重接它的左子樹
q=p; p=p->lchild; free(q);
}
else if(!p->lchild){ //左子樹空只需重接它的右子樹
q=p; p=p->rchild; free(q);
}
else{ //左右子樹均不空
q=p;
s=p->lchild;
while(s->rchild){
q=s;
s=s->rchild
} //轉左,然後向右到盡頭
p->data = s->data; //s指向被刪結點的“前驅”
if(q!=p)
q->rchild = s->lchild; //重接*q的右子樹
else
q->lchild = s->lchild; //重接*q的左子樹
free(s);
}
return TRUE;
}