二叉排序樹C語言實現一
一、定義:
二叉排序樹(二叉搜尋樹、二叉查詢樹)或者是空樹,或者滿足以下性質:`
(1)若它的左子樹非空,則左子樹上所有記錄的值均小於根記錄的值;
(2)若它的右子樹非空,則右子樹上所有記錄的值均大於根記錄的值;
(3)左、右子樹本身又各是一顆二叉排序樹。
——該定義源於《資料結構》李春葆
示例:
二、資料結構:
使用一個連結串列資料結構來表示,節點定義如下:
typedef struct STnode { int key;//資料資訊 struct STnode *left;//指向左孩子 struct STnode *right;//指向右孩子 struct STnode *p;//指向父節點 } STnode;
三、插入操作:
二叉搜尋樹插入操作比較簡單,將欲插入節點my_node從根節點開始比較,用cur_node表示當前被比較的節點,如果my_node.key > cur_node.key,則比較其右孩子,否則比較其左孩子,以此類推,直到找到葉節點為止,將my_node插入(大於所找到的葉節點則作為右孩子插入,小於則作為左孩子插入)。注意:插入操作一定是在葉節點上進的。
示例:插入關鍵字為9的節點,先和根節點比較(9>6),故與其右孩子節點比較(9>7),繼續與其右孩子節點比較(9>8),由於該節點為葉節點,且9>8,則將節點作為右孩子插入。
程式碼:
//將節點my_node插入到二叉搜尋樹tree STnode* STree_Insert(STnode *tree, STnode *my_node) { STnode *parent_node;//指向my_node的父節點 STnode *cur_node;//指向當前被比較的節點 //樹為空 if(tree==NULL) tree=my_node; //樹不為空 else { parent_node=NULL; cur_node=tree; while(cur_node!=NULL) //while迴圈尋找my_node的父節點 { parent_node=cur_node; if(my_node->key < cur_node->key) cur_node=cur_node->left; else cur_node=cur_node->right; } my_node->p=parent_node; if(my_node->key < parent_node->key)//插入到左子樹 parent_node->left=my_node; else //插入到右子樹 parent_node->right=my_node; } return tree; }
四、查詢節點
思想比較簡單,直接上程式碼:
//在tree裡查詢節點my_node STnode *STree_Find(STnode *tree, int my_key) { STnode *cur_node=tree; if(tree==NULL) return NULL; else { while(cur_node->key != my_key) { if(my_key < cur_node->key) cur_node=cur_node->left; else cur_node=cur_node->right; } return cur_node; } }
五、返回最小關鍵位元組點
根據二叉排序樹的性質可知,關鍵字最小的節點一定是整棵樹中最左邊的節點,所以只需從根節點開始一直尋找left指
針,直到找到NULL為止。
程式碼:
//返回最小關鍵字所在節點
STnode *STree_Min(STnode *tree)
{
STnode *cur_node=tree;
while(cur_node->left)
{
cur_node=cur_node->left;
}
return cur_node;
}
六、返回最大關鍵字所在節點
根據二叉排序樹的性質可知,關鍵字最大的節點一定是整棵樹中最右邊的節點,所以只需從根節點開始一直尋找right
指標,直到找到NULL為止。
程式碼:
//返回最大關鍵字所在節點
STnode *STree_Max(STnode *tree)
{
STnode *cur_node=tree;
while(cur_node->right)
{
cur_node=cur_node->right;
}
return cur_node;
}
七、查詢節點後繼(中序)
中序序列為:左子樹、根、右子樹,則一個節點若存在中序後繼,則該後繼必然位於該節點右邊。
下圖所示二叉排序樹的中序為:2、3、4、6、7、13、15、17、18、20
——該圖源於《演算法導論》
如上所述,節點的後繼一定位於節點右邊,分兩種情況:
1、該節點右孩子不為空:其後繼必然是右子樹上的最左節點(如節點6,後繼為節點9);
2、該節點右孩子為NULL且該節點為其父節點的左孩子:後繼為其父節點(如節點2,後繼為節點3);
3、該節點右孩子為NULL且該節點為其父節點的右孩子:後繼必為該節點所在“子樹”根節點T的父節點,該根節點T
必為其父節點的左孩子,否則繼續往上尋找(如節點13,滿足該子樹根節點為其父節點左孩子的子樹根節點為6,
該節點為其父節點15的左孩子,故該節點後繼為15)
程式碼:
STnode *STree_Successor(STnode *my_node)
{
STnode *cur_node;
STnode *successor;
if(my_node->right)//右孩子不為空
return STree_Min(my_node->right);
else //右孩子為空
{
if(my_node==my_node->p->left)//該節點為父節點左孩子
return my_node->p;
else//該節點為父節點右孩子
{
cur_node=my_node;
successor=cur_node->p;
while(successor!=NULL && cur_node!=successor->left)
{
cur_node=cur_node->p;
successor=cur_node->p;
}
return successor;
}
}
}
八、查詢節點前驅(中序)
查詢節點前驅的演算法和查詢節點後繼的演算法對稱,也分為三種情況,分析分發一樣,直接上程式碼。
程式碼:
STnode *STree_Predecessor(STnode *my_node)
{
STnode *cur_node;
STnode *predecessor;
if(my_node->left)//左孩子不為空
return STree_Max(my_node->left);
else //左孩子為空
{
if(my_node==my_node->p->right)//該節點為父節點右孩子
return my_node->p;
else//該節點為父節點左孩子
{
cur_node=my_node;
predecessor=cur_node->p;
while(predecessor!=NULL && cur_node!=predecessor->right)
{
cur_node=cur_node->p;
predecessor=cur_node->p;
}
return predecessor;
}
}
}
七、刪除節點
刪除節點操作是二叉排序樹所有操作中最複雜最難理解的操作,在下一篇博文
(連結地址http://blog.csdn.net/xiaowang627/article/details/51336272 )中對其進行詳細的圖文描述,
同時對所有函式進行測試。