二叉搜索树概念
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也分别为二叉搜索树
例如、
int a [ ] = {5,3,4,1,7,8,2,6,0,9};
1.二叉搜索树的查找
2.二叉搜索树的插入
a. 树为空,则直接插入.
如果是空树,直接插入,然后返回true.
b.树不空,按二叉搜索树性质插入位置,插入新节点。
3.二叉搜索树的删除
首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:
a. 要删除的结点无孩子结点
b. 要删除的结点只有左孩子结点
c. 要删除的结点只有右孩子结点
d. 要删除的结点有左、右孩子结点
看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程如下:
情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点
情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点
情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,
再来处理该结点的删除问题。
二叉搜索树实现
#pragma once
#include <vector>
#include <stack>
namespace leb {
template <class T>
class TreeNode
{
T m_data;
TreeNode<T> * m_left;
TreeNode<T> * m_right;
public:
TreeNode(const T & val = T()) :
m_data(val),
m_left(nullptr),
m_right(nullptr)
{}
template <class T>
friend class BinarySortTree;
};
template <class T>
class BinarySortTree
{
TreeNode<T> * m_root;
void destroy(TreeNode<T> * root)
{
if (root)
{
destroy(root->m_left);
destroy(root->m_right);
delete root;
}
}
public:
BinarySortTree() :
m_root(nullptr)
{}
~BinarySortTree()
{
destroy(m_root);
}
bool insert(const T &val)
{
if (m_root == nullptr)
{
m_root = new TreeNode<T>(val);
return true;
}
TreeNode<T> * cur = m_root;
TreeNode<T> * pre = nullptr;
while (cur)
{
if (val < cur->m_data)
{
pre = cur;
cur = cur->m_left;
}
else if (val > cur->m_data)
{
pre = cur;
cur = cur->m_right;
}
else
{
return false;
}
}
cur = new TreeNode<T>(val);
if (val < pre->m_data)
{
pre->m_left = cur;
}
else
{
pre->m_right = cur;
}
return true;
}
bool erase(const T &val)
{
if (m_root == nullptr)
{
return false;
}
TreeNode<T> * cur = m_root;
TreeNode<T> * pre = m_root;
while (cur)
{
if (val < cur->m_data)
{
pre = cur;
cur = cur->m_left;
}
else if (val > cur->m_data)
{
pre = cur;
cur = cur->m_right;
}
else
{
break;
}
}
if (cur == nullptr)
{
return false;
}
if (cur->m_left && cur->m_right)
{
#if 0
TreeNode<T> * cur2 = cur->m_left;
TreeNode<T> * pre2 = cur;
if (cur2->m_right)
{
for (; cur2->m_right; pre2 = cur2, cur2 = cur2->m_right);
pre2->m_right = cur2->m_left;
cur2->m_left = cur->m_left;
}
cur2->m_right = cur->m_right;
if (cur == pre)
{
m_root = cur2;
}
else
{
if (cur->m_data < pre->m_data)
{
pre->m_left = cur2;
}
else
{
pre->m_right = cur2;
}
}
delete cur;
#else
TreeNode<T> * cur2 = cur->m_left;
TreeNode<T> * pre2 = cur;
if (cur2->m_right)
{
for (; cur2->m_right; pre2 = cur2, cur2 = cur2->m_right);
pre2->m_right = cur2->m_left;
}
cur->m_data = cur2->m_data;
delete cur2;
#endif
}
else if (cur->m_left)
{
if (cur == pre)
{
m_root = cur->m_left;
}
else
{
if (cur->m_data < pre->m_data)
{
pre->m_left = cur->m_left;
}
else
{
pre->m_right = cur->m_left;
}
}
delete cur;
}
else
{
if (cur == pre)
{
m_root = cur->m_right;
}
else
{
if (cur->m_data < pre->m_data)
{
pre->m_left = cur->m_right;
}
else
{
pre->m_right = cur->m_right;
}
}
delete cur;
}
}
/*
看是不是有左右子树:
①左右子树都有:
a、左子树没有右孩子
直接让左孩子继承自己的右孩子和父亲
b、左子树有右孩子
一路向右,找到最后的一个右孩子,然后将这个孩子的
左子树挂在它父亲的右子树上,然后让它继承要删除节
点的人际关系(左右子树和父亲)
当要删除的节点是根节点时,不用继承父亲关系,但要修改
根节点指向。
②只有左子树
直接让左子树继承自己的父亲关系,如果要删的是根,那么
直接换根即可。
③其他
直接让右子树(或者空)继承自己的父亲关系,其他同上
*/
std::vector<T> InOrder()
{
std::stack<TreeNode<T> *> s;
std::vector<T> res;
TreeNode<T> * cur = m_root;
while (cur || !s.empty())
{
for (; cur; cur = cur->m_left)
{
s.push(cur);
}
if (!s.empty())
{
cur = s.top();
res.push_back(cur->m_data);
s.pop();
cur = cur->m_right;
}
}
return res;
}
};
};
#include "binaryTree.h"
#include <iostream>
using namespace std;
int main()
{
leb::BinarySortTree<int> bst;
bst.insert(5);
bst.insert(2);
bst.insert(8);
bst.insert(0);
bst.insert(1);
bst.insert(4);
bst.insert(7);
bst.insert(9);
bst.insert(3);
bst.insert(6);
bst.erase(7);
vector<int> v = bst.InOrder();
for (auto & i : v)
{
cout << i << ' ';
}
system("pause");
return 0;
}
运行结果: