二叉搜索樹(BinarySearchTree)性質
二叉搜索樹首先是一棵二叉樹,二叉樹可能爲空,而一顆非空的二叉搜索樹要滿足以下條件:
(1)每個元素有一個關鍵字,所有關鍵字是唯一的。(關鍵字不唯一的二叉搜索樹叫有重複值的二叉搜索樹)
(2)在根節點的左子數的元素都小於根節點的關鍵字。
(3)在根節點的右子數的元素都大於根節點的關鍵字。
(4)根節點的左右子樹也是一棵二叉搜索樹
二叉搜索樹的結構
c++代碼:
template <class K,class V>
struct BSTnode //二叉搜索樹節點結構
{
BSTnode *leftChild; //左子樹
BSTnode *rightChild; //右子樹
K key;
V value;
//構造方法
BSTnode(const K& theKey,const V& theValue)
:leftChild(NULL),rightChild(NULL),key(theKey),value(theValue)
{}
};
template <class K,class V>
class MyBSTree
{
private:
BSTnode<K, V> rootNode; //根節點
public:
BSTnode<K, V>* Find(const K& theKey); //查找
bool Insert(const K& theKey, const V& theValue); //插入
bool Erase(const K& theKey); //刪除
void InOrder(); //中序遍歷
};
二叉搜索樹的查找
查找的遞歸實現(c++):
//查找的遞歸實現
template <class K,class V>
BSTnode<K, V>* MyBSTree<K, V>::Find(BSTnode<K,V>* root,const K& theKey)
{
if (root == NULL)
{
return NULL;
}
if (root->key > theKey)
{
return Find(root->leftChild, theKey);
}
else if (root->key < theKey)
{
return Find(root->rightChild, theKey);
}
else
{
return root;
}
}
查找的迭代實現(c++):
template <class K,class V>
BSTnode<K, V>* MyBSTree<K, V>::Find(const K& theKey)
{
BSTnode<K, V>* currentNode = rootNode;
while (currentNode != NULL)
{
if (currentNode->key > theKey)
{
currentNode = currentNode->rightChild;
}
else if (currentNode->key < theKey)
{
currentNode = currentNode->leftChild;
}
else
{
return currentNode;
}
}
return NULL;
}
二叉搜索樹的插入二叉搜索樹的插入步驟:
首先查找二叉搜索樹是否有節點的關鍵字和要插入的相同,有的話則不插入;
如果沒有與要插入的節點的關鍵字相同的節點,則將該節點作爲搜索中斷的節點的孩子插入二叉搜索樹。
插入的遞歸實現
template <class K,class V>
bool MyBSTree<K,V>::Insert(BSTnode<K,V>*& root ,const K& theKey, const V& theValue)
{
if (root == NULL)
{
rootNode = new BSTnode(theKey, theValue);
return true;
}
if (root->key >theKey)
{
return Insert(root->leftChild,theKey,theValue);
}
else if (root->key < theKey)
{
return Insert(root->rightChild,theKey,theValue);
}
else
{
return false;
}
}
插入的迭代實現
//插入的迭代實現
template <class K, class V>
bool MyBSTree<K, V>::Insert(const K& theKey, const V& theValue)
{
if (rootNode == NULL) //插入空樹
{
rootNode = new BSTnode(theKey, theValue);
return;
}
BSTnode<K, V>* currentNode = rootNode;
BSTnode<K, V>* parentNode = NULL;
while (currentNode != NULL) //尋找插入位置
{
if (currentNode->key > theKey)
{
parentNode = currentNode;
currentNode = currentNode->leftChild;
}
else if (currentNode->key < theKey)
{
parentNode = currentNode;
currentNode = currentNode->rightChild;
}
else
{
return false;
}
}
//找到插入位置後,判斷是左節點還是右節點,建立新的節點並與parentNode進行連接
if (parentNode->key >theKey)
{
parentNode->leftChild = new BSTnode(theKey, theValue);
}
else if (parentNode->key < theKey)
{
parentNode->rightChild = new BSTnode(theKey, theValue);
}
return true;
}
二叉搜索樹的刪除
二叉搜索樹刪除的步驟:
要考慮三種情況:(1)p是葉子節點(2)p只有只有一棵非空子樹(3)p有兩棵非空子樹
當p爲葉子節點,只需要把p的父節點對應子樹置爲NULL,如果p爲根節點,則令根節點爲NULL。
當p有一棵非空子樹,子樹繼承p的位置。
當p有兩棵非空子樹,找到p的最近前驅,來替代p的位置,並將前驅刪去,用前驅的子樹替代前驅位置。
刪除的遞歸實現:
//刪除遞歸實現
template <class K, class V>
bool MyBSTree<K, V>::Erase(BSTnode<K,V>*& root,const K& theKey)
{
if (root == NULL) //空樹
{
return false;
}
if (root->leftChild == NULL&&root->rightChild == NULL) //只有根節點
{
if (root->key == theKey) //要刪除的是根節點
{
delete root;
root = NULL;
return true;
}
else
{
return false;
}
}
if (root->key > theKey)
{
Erase(root->leftChild, theKey);
}
else if (root -> key < theKey)
{
Erase(root->rightChild, theKey);
}
else //找到要刪除的節點
{
BSTnode<K, V>* tempNode = NULL; //臨時節點
if (root->leftChild == NULL) //沒有左子樹
{
tempNode = root;
root = root->rightChild; //右子樹繼承自身位置
delete tempNode;
return true;
}
else if (root ->rightChild == NULL) //沒有右子樹
{
tempNode = root;
root = root->leftChild; //左子樹替代自身位置
delete tempNode;
return true;
}
else //既有左子樹也有右子樹
{
//找到最近前驅
BSTnode<K, V>* closestNode = root->leftChild;
while (closestNode->rightChild) //根節點左子樹的右子樹爲最近前驅
{
tempNode = closestNode;
closestNode = closestNode->rightChild;
}
//前驅替換要刪除的節點
swap(root->key, closestNode->key);
swap(root->value, closestNode->value);
Erase(root->leftChild);
}
}
}
刪除的迭代實現:
//刪除迭代實現
template <class K, class V>
bool MyBSTree<K, V>::Erase(const K& theKey)
{
if (rootNode == NULL) //空樹
{
return false;
}
if (rootNode->leftChild ==NULL&& rootNode->rightChild ==NULL) //只有根節點
{
if (rootNode.key == theKey)
{
rootNode = NULL;
delete rootNode;
return true;
}
return false;
}
BSTnode<K, V>* parentNode = NULL;
BSTnode<K, V>* currentNode = rootNode;
while (currentNode != NULL)
{ //尋找要刪除的節點
if (currentNode->key>theKey)
{
parentNode = currentNode;
currentNode = currentNode->leftChild;
}
else if (currentNode->key<theKey)
{
parentNode = currentNode;
currentNode = currentNode->rightChild;
}
else
{ //找到要刪除的節點
if (currentNode->leftChild == NULL) //沒有左子樹
{
if (parentNode == NULL) //要刪除的爲根節點
{
rootNode = currentNode.rightChild;
delete currentNode;
currentNode = NULL;
return true;
}
if (parentNode->key>currentNode->key)
{
parentNode->leftChild = currentNode->rightChild;
delete currentNode;
currentNode = NULL;
return true;
}
else if (parent->key<currentNode->key)
{
parentNode->rightChild = currentNode->rightChild;
delete currentNode;
currentNode = NULL;
return true;
}
}
else if (currentNode->rightChild == NULL) //沒有右子樹,同沒右左子樹
{
if (parentNode == NULL) //要刪除的爲根節點
{
rootNode = currentNode.leftChild;
delete currentNode;
currentNode = NULL;
return true;
}
if (parentNode->key>currentNode->key)
{
parentNode->leftChild = currentNode->leftChild;
delete currentNode;
currentNode = NULL;
return true;
}
else if (parent->key<currentNode->key)
{
parentNode->rightChild = currentNode->leftChild;
delete currentNode;
currentNode = NULL;
return true;
}
}
else //既有左子樹也有右子樹
{
BSTnode<K, V>* tempNode = currentNode;
BSTnode<K, V>* closestNode = currentNode->leftChild;
while (closestNode->rightChild)
{
tempNode = closestNode;
closestNode = closestNode->rightChild; //closestNode指向最近前驅節點,tempNode指向其父節點
}
currentNode->key = closestNode->key;
currentNode->value = closestNode->value;
if (tempNode != currentNode)
tempNode->rightChild = closestNode->leftChild;
else
{
tempNode->leftChild = closestNode->leftChild;
}
delete tempNode;
}
return true;
}
}
}
二叉搜索樹的遍歷
根據二叉搜索樹的性質,所以二叉樹的中序遍歷可以得到有序表。
中序遍歷的實現(c++)
//中序遍歷
template <class K,class V>
void MyBSTree<K, V>::InOrder()
{
if (rootNode == NULL)
{
return;
}
InOrder(rootNode->leftChild);
cout << rootNode->key<<" ";
InOrder(rootNode->rightChild);
}