目录
概念
二叉搜索树又称二叉排序树,二叉查找树,它或者是一棵空树
,或者是具有以下性质的二叉树
:
若它的左子树不为空,则左子树上所有节点的值都小于根节点的值若它的右子树不为空,则右子树上所有节点的值都大于根节点的值它的左右子树也分别为二叉搜索树
下面就是一个二叉搜索树:
节点定义
template<class K>
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
BSTreeNode(const K& key)
:_left(nullptr)
,_right(nullptr)
,_key(key)
{}
};
二叉搜索树实现细节
框架
template<class K>
class BSTree
{
typedef BSTreeNode<K> Node;
public:
BSTree()
{}
private:
Node* _root = nullptr;
};
查找
查找分三种情况:要查找的值正好是当前节点的值;要查找的值小于当前节点的值,去左子树查找;要查找的值大于当前节点的值,去右子树查找。
循环控制版
bool Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
cur = cur->_right;
else if (cur->_key > key)
cur = cur->_left;
else
return true;
}
return false;
}
递归版
bool FindR(const K& key)
{
return _FindR(_root, key);
}
bool _FindR(Node* root, const K& key)
{
if (root == nullptr)
return false;
if (root->_key < key)
return _FindR(root->_right, key);
else if (root->_key > key)
return _FindR(root->_left, key);
else
return true;
}
插入
插入思路和查询一样,要插入的值小于当前节点的值,去左子树插入,直到找到空位置为止;要插入的值大于当前节点的值,去右子树插入,直到找到空位置为止。
循环控制版
bool Insert(const K& key)
{
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
parent = cur;
if (cur->_key < key)
cur = cur->_right;
else if (cur->_key > key)
cur = cur->_left;
else
return false;
}
cur = new Node(key);
if (parent->_key < key)
parent->_right = cur;
else
parent->_left = cur;
return true;
}
递归版
bool InsertR(const K& key)
{
return _InsertR(_root, key);
}
bool _InsertR(Node*& root, const K& key)
{
if (root == nullptr)
{
root = new Node(key);
return true;
}
if (root->_key < key)
return _InsertR(root->_right, key);
else if (root->_key > key)
return _InsertR(root->_left, key);
else
return false;
}
删除
删除的话,就比上边两种难了。删除分四种情况:要删除的节点无孩子节点;要删除的节点只有左孩子;要删除的节点只有右孩子;要删除的节点既有左孩子又有右孩子。
当然,第一种情况可以归类为第二种情况或第三种情况。那么接下来只分三种情况来讨论:
左为空
只需要将要删除的节点的右子树根节点连接到要删除节点的父节点即可。
右为空
只需要将要删除的节点的左子树根节点连接到要删除节点的父节点即可。
左右都不为空
当要删除的节点左右子树都不为空时,该怎么进行调整来保证删除节点后的树还是二叉搜索树呢?
我们知道,如果要删除的节点是叶子节点时,只需要将它删除,并将其父节点对应方向置空即可。
下面我们将采用这种思想,使用替换法来进行删除。
思路如下:
【法1】找到要删除的节点左子树最大值的节点,然后交换二者的值,再进行对交换后的叶子结点进行删除即可。
【法2】找到要删除的节点右子树最小值的节点,然后交换二者的值,再进行对交换后的叶子结点进行删除即可。
以法2为例
循环控制版
bool Erase(const K& key)
{
Node* cur = _root;
Node* parent = nullptr;
while (cur)
{
if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
// cur->_key == key,开始删除
else
{ //1、左为空
//2、右为空
//3、左右都不为空
if (cur->_left == nullptr)
{
if (cur == _root)
{
_root == cur->_right;
}
else
{
if (cur == parent->_left)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
delete cur;
cur == nullptr;
}
else if (cur->_right == nullptr)
{
if (cur == _root)
{
_root == cur->_left;
}
else
{
if (cur == parent->_left)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
}
delete cur;
cur == nullptr;
}
else
{
//替换法删除
Node* minparent = cur;
Node* min = cur->_right;
while (min->_left)
{
minparent = min;
min = min->_left;
}
swap(cur->_key, min->_key);
if (min == minparent->_left)
minparent->_left = min->_right;
else
minparent->_right = min->_right;
delete min;
}
}
}
return false;
}
递归版
bool _EraseR(Node*& root, const K& key)
{
if (root == nullptr)
return false;
if (root->_key < key)
return _EraseR(root->_right, key);
else if (root->_key > key)
return _EraseR(root->_left, key);
else
{
Node* del = root;
if (root->_left == nullptr)
root = root->_right;
else if (root->_right == nullptr)
root = root->_left;
else
{
Node* min = root->_right;
while (min->_left)
{
min = min->_left;
}
swap(root->_key, min->_key);
return _EraseR(root->_right, key);
}
delete del;
return true;
}
}
bool EraseR(const K& key)
{
return _EraseR(_root, key);
}
析构函数
void _Destory(Node*& root)
{
if (root == nullptr)
return;
_Destory(root->_left);
_Destory(root->_right);
delete root;
root = nullptr;
}
~BSTree()
{
_Destory(_root);
}
拷贝构造函数
Node* _Copy(Node* root)
{
if (root == nullptr)
return nullptr;
Node* copyroot = new Node(root->_key);
copyroot->_left = _Copy(root->_left);
copyroot->_right = _Copy(root->_right);
return copyroot;
}
BSTree(const BSTree<K>& t)
{
_root = _Copy(t._root);
}
赋值
BSTree<K>& operator=(BSTree<K> t)
{
swap(_root, t._root);
return *this;
}
完整代码实现
#pragma once
#include<iostream>
using namespace std;
template<class K>
struct BSTreeNode
{
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
BSTreeNode(const K& key)
:_left(nullptr)
, _right(nullptr)
, _key(key)
{}
};
template<class K>
class BSTree
{
typedef BSTreeNode<K> Node;
public:
BSTree()
{}
//拷贝构造函数
BSTree(const BSTree<K>& t)
{
_root = _Copy(t._root);
}
BSTree<K>& operator=(BSTree<K> t)
{
swap(_root, t._root);
return *this;
}
bool Insert(const K& key)
{
if (_root == nullptr)
{
_root = new Node(key);
return true;
}
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
parent = cur;
if (cur->_key < key)
cur = cur->_right;
else if (cur->_key > key)
cur = cur->_left;
else
return false;
}
cur = new Node(key);
if (parent->_key < key)
parent->_right = cur;
else
parent->_left = cur;
return true;
}
bool Find(const K& key)
{
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
cur = cur->_right;
else if (cur->_key > key)
cur = cur->_left;
else
return true;
}
return false;
}
bool Erase(const K& key)
{
Node* parent = nullptr;
Node* cur = _root;
while (cur)
{
if (cur->_key < key)
{
parent = cur;
cur = cur->_right;
}
else if (cur->_key > key)
{
parent = cur;
cur = cur->_left;
}
else
{
// 准备删除 20:15继续
if (cur->_left == nullptr)
{//左为空
if (cur == _root)
{
_root = cur->_right;
}
else
{
if (cur == parent->_left)
{
parent->_left = cur->_right;
}
else
{
parent->_right = cur->_right;
}
}
delete cur;
}
else if (cur->_right == nullptr)
{//右为空
if (cur == _root)
{
_root = cur->_left;
}
else
{
if (cur == parent->_left)
{
parent->_left = cur->_left;
}
else
{
parent->_right = cur->_left;
}
}
delete cur;
}
else
{//左右都不为空
// 右树的最小节点(最左节点)
Node* parent = cur;
Node* subLeft = cur->_right;
while (subLeft->_left)
{
parent = subLeft;
subLeft = subLeft->_left;
}
swap(cur->_key, subLeft->_key);
if (subLeft == parent->_left)
parent->_left = subLeft->_right;
else
parent->_right = subLeft->_right;
delete subLeft;
}
return true;
}
}
return false;
}
Node* _Copy(Node* root)
{
if (root == nullptr)
return nullptr;
Node* copyroot = new Node(root->_key);
copyroot->_left = _Copy(root->_left);
copyroot->_right = _Copy(root->_right);
return copyroot;
}
void _Destory(Node*& root)
{
if (root == nullptr)
return;
_Destory(root->_left);
_Destory(root->_right);
delete root;
root = nullptr;
}
void InOrder()
{
_InOrder(_root);
cout << endl;
}
bool FindR(const K& key)
{
return _FindR(_root, key);
}
bool InsertR(const K& key)
{
return _InsertR(_root, key);
}
bool EraseR(const K& key)
{
return _EraseR(_root, key);
}
~BSTree()
{
_Destory(_root);
}
private:
bool _EraseR(Node*& root, const K& key)
{
if (root == nullptr)
return false;
if (root->_key < key)
{
return _EraseR(root->_right, key);
}
else if (root->_key > key)
{
return _EraseR(root->_left, key);
}
else
{
// 删除
if (root->_left == nullptr)
{
Node* del = root;
root = root->_right;
delete del;
return true;
}
else if (root->_right == nullptr)
{
Node* del = root;
root = root->_left;
delete del;
return true;
}
else
{
Node* subLeft = root->_right;
while (subLeft->_left)
{
subLeft = subLeft->_left;
}
swap(root->_key, subLeft->_key);
// 转换成在子树去递归删除
return _EraseR(root->_right, key);
}
}
}
bool _InsertR(Node*& root, const K& key)
{
if (root == nullptr)
{
root = new Node(key);
return true;
}
if (root->_key < key)
return _InsertR(root->_right, key);
else if (root->_key > key)
return _InsertR(root->_left, key);
else
return false;
}
bool _FindR(Node* root, const K& key)
{
if (root == nullptr)
return false;
if (root->_key < key)
return _FindR(root->_right, key);
else if (root->_key > key)
return _FindR(root->_left, key);
else
return true;
}
void _InOrder(Node* root)
{
if (root == nullptr)
return;
_InOrder(root->_left);
cout << root->_key << " ";
_InOrder(root->_right);
}
private:
Node* _root = nullptr;
};