一、定義
二叉排序樹(BST)(二叉查找樹)或者是一棵空樹,或者是具有下列特性的二叉樹:
1)若左子樹非空,則左子樹上所有的結點的值均小於根結點的值。
2)若右子樹非空,則右子樹上所有結點的值均大於根結點的值。
3)左右子樹均是一棵二叉排序樹
注意:由二叉排序樹的定義可知,左子樹結點值<根結點值<右子樹結點值,所以如果我們對二叉排序樹進行中序遍歷(左根右),可以得到一個遞增(這里的遞增是針對於結點值而言,也就是查找的關鍵字)的有序序列
二叉樹排序樹的結構體
/*其實就是二叉樹的二叉鏈表的結點定義*/
typedef struct BiTNode
{
ElemType data;//關鍵字
struct BiTNode *lchild,*rchild;//左右孩子
}BiTNode,*BiTree;
二叉排序樹的建立
void CreatBST(BiTree &T,KeyType str[],int n)
{
T=NULL;
int i=0;
while(i<n)
{
InsertBST(T,str[i]);
i++;
}
}
二、二叉排序樹的查找
算法描述:從根結點開始,沿着某個分支逐層向下比較。若二叉排序樹非空,先將給定值與根結點的關鍵字比較,若相等,則查找成功;若不等,如果小於根結點的關鍵字,則在根結點的左子樹上查找,否則在根結點的右子樹上查找。
1.遞歸實現
int SearchBST(BiTree T,int key,BiTree f,BiTree &p)//二叉樹f指向T的雙親
{
if(T==NULL)
{
p=f;
return 0;
}
else if(key==T->data)//查找成功,則P指向該數據元素結點
{
p=T;
return 1;
}
else if(key<T->data)//在左子樹中繼續查找
{
return SearchBST(T->lchild,key,T,p);
}
else//在右子樹中繼續查找
{
return SearchBST(T->rchild,key,T,p);
}
}
2.非遞歸實現
BiTNode *SearchBST(BiTree T,ElemType key)
{
while(T!=NULL&&key!=T->data)//若樹為空或者等於根結點值,則結束循環
{
if(key<T->data)//小於,則在左子樹查找
{
T=T->lchild;
}
else//大於,則在右子樹查找
{
T=T->rchild;
}
}
return T;
}
三、二叉排序樹的插入
算法描述:若二叉排序樹為空,則直接插入結點;否則,若關鍵字key小於根節點值,則插入到左子樹,若關鍵字key大於根結點值,則插入到右子樹。
注意:插入的結點一定是一個新添加的葉子結點,且是查找失敗時的查找路徑上訪問的最后一個結點的左孩子或右孩子。
int insertBST(BiTree &T,KeyType key)
{
if(T==NULL)
{
T=(BiTree)malloc(sizeof(BiTNode));
T->data=key;
T->lchild=T->rchild=NULL;
return 1;
}
else if(key==T->data)
{
return 0;
}
else if(key<T->data)
{
return InsertBST(T->lchild,key);
}
else
{
return InsertBST(T->rchild,key);
}
}
四、二叉排序樹的刪除
算法描述:分三種情況
- 若被刪除結點是葉子結點,則直接刪除,不會破壞二叉排序樹的性質。
- 若被刪除結點只有左子樹或者右子樹,則讓該結點的子樹代替該結點的位置。
- 若被刪除結點有左右兩棵子樹,則令該結點中序遍歷下的直接前驅或直接后繼替代該結點,然后從二叉排序樹中刪去這個直接前驅或直接后繼,這樣就轉換成了第一或第二種情況。
/* 從二叉排序樹中刪除結點p,並重接它的左或右子樹。 */
int Delete(BiTree &p)
{
BiTree q,s;
if(p->rchild==NULL) /* 右子樹空則只需重接它的左子樹(待刪結點是葉子也走此分支) */
{
q=p;p=p->lchild; free(q);
}
else if(p->lchild==NULL) /* 只需重接它的右子樹 */
{
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//說明p==q,也就是說前面的while循環沒有進行,也就是說一開始s沒有右子樹,此時直接將s的左子樹接到q的左子樹上就行
{
q->lchild=s->lchild; /* 重接q的左子樹 */
}
free(s);
}
return 1;
}
/* 若二叉排序樹T中存在關鍵字等於key的數據元素時,則刪除該數據元素結點, */
/* 並返回1;否則返回0。 */
int DeleteBST(BiTree T,KeyType key)
{
if(T==NULL) /* 不存在關鍵字等於key的數據元素 */
{
return 0;
}
else
{
if (key==T->data) /* 找到關鍵字等於key的數據元素 */
{
return Delete(T);
}
else if (key<T->data)
{
return DeleteBST(T->lchild,key);//左子樹
}
else
{
return DeleteBST(T->rchild,key);//右子樹
}
}
}