搜索树特点: 右子树所有节点比跟节点大 左子树所有节点比根结点小
优点:搜索性能比普通二叉树好的多 普通二叉树无任何规律 搜索性能最好情况下可达log2n级别
缺点:插入顺序如果有问题将会使该树成为一颗最垃圾的树 性能与单链表无异
#include<iostream>
template<typename T>
struct BTreeNode
{
T data;//这里我们是把key也当做value了 其实可以分开看
BTreeNode<T>* left;
BTreeNode<T>* right;
};
template<typename T>
class SearchBTree
{
public:
SearchBTree() :root(nullptr) {}
~SearchBTree();
bool InserElem(const T& data);
void InOrderTravel();
bool DeleteElem(const T& data);
BTreeNode<T>* FindNextIO(const T& data);//找中序的后继结点
BTreeNode<T>* FindPreIO(const T& data);
BTreeNode<T>* FindPrePreO(const T& data);//找这个前序的前驱结点没有任何意义 我就不实现了
//思路如下 先找到我们要找的结点的父节点 如果该结点是父节点的左节点 则前驱结点就是父节点
//如果是父节点的右结点 则是递归父节点的左子节点 找到存在右子节点的左子节点后中最右的右子节点
BTreeNode<T>* FindNextPostO(const T& data);//思路为找到父节点 如果是父节点的右子节点 后继为父节点
//如果是父节点的左子节点 后继为父节点的右子节点中的后序遍历的第一个结点
private:
void InOrderTravel(BTreeNode<T>* root);
void ReleaseNode(BTreeNode<T>* root);
bool DeleteElem(BTreeNode<T>*& root, const T& data);
bool InsertElem(BTreeNode<T>*& root, const T& data);
BTreeNode<T>* FindElem(BTreeNode<T>* root,const T& data);
private:
BTreeNode<T>* root;
};
template<typename T>
SearchBTree<T>::~SearchBTree()
{
ReleaseNode(root);
}
template<typename T>
bool SearchBTree<T>::InserElem(const T& data)
{
return InsertElem(root, data);
}
template<typename T>
void SearchBTree<T>::InOrderTravel()
{
InOrderTravel(root);
}
template<typename T>
bool SearchBTree<T>::DeleteElem(const T& data)
{
return DeleteElem(root, data);
}
template<typename T>
BTreeNode<T>* SearchBTree<T>::FindNextIO(const T& data)
{
//找到大的里面最小的
BTreeNode<T>* next = nullptr;
BTreeNode<T>* cur = root;
while (cur != nullptr)
{
if (cur->data > data)
{
next = cur;
cur = cur->left;
}
else
{
cur = cur->right;
}
}
return next;
}
template<typename T>
BTreeNode<T>* SearchBTree<T>::FindPreIO(const T& data)
{
//前驱为比我小的里面最大的
BTreeNode<T>* pre = nullptr;
BTreeNode<T>* cur = root;
while (cur != nullptr)
{
if (cur->data >= data)
{
//不用更新任何东西直接更新cur就行
cur = cur->left;//去往更小的地方
}
else if (cur->data < data)
{
pre = cur;
cur = cur->right;
}
}
return pre;
}
template<typename T>
void SearchBTree<T>::InOrderTravel(BTreeNode<T>* root)
{
if (root == nullptr)return;
InOrderTravel(root->left);
std::cout << root->data;
InOrderTravel(root->right);
}
template<typename T>
void SearchBTree<T>::ReleaseNode(BTreeNode<T>* root)
{
if (root == nullptr)return;
ReleaseNode(root->left);
ReleaseNode(root->right);
delete root;
}
template<typename T>
bool SearchBTree<T>::DeleteElem(BTreeNode<T>*& root, const T& data)
{
if (root == nullptr)return false;
//找到了应该删除的结点
if (root->data == data)
{
//分三种情况 第一种 左右子节点都为空 那么直接置空就完事了
//第二种 左为空右不为空 或者右为空左不为空 任意一个替换上来就行了
//第三种 找到左子树中最大 或者右子树中最小然后替换即可
if (root->left == nullptr && root->right == nullptr)
{
ReleaseNode(root);
root = nullptr;
}
else if (root->left != nullptr && root->right != nullptr)
{
BTreeNode<T>* tmp = root->right;
BTreeNode<T>* tmpparent = root;
//找右子树中最小值
while (tmp->left)
{
tmpparent = tmp;
tmp = tmp->left;
}
root->data = tmp->data;
tmpparent->left = tmp->right;//收养你的右孩子
delete tmp;
}
else
{
auto tmp = root;
if (root->left == nullptr)
{
root = root->right;
}
else root = root->left;
delete tmp;
}
return true;
}
else
{
//没找到的话继续递归
bool left = DeleteElem(root->left, data);
bool right = DeleteElem(root->right, data);
return left || right;
}
}
template<typename T>
bool SearchBTree<T>::InsertElem(BTreeNode<T>*& root, const T& data)
{
if (root == nullptr)//找到了应该插入的位置 我们进行插入
{
root = new BTreeNode<T>;
root->data = data;
root->left = nullptr;
root->right = nullptr;
return true;
}
bool left = false;
bool right = false;
if (data > root->data)
{
right=InsertElem(root->right,data);
}
else if (data < root->data)
{
left=InsertElem(root->left,data);
}
else//相同的话 我们不做处理
{
return false;
}
return left||right;
}
template<typename T>
BTreeNode<T>* SearchBTree<T>::FindElem(BTreeNode<T>* root,const T& data)
{
if (root == nullptr)return nullptr;
if (root->data == data)return root;
auto left = FindElem(root->left, data);
auto right = FindElem(root->right, data);
return left == nullptr ? right : left;
}
测试代码
int main()
{
SearchBTree<int>tree;
vector<int> vec{ 1,3,5,7,6,2,4,2,3,5 };
for (auto i : vec)
{
tree.InserElem(i);
}
auto temp = tree.FindPreIO(4);
cout << temp->data << endl;
temp = tree.FindNextIO(4);
cout << temp->data<<endl;
for (auto i : vec)
{
tree.DeleteElem(i);
tree.InOrderTravel();
cout << endl;
}
}
测试结果