搜索树:一种二叉树,满足任何节点的关键字大于都其左子树所有节点的关键字,小于其右子树所有节点的关键字(默认所有节点关键字不重复)。
查找:输入需要查找的关键字,从根节点开始,通过比较关键字的大小来搜索,若查找关键字小于根节点,则考察左子树;若查找关键字大于根节点,则考察右子树。最终若指针指向空节点,说明查找元素不存在。
插入:方法类似于查找,最终当指针指向的空节点即为插入元素的位置。
删除:先找到需要删除的节点的位置,若不存在则返回。若删除节点有两个子树,则需要先将需要删除的节点的左子树最大值(或右子树的最小值)节点复制到删除节点上,然后需要删除的节点变为原来左子树最大值(或右子树的最小值)节点。删除节点至多有一个子树时,只需要将子树的根节点替换到删除节点的位置上。
代码
#include<iostream>
using namespace std;
template<class T,class E>
struct bsNode//定义二叉搜索树节点
{
pair<T, E> element;//元素为数对,前项表示关键字,后项表示数值
bsNode<T,E>* leftChild;//左子节点指针
bsNode<T,E>* rightChild;//右子节点指针
bsNode(const pair<T,E>& theElement)
{
element = theElement;
leftChild = NULL;
rightChild = NULL;
}
bsNode(const pair<T, E>& theElement, bsNode<T,E>* LEFT, bsNode<T,E>* RIGHT)
{
element = theElement;
leftChild = LEFT;
rightChild = RIGHT;
}
};
template<class T, class E>
int height(bsNode<T,E>* node)//获得某一节点下二叉树的高度
{
if (node == nullptr)
return 0;
int leftHeight = height(node->leftChild);
int rightHeight = height(node->rightChild);
if (leftHeight > rightHeight)
return ++leftHeight;
else
return ++rightHeight;
}
template<class T, class E>
int countNode(bsNode<T,E>* node)//获取某一节点下二叉树的节点个数
{
if (node == nullptr)
return 0;
int leftCount = countNode(node->leftChild);
int rightCount = countNode(node->rightChild);
return leftCount + rightCount + 1;
}
template<class T, class E>
class bsTree
{
public:
bsTree()
{
size = 0;
root = NULL;
}
void ascend() { inOrder(root); }//按关键字顺序输出元素数值
void find(const T& theKey)//按关键字查找对应元素的数值
{
bsNode<T, E>* p = root;
while (p != NULL)
{
if (theKey < p->element.first)
p = p->leftChild;
else if (theKey > p->element.first)
p = p->rightChild;
else
{
cout << p->element.second << endl;
return;
}
}
cout << "Not find" << endl;
}
void insert(const pair<T, E>& theElement)//插入元素(若关键字上已经存在元素,则覆盖其数值)
{
bsNode<T, E>* p = root;//用于寻找安放空位
bsNode<T, E>* pp = NULL;//p节点的父节点
while (p != NULL)//寻找
{
pp = p;
if (theElement.first < p->element.first)
p = p->leftChild;
else if (theElement.first > p->element.first)
p = p->rightChild;
else
{
p->element.second = theElement.second;//覆盖
return;
}
}
bsNode<T, E>* newNode = new bsNode<T, E>(theElement);
if (root != NULL)//树非空
{
if (theElement.first < pp->element.first)
pp->leftChild = newNode;
else
pp->rightChild = newNode;
}
else//树空
root = newNode;
size++;
}
void erase(const T& theKey)//删除元素
{
bsNode<T, E>* p = root;//用于寻找需要删除的节点
bsNode<T, E>* pp = NULL;//p节点的父节点
while (p != NULL && p->element.first != theKey)//把p定位到删除节点上
{
pp = p;
if (theKey < p->element.first)
p = p->leftChild;
else
p = p->rightChild;
}
if (p == NULL)//若p为空,则说明删除节点不存在,退出函数
{
cout << "Not find" << endl;
return;
}
//当删除节点至多只有一个子树时,只需要将删除节点替换成其子树的根节点;
//当删除节点存在两个子树时,需要先重新组织树结构:
//把删除节点的左子树的关键字最大值(或右子树的关键字最小值)元素复制到删除位置上,
//然后把删除指针指向左子树的关键字最大值(或右子树的关键字最小值)节点,此时转化为删除只有一个子树的节点。
//(↑因为左子树的关键字最大值和右子树的关键字最小值节点至多只有一个子树)
if (p->leftChild != NULL && p->rightChild != NULL)
{
bsNode<T, E>* s = p->leftChild;//寻找p左子树的最大值
bsNode<T, E>* ps = p;//s节点的父节点
while (s->rightChild != NULL)//循环结束后,s指向p的左子树的最大值
{
ps = s;
s = s->rightChild;
}
p->element = s->element;
bsNode<T, E>* q = new bsNode<T, E>(s->element, p->leftChild, p->rightChild);//q节点的元素是p节点左子树的最大值,q节点的位置是p
if (pp == NULL)//以q节点替换p节点
root = q;
else if (p == pp->leftChild)
pp->leftChild = q;
else
pp->rightChild = q;
if (ps == p)//把pp移动到s节点的父节点
pp = q;
else
pp = ps;
delete p;
p = s;//把p移动到s节点
}
//之后删除节点至多只有一个子树
bsNode<T, E>* c;
if (p->leftChild != NULL)
c = p->leftChild;
else
c = p->rightChild;
if (p == root)
root = c;
else
{
if (p == pp->leftChild)
pp->leftChild = c;
else
pp->rightChild = c;
}
size--;
delete p;
}
private:
bsNode<T, E>* root;
int size;
void inOrder(bsNode<T,E>* node)//中序遍历
{
if (node != nullptr)
{
inOrder(node->leftChild);
cout << node->element.second << " ";
inOrder(node->rightChild);
}
}
};
int main()//简单测试
{
bsTree<int, int> tree;
for (int i = 0; i < 10; i++)
{
pair<int, int> p(i, i*2);
tree.insert(p);
}
tree.ascend();
cout << endl;
tree.erase(8);
tree.erase(8);
tree.find(8);
tree.find(7);
tree.ascend();
}