數據結構中的二叉排序樹研究,做個記錄。
(1)二叉排序樹概念(二叉查找樹)
它是一顆空樹,或者具有以下性質的二叉樹。
a、若它的左子樹不爲空,則左子樹上所有結點值均小於它的根結點的值
b、若它的右子樹不爲空,則左子樹上所有結點值均大於它的根結點的值
c、左右子樹有分別是二叉排序樹
(2)二叉排序樹查找操作
二叉排序樹結點結構體:
typedef struct BiTNode //結點結構體
{
int data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
查找代碼如下:
/*********************************************
**功能:遞歸查找二叉排序樹中是否存在key
**T:二叉排序樹
**key:鍵值
**f:指向T的雙親
**p:如果查找成功 指向該數據元素結點 否則指向查找路徑上訪問的最後一個結點,並返回一個false
*********************************************/
int SearchBST(BiTree T,int key,BiTree f,BiTree *p)
{
if (!T) //查找不成功
{
*p = f;
return 0;
}
else if (key == T->data) //找到了鍵值
{
*p = T;
return 1;
}
else if (key < T->data) //左子樹繼續查找
{
return SearchBST(T->lchild,key,T,p);
}
else //右子樹中繼續查找
{
return SearchBST(T->rchild,key,T,p);
}
}
(3)二叉排序樹插入操作/*********************************************
**功能:二叉排序樹插入操作,如果二叉排序樹中不存在關鍵字等於key的數據元素時,插入key並返回true,否則返回false
**T:二叉排序樹
**key:關鍵字
*********************************************/
int InsertBST(BiTree *T,int key)
{
BiTree p,s; //兩個臨時變量,p指向查找路徑上的最後一個結點;s用於新插入的結點
if (!SearchBST(*T,key,NULL,&p)) //查找不成功時進行插入
{
s = (BiTree)malloc(sizeof(BiTNode));
s->data = key;
s->lchild = s->rchild = NULL;
if (!p) //表示一顆空樹
{
*T = s;
}
else if (key < p->data) //插入到左子樹
{
p->lchild = s;
}
else //插入到右子樹
{
p->rchild = s;
}
return 1;
}
else
{
return 0;
}
}
(4)二叉排序樹刪除操作
刪除操作稍微麻煩寫,分三種情況討論
a、待刪除結點是葉子結點(直接刪除)
b、待刪除結點僅有左或者右子樹(子承父業)
c、待刪除結點左右子樹同時存在(找到待刪除結點的直接前驅,用直接前驅替換當前點,然後重接左或右子樹)
代碼如下:
/*********************************************
**功能:二叉排序樹刪除操作,如果二叉排序樹中存在關鍵字等於key的數據元素時,刪除該數據元素結點,並返回true,否則返回false
**T:二叉排序樹
**key:關鍵字
*********************************************/
int DeleteBST(BiTree* T,int key)
{
if (! *T) //不存在關鍵字等於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);
}
}
}
真正執行刪除操作的是Delete()函數,代碼如下:
/*********************************************
**功能:二叉排序樹中刪除結點p,並重接左右子樹
**p:待刪除的結點
*********************************************/
int Delete(BiTree *p)
{
//分三種情況討論:待刪除的結點 1、葉結點 2、僅有左或右子樹 3、左右子樹同時存在
BiTree q,s;
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 1;
}
測試如下:
/*********************************************
**功能:二叉排序樹刪除操作,如果二叉排序樹中存在關鍵字等於key的數據元素時,刪除該數據元素結點,並返回true,否則返回false
**T:二叉排序樹
**key:關鍵字
*********************************************/
int DeleteBST(BiTree* T,int key)
{
if (! *T) //不存在關鍵字等於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);
}
}
}
/*********************************************
**功能:遞歸打印二叉樹,中序遍歷
**T:二叉排序樹
*********************************************/
void PrintBTree(BiTree T)
{
if (!T) //遞歸出口
return;
PrintBTree(T->lchild);
printf("%d\t",T->data);
PrintBTree(T->rchild);
}
int _tmain(int argc, _TCHAR* argv[])
{
int a[] = {62,88,58,47,35,73,51,99,37,93};
BiTree T = NULL;
for (int i=0;i<10;++i)
{
InsertBST(&T,a[i]);
}
PrintBTree(T);
DeleteBST(&T,58);
PrintBTree(T);
return 0;
}
結果有圖爲證: