BST樹:(也稱二叉排序樹或二叉搜索樹)
特點:如果左孩子不空,則左孩子一定比根結點值要小,如果右孩子不空,則右孩子一定比根節點值要大
頭結點的組成如下:
Lchild(指向BST最小結點) | parent(指向BST的根) | data(隨機值) | Rchild(指向BST最大結點) |
一、創建結點:
#include<iostream>
using namespace std;
typedef int ElemType;
typedef struct BstNode
{
BstNode *LeftChild;
BstNode *parent;
BstNode *RightChild;
ElemType data;
}BstNode;
typedef struct
{
BstNode *head;
int Cursize ;
}BSTree;
二、購買結點和釋放結點
BstNode *BuyNode(BstNode *parent = NULL, BstNode *Leftchild = NULL, BstNode *Rightchild = NULL)
{
BstNode *p = (BstNode *)malloc(sizeof(BstNode));
if(NULL == p)
{
return NULL;
}
p->LeftChild = Leftchild;
p->parent = parent;
p->RightChild = Rightchild;
return p;
}
void FreeNode(BstNode *p)
{
free(p);
}
三、初始化:
void InitBSTree(BSTree &bt)
{
bt.Cursize = 0;
bt.head = BuyNode();
}
四、非遞歸查找某個數值的結點
BstNode *FindValue(BSTree &bt, ElemType x) //非遞歸查找
{
BstNode *p = bt.head->parent;
while (p!= NULL && p->data != x)
{
p = x > p->data ? p->RightChild:p->LeftChild;
}
if(p->data == x)
return p;
}
五、遞歸查找某個數值的結點
BstNode *Search(BstNode *p,ElemType x)
{
if(p == NULL || p->data == x)
return p;
else if(p->data > x)
{
return Search(p->LeftChild,x);
}
else
{
return Search(p->RightChild,x);
}
}
BstNode *SearchValue(BSTree &bt, ElemType x) //遞歸查找
{
return Search(bt.head->parent,x);
}
六、插入結點
bool InsertItem(BSTree &bt, ElemType x)
{
BstNode *pa = bt.head; //head
BstNode *p = bt.head->parent; //root
while (p!= NULL && p->data != x)
{
pa = p;
p = x > p->data ? p->RightChild:p->LeftChild;
}
if(p != NULL)
{
return false;
}
p = BuyNode(pa);
p->data = x;
if(pa == bt.head) //在空的二叉樹中插入結點
{
bt.head->parent = p;
bt.head->LeftChild = p;
bt.head->RightChild = p;
}
else //非空二叉樹中插入結點
{
if(p->data < pa->data)
{
pa->LeftChild = p;
if(bt.head->LeftChild->data > p->data) //維護BST樹中,頭結點左指針指向樹中最小值結點
{
bt.head->LeftChild = p;
}
}
else
{
pa->RightChild = p;
if(bt.head->RightChild->data < p->data)//維護BST中,頭結點右孩子指向樹中最大值得結點
{
bt.head->RightChild = p;
}
}
}
bt.Cursize += 1;
return true;
}
七、非遞歸中序遍歷
BstNode *First(BstNode *ptr)
{
while(ptr != NULL && ptr->LeftChild != NULL)
{
ptr = ptr->LeftChild;
}
return ptr;
}
BstNode * Next(BSTree &bt,BstNode *ptr)
{
if(NULL == ptr || ptr == bt.head) return NULL;
if(ptr->RightChild != NULL)
{
return First(ptr->RightChild);
}
else
{
BstNode *pa = ptr->parent;
while(pa != bt.head && pa->LeftChild != ptr)
{
ptr = pa;
pa = pa->parent;
}
if(pa == bt.head)
{
pa = NULL;
}
return pa;
}
}
//非遞歸遍歷
void NiceInOrder(BSTree &bt)
{
for(BstNode *p = First(bt.head->parent); p != NULL ; p = Next(bt,p))
{
cout<<p->data<<" ";
}
cout<<endl;
}
八、遞歸中序遍歷
void InOrder(BstNode *p)
{
if(p != NULL)
{
InOrder(p->LeftChild);
cout<<p->data<<" ";
InOrder(p->RightChild);
}
}
void InOrder(BSTree &bt)
{
InOrder(bt.head->parent);
cout<<endl;
}
九、刪除結點:
在刪除結點的時候要考慮:
(1)空樹
(2)是否找得到要刪除的結點
(3)葉子結點
(4)單分支
(5)雙分支雙分支轉換爲刪除它的找它的直接前驅或者直接後繼刪除,然後進行替換
int GetSize(BSTree &bt)
{
return bt.Cursize;
}
bool Empty(BSTree &bt)
{
return GetSize(bt) == 0;
}
bool RemoveItem(BSTree &bt, ElemType x)//刪除某一結點
{
if(Empty(bt)) //二叉樹是否爲空
{
return false;
}
BstNode *p = FindValue(bt,x); //能否找得到要刪除的結點
if(NULL == p)
{
return false;
}
if(p->LeftChild != NULL && p->RightChild != NULL) //刪除的是有雙分支的結點
{
BstNode *nt = Next(bt,p);
p->data = nt->data;
p = nt;
}
BstNode *pa = p->parent;
BstNode *child = p->LeftChild != NULL? p->LeftChild:p->RightChild;
if(child != NULL)
{
child->parent = pa;
}
if(pa == bt.head) //刪除根節點
{
bt.head->parent = child;
}
else
{
if(pa->LeftChild == p)
{
pa->LeftChild = child;
}
else
{
pa->RightChild = child;
}
}
FreeNode(p);
bt.Cursize -= 1;
return true;
}
十、測試
int main()
{
int ar[]={53,17,78,9,45,65,87,23,81,94,88};
int n = sizeof(ar)/sizeof(ar[0]);
int x = 0;
BSTree myt;
InitBSTree(myt);
for(int i = 0;i<n;++i)
{
InsertItem(myt,ar[i]);
}
NiceInOrder(myt);
ResNiceInOrder(myt);
while(cin>>x , x != -1)
{
RemoveItem(myt,x);
NiceInOrder(myt);
}
cout<<"InsertItem(myt,16) "<<InsertItem(myt,16)<<endl;
NiceInOrder(myt);
BstNode *p1 = FindValue(myt,23);
cout<<"FindValue(myt,23) "<<p1->data<<endl;
BstNode *p2 = SearchValue(myt,23);
cout<<"SearchValue(myt,23) "<<p2->data<<endl;
return 0;
}
十一、結果展示: