什麼是二叉搜索樹
二叉搜索樹是一種特殊的二叉樹,它是被廣泛運用的存儲查找結構------完全平衡二叉樹(AVLtree) 和紅黑樹的基礎(RBtree)
二叉搜索樹的規則:
- 二叉搜索樹可以是一棵空樹
- 如果其節點的左子樹不空 則其左子樹上的所有節點的值小於根節點的值
- 如果其節點的右子樹不空 則其右子樹上的所有節點的值小於根節點的值
- 每個節點的左右子樹都是二叉搜索樹
爲什麼要設計出這種規則的二叉搜索樹呢? 其目的在於提高查詢數據的效率 ,數據存儲在樹的結點中。
在滿足此規則的二叉搜索樹查找數據時 從根結點開始查找 如果要查找的值比當前節點小 則在當前節點的左子樹中查找,
反之則在當前節點的右子樹中查找
如果待查找的的值等於當前結點的值 則返回當前節點的值—查找找功。
如果查找到根節點時還未碰見與待查找值相同的節點 說明該書中沒有這個數據 —–查找失敗
二叉搜索樹首先是一棵二叉樹 他滿足一棵普通二叉樹的所有性質。
二叉搜索樹的操作:
插入操作:
二叉搜索樹一開始是一棵空樹 插入第一個值時把第一個值構造結點作爲根。
插入後續結點時,被插入的值和根節點的值和根節點的值作比較 ,大則和其左節點值相比較 小則和其右結點值相比較。再把 其左/右節點當作根節點比較 依次向下。 直到找到空節點 這時用要插入的值構造一個新節點用指針和其父節點連接起來。注意在查找可以插入的位置時有存儲下來可能作爲新插入節點父節點的節點以便插入。
如果找到了一個節點的值和被插入值相同 則樹中已有該節點 插入失敗 返回false;
代碼實現:
bool Insert(const K& key, const V& value)
{
if (NULL == _pRoot){
_pRoot = new Node(key, value);
return true;
}
Node* pCur = _pRoot;
Node* pParent = pCur;
while (pCur){
if (key < pCur->_key)
{
pParent = pCur;
pCur = pCur->_pLeft;
}
else if (key > pCur->_key)
{
pParent = pCur;
pCur = pCur->_pRight;
}
else return false;
}
pCur = new Node(key, value);
if (key < pParent->_key)
nt->_key)
pParent->_pRight = pCur;
}
bool InsertR(const K& key,const V& v
{
_InsertR(_pRoot,key,value)
}
2.查找操作:
和插入操作非常相似按照插入操作相同的方式從根開始依次比較 和插入相反的是查找時遇到與查找值相;
的節點時返回該節點指針。
遇到NULL節點時說明樹中沒有該節點 返回fNULL;
代碼:
Node* Find(const K& key)
{
Node* pCur = _pRoot;
while (pCur)
{
if (key < pCur->_key)
{
pCur = pCur->_pLeft;
}
else if (key > pCur->_key)
{
pCur = pCur->_pRight;
}
else return pCur;
}
return NULL;
}
3.刪除操作:
刪除操作相比前兩個操作略有難度 難點在於刪除一個節點之後整棵樹仍需保持二叉搜索樹的性質
刪除操作中主要體現了替換法刪除的思想
被刪除的節點可以被分爲以下幾種情況:
1. 空樹 ----return false;
2. 被刪除的節點左節點爲空 ----
1. 該節點爲根節點
讓樹的根指向該節點的右子樹
2. 該節點不是根節點
讓該節點的父節點指向該節點的右子樹
3. 被刪除的節點右節點爲空 ----
1. 該節點爲根節點
讓樹的根指向該節點的左子樹
2. 該節點不是根節點
讓該節點的父節點指向該節點的左子樹
4. 被刪除節點的左右均不爲空---------
找到該節點右子樹的最左結點 把找到的這個節點的值賦給邏輯上要被刪除的節點 並實際刪除找到的這個 邏輯上要被刪除右子樹的最左節點。 此時根據二叉搜索樹的性質該樹依然合法。
其他情況均被包含在以上情況中
代碼:
const K& GetMaxKey()const
{
Node* pCur = _pRoot;
while (pCur->_pRight)
pCur = pCur->_pRight;
return pCur;
}
bool Remove(const K& key)
{
Node* pParent = _pRoot;
Node* pCur = _pRoot;
while (pCur){
if (pCur->_key > key){
pParent = pCur;
pCur = pCur->_pLeft;
}
else if (pCur->_key < key){
pParent = pCur;
pCur = pCur->_pRight;
}
else{
break;
}
}
if (pCur)
{
if (pCur->_pLeft == NULL){
//情況2
if (pCur != _pRoot){
if (pParent->_pLeft == pCur)
pParent->_pLeft = pCur->_pRight;
else
pParent->_pRight = pCur->_pRight;
}
else
_pRoot = pCur->_pRight;
delete pCur;
pCur = NULL;
}
else if (pCur->_pRight == NULL){
//情況3
if (pCur != _pRoot){
if (pParent->_pLeft == pCur)
pParent->_pLeft = pCur->_pLeft;
else
pParent->_pRight = pCur->_pRight;
}
else
_pRoot = pCur->_pLeft;
delete pCur;
pCur = NULL;
}
else{
//情況4
Node* pParent = pCur;
Node* pDel = pCur->_pRight;
while (pDel->_pLeft){
pParent = pDel;
pDel = pDel->_pLeft;
}
pCur->_key = pDel->_key;
pCur->_value = pDel->_value;
if (pParent->_pLeft == pDel)
pParent->_pLeft = pDel->_pRight;
else
pParent->_pRight = pDel->_pR
ight;
delete pDel;
pDel = NULL;
}
return true;
}
return false;
}