1 二叉搜索树概念
- 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也分别为二叉搜索树
int a [] = {5,3,4,1,7,8,2,6,0,9};
2 二叉搜索树操作
- 二叉搜索树的查找
- 二叉搜索树的插入
插入的具体过程如下:
a. 树为空,则直接插入
b. 树不空,按二叉搜索树性质查找插入位置,插入新节点
- 二叉搜索树的删除
首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情况:
a. 要删除的结点无孩子结点
b. 要删除的结点只有左孩子结点
c. 要删除的结点只有右孩子结点
d. 要删除的结点有左、右孩子结点
看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程如下:
- 情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点
- 情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点
- 情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中,
再来处理该结点的删除问题
3 二叉搜索树的实现
#include<time.h>
#include<iostream>
using namespace std;
template <class T>
struct BNode
{
T _data;
typedef BNode<T> Node;
Node* _left;
Node* _right;
BNode(const T& data)
:_data(data)
, _left(nullptr)
, _right(nullptr)
{}
};
template <class T>
class BTree
{
public:
typedef BNode<T> Node;
Node* find(const T& val)
{
Node* cur = _root;
while (cur)
{
if (cur->_data == val)
return cur;
else if (cur->_data > val)
cur = cur->_left;
else
cur = cur->_right;
}
}
//拷贝二叉搜索树的数据和结构
Node* copy(Node* root)
{
if (root == nullptr)
return nullptr;
Node* newNode = new Node(root->_data);
newNode->_left = copy(root->_left);
newNode->_right = copy(root->_right);
return newNode;
}
//拷贝构造
BTree(const BTree<T>& btree)
:_root(copy(btree._root))
{}
BTree()
:_root(nullptr)
{}
//不插入重复的值
bool insert(const T& val)
{
//插入第一个值
if (_root == nullptr)
{
_root = new Node(val);
return true;
}
//找到需要插入元素的位置
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
parent = cur;
if (cur->_data == val)
return false;
else if (cur->_data > val)
cur = cur->_left;
else
cur = cur->_right;
}
//插入
cur = new Node(val);
if (parent->_data > val)
parent->_left = cur;
else
parent->_right = cur;
return true;
}
void inorder()
{
_inorder(_root);
cout << endl;
}
//搜索树的中序遍历有序
void _inorder(Node* root)
{
if (root)
{
_inorder(root->_left);
cout << root->_data << " ";
_inorder(root->_right);
}
}
//销毁
void destroy(Node* root)
{
if (root)
{
destroy(root->_left);
destroy(root->_right);
cout << "destroy:" << root->_data << endl;
delete root;
}
}
~BTree()
{
if (_root)
{
destroy(_root);
_root = nullptr;
}
}
bool erase(const T& val)
{
//查找
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (cur->_data == val)
break;
parent = cur;
if (cur->_data > val)
cur = cur->_left;
else
cur = cur->_right;
}
//删除
//1.删除的为叶子节点
if (cur->_left == nullptr && cur->_right == nullptr)
{
//判断是否为根节点
if (cur == _root)
{
_root = nullptr;
}
else
{
//判断需要删除的父节点在哪一边
if (parent->_left == cur)
parent->_left = nullptr;
else
parent->_right = nullptr;
}
//删除节点
delete cur;
}
else if (cur->_left == nullptr) //左为空
{
//判断是否为根节点
if (cur == _root)
{
//更新根节点
_root = cur->_right;
}
else
{
if (parent->_left == cur)
parent->_left = cur->_right;
else
parent->_right = cur->_right;
}
//删除节点
delete cur;
}
else if (cur->_right == nullptr)
{
//判断是否为根节点
if (cur == _root)
{
//更新根节点
_root = cur->_left;
}
else
{
if (parent->_left == cur)
parent->_left = cur->_left;
else
parent->_right = cur->_left;
}
delete cur;
}
else
{
//左右子树都存在
//1.假设找左子树的最右节点
Node* leftRightMost = cur->_left;
parent = cur;
while (leftRightMost->_right)
{
parent = leftRightMost;
leftRightMost =leftRightMost->_right;
}
//2.交换
swap(cur->_data, leftRightMost->_data);
//3.删除最右节点
if (parent->_left == leftRightMost)
parent->_left = leftRightMost->_left;
else
parent->_right = leftRightMost->_left;
//4.删除最右节点
delete leftRightMost;
}
return true;
}
private:
Node* _root;
};
//void test()
//{
// BTree<int> b;
// b.insert(5);
// b.insert(3);
// b.insert(7);
// b.insert(1);
// b.insert(4);
// b.insert(6);
// b.insert(8);
// b.insert(0);
// b.insert(2);
// b.insert(9);
// b.inorder();
//
// b.erase(5);
// b.inorder();
//}
//
//int main()
//{
// test();
// return 0;
//}