二叉搜索树(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);
}