一、二叉搜索树的定义
二叉搜索树又称二叉排序树,它或者是一颗空树,或者是一棵排序树,它具有如下性质:
1、若它的左子树不为空,则它的左子树的所有节点的值都小于根节点的值
2、若它的右子树不为空,则它的右子树的所有节点的值都大于根节点的值
3、它的左右子树也都是二叉搜索树
二、二叉树的主要操作分析
1、二叉树的插入
a.若二叉树为空,则直接插入,然后返回true
b.若二叉树不为空,按照二叉搜索树的性质查找插入位置,插入新节点
举个例子:插入节点12
2、二叉树的查找
若根节点不为空
a.如果root->_key=Find(key),返回true;
b.如果root->_key>Find(key),在其左树查找
c.如果root->_key<Find(key),在其右树查找
否则,返回false。
举个例子:查找2
3、二叉树的删除
首先查找要删除的元素是否在二叉树中,如果不存在,则返回,否则要删除的节点可能存在以下几种情况:
a.要删除的节点左为空,则让父亲指向节点的右,删除节点
b.要删除的节点右为空,则让父亲指向节点的左,删除节点
c.要删除的节点左右都不为空,找右树的最左节点或左树的最右节点替换要删除的节点
举例说明
1)要删除的节点左为空,删除8
2)要删除的节点右为空,删除7
3)要删除的节点左右都不是空,删除7
这里需要注意的是:
若找的是右树的最左节点,则最左节点的右树不一定为空;
若找的是左树的最右节点,则最右节点的左树不一定为空;
附上二叉搜索树的模拟实现代码:
#pragma once
#include <iostream>
#include <set>
using namespace std;
template <class K>
struct BSTNode
{
BSTNode(const K& key = K())
:_left(nullptr)
,_right(nullptr)
, _key(key)
{}
BSTNode* _left;
BSTNode* _right;
K _key;
};
template <class K>
class BSTree
{
typedef BSTNode<K> Node;
public:
BSTree()
:_root(nullptr)
{}
Node* Copy(Node* root)
{
if (root == nullptr)
{
return nullptr;
}
//前序拷贝
Node* newroot = new Node(root->_key);
newroot->_left = Copy(root->_left);
newroot->_right = Copy(root->_right);
return newroot;
}
//copy(t)
BSTree(const BSTree<K>& tree)
{
_root = Copy(tree._root);
}
//t1=t2
BSTree<K>& operator=(const BSTree<K>& tree)
{
if (this != &tree)
{
//首先销毁t1,再赋值
_Destory(this->_root);
this->_root = Copy(tree._root);
}
return *this;
}
~BSTree()
{
_Destroy(_root);
_root = nullptr;
}
//插入元素
bool Insert(const K& key)
{
//如果树为空,直接插入
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
Node* cur = _root;
Node* parents = nullptr;
//找插入新节点的位置
while (cur)
{
parents = cur;
if (key > cur->_key)
{
cur = cur->_right;
}
else if (key < cur->_key)
{
cur = cur->_left;
}
else
{
//set有重复的不插入
return false;
}
}
cur = new Node(key);
//插入节点
if (key > parents->_key)
{
parents->_right = cur;
}
else
parents->_left = cur;
return true;
}
//查找值为data的节点
bool Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_key == key)
{
return true;
}
else if (key < cur->_key)
{
cur = cur->_left;
}
else if (key > cur->_key)
{
cur = cur->_right;
}
}
return false;
}
bool Erase(const K& key)
{
if (_root == nullptr)
return false;
Node* cur = _root;
Node* parents = nullptr;
if (Find(key))
{
//找data在树中的位置
while (cur)
{
if (key == cur->_key)
{
break;
}
else if (key > cur->_key)
{
parents = cur;
cur = cur->_right;
}
else if (key < cur->_key)
{
parents = cur;
cur = cur->_left;
}
}
Node* del = cur;
//cur的左树为空
if (cur->_left == nullptr)
{
//key是根节点
if (parents == nullptr)
{
_root = cur->_right;
}
else
{
//删除cur,再把parents和cur的子树链起来
if (parents->_left == cur)
{
parents->_left = cur->_right;
}
else
parents->_right = cur->_right;
}
}
//cur的右树为空
else if (cur->_right == nullptr)
{
//data是根节点
if (parents == nullptr)
{
_root = cur->_left;
}
else
{
if (parents->_left == cur)
{
parents->_left = cur->_left;
}
else
parents->_right = cur->_left;
}
}
//替代法删除:用左树的最右节点或右树的最左节点覆盖cur
//cur的左右都不为空,找左树的最右节点(该节点的右一定为空)和右树的最左节点(该节点的左一定为空)
else
{
//1、找cur的替代节点,假定替代节点replace指向cur的右
Node* replace = cur->_right;
//p_replace作为replaced父亲节点
Node* p_replace = cur;
//2、找替代节点replace的最左节点
while (replace->_left)
{
p_replace = replace;
replace = replace->_left;
}
//3、用replace的值去覆盖cur的值
cur->_key = replace->_key;
//4、删除replace节点
if (p_replace->_left == replace)
{
p_replace->_left = replace->_right;
}
else
{
p_replace->_right = replace->_right;
}
del = replace;
}
delete del;
return true;
}
else
return false;
}
//_root节点是私有的,在类外面无法访问,所以要套一个_InOrder
void InOrder()
{
_InOrder(_root);
}
private:
void _InOrder(Node* root)
{
if (root)
{
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
}
void _Destory(Node* root)
{
//后序销毁
if (root == nullptr)
{
return;
}
_Destory(root->_left);
_Destory(root->_right);
delete root;
}
private:
Node* _root;
};
需要注意的是:
中序遍历:要套_InOrder,因为_root是私有的,无法在类外面访问
析构:递归实现后序销毁
拷贝构造:前序拷贝
赋值:要先销毁原来的树,再进行递归赋值
测试代码:
void test()
{
/*BSTree<int> BT;
BT.Insert(5);
BT.Insert(3);
BT.Insert(7);
BT.Insert(1);
BT.Insert(4);
BT.Insert(6);
BT.Insert(8);
BT.InOrder();
cout << endl;*/
/*cout <<"查找:"<< BT.Find(3) << endl;
cout << endl;
cout << "删除:" << BT.Erase(7) << endl;*/
BSTree<int> t;
int a[] = { 5, 3, 7, 1, 4, 6, 8, 9, 0, 2 };
for (auto e : a)
{
t.Insert(e);
}
t.InOrder();
cout << endl;
BSTree<int> copy(t);
copy.InOrder();
cout << endl;
t = copy;
t.InOrder();
/*t.Erase(5);
t.Erase(1);
t.Erase(8);
t.InOrder();
t.~BSTree();*/
}
int main()
{
test();
system("pause");
return 0;
}