二叉搜尋樹(binary search tree)它或者是一棵空樹,或者是具有下列性質的二叉樹: 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值; 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值; 它的左、右子樹也分別為二叉搜尋樹樹。
節點設定:
typedef
int datatype;
typedef
struct bstreenode
bstreenode;
我們知道二叉搜尋樹的性質是:根節點左邊的節點值均小於根節點;根節點右邊的值都大於根節點,並且所有子樹也滿足這個性質。那麼當我們插入乙個新節點時也必須保證這個性質成立。
1.非遞迴插入
如果是一棵空樹,那就直接根節點指標指向這個插入節點。
不是空樹,就要找到這個節點的正確插入位置。
拿待插入的節點值和根節點比較,比根節點小,就往左子樹尋找插入位置;比根節點大,就往右子樹尋找插入位置。
找到確定位置後比較待插入節點和它父親節點的大小,比之小,就插入到左孩子位置;比之大,就插入到右孩子位置。
bstreenode* buybstreenode(datatype x) //生成新節點
/* 成功返回0,失敗返回-1 */
int bstreeinsert(bstreenode** pptree, datatype x) //插入
bstreenode*
parent
=null;
bstreenode* cur =
*pptree;
while (cur !=
null)
else
if (cur->_data > x)//插入的數小於根節點,往左子樹找位置
else
//相等就不能插入
}if (x >
parent
->_data) //根據大小選擇插入的左節點還是右節點
else
return
0;}
2. 遞迴插入
上面介紹的是非遞迴實現方法,**比較冗餘,接下來介紹遞迴實現插入操作。
int bstreeinsertr(bstreenode** pptree, datatype x) //遞迴插入
/*這裡傳參傳的是當前節點的左右子樹的位址*/
if ((*pptree)->_data > x)
else
if ((*pptree)->_data < x)
else
}
我們發現遞迴實現的**量比非遞迴的少了很多,這段**只有插入節點,但是二叉樹的節點之間不是要鏈結起來嗎?這裡面沒有鏈結**啊?
return bstreeinsertr(&(*pptree)->_left, x);
return bstreeinsertr(&(*pptree)->_right, x);
注意這兩句**,遞迴時是把根節點的左節點指標或右節點指標的位址傳過去了。在下層遞迴中,解引用根節點得到的就是上層遞迴的根節點的左節點指標或右節點指標。
此時讓本層根節點指向插入節點,實際上就是上層根節點的左節點指標或右節點指標指向了待插入節點。這樣待插入節點就和樹中其他節點鏈結起來了。
bstreenode* bstreefind(bstreenode* ptree, datatype x) //查詢
else
if (cur->_data < x)
else
}return
null;
}
1. 非遞迴刪除
刪除節點的情況比較複雜,因為我們刪了乙個節點後也要保證搜尋樹的性質不被改變。為了更好處理,我們把刪除分為三種情況:
1. 被刪除節點的左子樹為空;
2. 被刪除節點的右子樹為空;
3. 被刪除節點的左右子樹均不為空。
情況1和情況2還是挺好處理的,找到待刪除節點和他的父親節點,如果是情況1就讓它的父親節點指向它的右子樹;如果是情況2就讓它的父親節點指向它的左子樹;然後free了這個節點。
情況3是比較麻煩的,應為要刪除的節點有兩個孩子,處理地不好就會破壞二叉樹的結構,這裡給出兩種解決方案。
方案一:找到待刪除的節點cur的右子樹的最左節點sub,把sub節點的值賦給cur節點,然後刪除sub節點。
方案二:找到待刪除的節點cur的左子樹的最右節點sub,把sub節點的值賦給cur節點,然後刪除sub節點。
要注意的是我們也要對sub進行分析,根據sub的情況把刪除分為兩種:
1. sub就是cur的左孩子或右孩子,直接讓cur->_right = sub->_right;
如下圖所示(紅色節點cur, 藍色節點sub):
sub不是cur的孩子,讓sub的父親節點parent->_left = sub->_right;
如下圖所示(紅色節點cur, 藍色節點sub):
int bstreeremove(bstreenode** pptree, datatype x) //刪除
else
if (cur->_data > x)
else //找到了
else 被刪除的節點有父節點,parent
else.2被刪除節點是它父節點的右孩子
del = cur;}}
else
if (cur->_right == null)// 2.右孩子為空
else被刪除節點有父節點,parent
else .2被刪除節點是它父節點的左孩子
del = cur;}}
else // 3.左右孩子都不為空
del = sub;
cur->_data = sub->_data;
if (parent->_left == sub) 找到的sub不是cur的左孩子,此時sub是parent的左孩子
else 找到的sub就是cur的右孩子(sub可能有右子樹,但左子樹必定為空)
//方法二:找左子樹的最右節點
//bstreenode* parent = cur;
//bstreenode* sub = cur->_left;
//while (sub->_right)
////del = sub;
//cur->_data = sub->_data;
//if (parent->_left == sub)
////else//}
free(del);
return
0; }}}
2. 遞迴刪除int bstreeremover(bstreenode** pptree, datatype x)
if ((*pptree)->_data > x)
else
if ((*pptree)->_data < x)
else
else
if ((*pptree)->_right == null)
else
cur->_data = sub->_data;
del = sub;
if (parent->_left == sub)
else
}free(del);
return
0; }
}
void bstreedestoryr(bstreenode** pptree)
二叉搜尋樹的基本操作
建立乙個非負二叉搜尋樹 1表空結點 編寫查詢函式,層序遍歷函式,插入函式,刪除函式,查詢最大值最小值函式 輸入該樹和要查詢的值 輸出 如果找到,列印出 x is found 沒找到列印出 not found 列印出層序遍歷序列 刪除最大值和最小值 刪除成功輸出 x is delete 最後再進行一層...
二叉搜尋樹的基本操作
pragma once typedef int datatype typedef struct bstreenode bstnode include include include bstnode buybstreenode datatype data pnewnode data data pnew...
二叉搜尋樹的基本操作
binsearchtree.h typedef int datatype typedef struct bstreenode bstnode,pbstnode 初始化二叉搜尋樹 void initbstree bstnode proot 生成新節點 pbstnode buynewnode datat...