文章目录
搜索二叉树的实现
框架和insert函数
我们很容易写出下面的框架和insert函数
struct BSTreeNode
{
BSTreeNode(const K& val)
{
_val = val;
_left = nullptr;
_right = nullptr;
}
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _val;
};
template <class K>
class BSTree
{
typedef BSTreeNode<K> Node;
public:
bool insert(const K& val)
{
// a. 树为空,则直接新增节点,赋值给root指针
if (_root == nullptr) {
_root = new BSTreeNode(val);
return true;
}
// b. 树不空,按二叉搜索树性质查找插入位置,插入新节点
Node* cur = _root, *prev=nullptr;
while (cur) {
if (val < cur->_val) {
prev = cur;
cur = cur->_left;
}
else if (val > cur->_val) {
prev = cur;
cur = cur->_right;
}
else {
// val的值和树中某个节点的值相同,返回false
return false;
}
}
// 找到了一个合适的位置,此时需要链接,注意链接位置
cur = new Node(val);
if (val < prev->_val) {
prev->_left = cur;
return true;
}
else {
prev->_right = cur;
return true;
}
}
private:
Node _root = nullptr;
};
中序遍历
我们知道,搜索二叉树的中序遍历是一个有序表,现在我们想要像这样调用
int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
BSTree<int> tree;
for (auto& e : a)
tree.insert(e);
tree.InOrder();
但是InOrder()需要一个参数root,现在有三种解决办法,a.将_root改为public,b.写一个GetRoot(),c.如下
protected:
void _InOrder(Node* root)
{
if (root == nullptr) return;
_InOrder(root->_left);
cout << root->_val << ' ';
_InOrder(root->_right);
}
public:
void InOrder()
{
_InOrder(_root);
}
有人可能会这样写void _InOrder(Node* root) = _root
, 这样是错误的,因为函数的默认参数只能是全局变量或者常量
find(const K& val)
bool find(const K& val)
{
Node* cur = _root;
while (cur) {
if (val < cur->_val)
cur = cur->_left;
else if (val > cur->_val)
cur = cur->_right;
else
return true;
}
return false;
}
erase()函数
其中第②种情况包含第①中情况
bool erase(const K& key)
{
Node* cur = _root, * prev = nullptr;
while (cur) {
if (key < cur->_key) {
prev = cur;
cur = cur->_left;
}
else if (key > cur->_key) {
prev = cur;
cur = cur->_right;
}
else {
// 1.左为空,prev指向cur的_right,但是prev的_left还是_right需要判断
if (cur->_left == nullptr) {
if (prev->_left == cur) prev->_left = cur->_right;
else prev->_right = cur->_right;
delete cur;
}
// 2.右为空
else if (cur->_right == nullptr) {
if (prev->_left == cur) prev->_left = cur->_left;
else prev->_right = cur->_left;
delete cur;
}
// 其他情况,需要"找保姆"
else {
// 找右树的最小节点
Node* minRight = cur->_right, * prevMinRight = cur;
while (minRight->_left) {
prevMinRight = minRight;
minRight = minRight->_left;
}
cur->_key = minRight->_key;
/*if (prevMinRight == cur) prevMinRight->_right = minRight->_right;
else prevMinRight->_left = minRight->_right;*/
// 这里也需要判断,因为不能保证prevMinRight是否是cur
if (prevMinRight->_right == minRight) prevMinRight->_right = minRight->_right;
else prevMinRight->_left = minRight->_right;
delete minRight;
}
return true;
}
}
return false;
}
看似上面的代码没有问题,但面对下面的测试用例时,就会有问题
// 测试erase
void test2()
{
int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
BSTree<int> tree;
for (auto& e : a)
tree.insert(e);
tree.erase(10);
tree.erase(14);
tree.erase(13);
tree.erase(8);
tree.InOrder();
}
此时有两种解决办法,一是更新_root,更新为节点3,二是找左子树的最大值来作为cur的prev
左树为空时同理
此时erase变为
bool erase(const K& key)
{
Node* cur = _root, * prev = nullptr;
while (cur) {
if (key < cur->_key) {
prev = cur;
cur = cur->_left;
}
else if (key > cur->_key) {
prev = cur;
cur = cur->_right;
}
else {
// 1.左为空,prev指向cur的_right,但是prev的_left还是_right需要判断
if (cur->_left == nullptr) {
if (cur == _root) _root = cur->_right;
else {
if (prev->_left == cur) prev->_left = cur->_right;
else prev->_right = cur->_right;
delete cur;
}
}
// 2.右为空
else if (cur->_right == nullptr) {
if (cur == _root) _root = cur->_left;
else {
if (prev->_left == cur) prev->_left = cur->_left;
else prev->_right = cur->_left;
delete cur;
}
}
// 其他情况,需要"找保姆"
else {
// 找右树的最小节点
Node* minRight = cur->_right, * prevMinRight = cur;
while (minRight->_left) {
prevMinRight = minRight;
minRight = minRight->_left;
}
cur->_key = minRight->_key;
/*if (prevMinRight == cur) prevMinRight->_right = minRight->_right;
else prevMinRight->_left = minRight->_right;*/
// 这里也需要判断,因为不能保证prevMinRight是否是cur
if (prevMinRight->_right == minRight) prevMinRight->_right = minRight->_right;
else prevMinRight->_left = minRight->_right;
delete minRight;
}
return true;
}
}
return false;
}
搜索二叉树的递归实现
findR()函数
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) _findR(root->_right, key);
else if (root->_key > key) _findR(root->_left, key);
else return true;
}
insertR()函数
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;
}
关于参数为什么是Node*& root
,可以看下面的递归展开图
eraseR()函数
bool eraseR(const K& key)
{
return _eraseR(_root, key);
}
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* maxLeft = root->_left;
while (maxLeft->_right != nullptr) maxLeft = maxLeft->_right;
swap(root->_key, maxLeft->_key);
// 转换成子问题去删除
return _eraseR(root->_left, key);
}
delete del;
return true;
}
}
注意第16行return _eraseR(root->_left, key);
不能改成return _eraseR(maxLeft, key);
,因为我们要想让Node*& root
这个引用起作用,就需要一层一层的往下递归传递
其他函数
析构函数
~BSTree()
{
Destroy(_root);
_root = nullptr;
}
void Destroy(Node* root)
{
if (root == nullptr) return;
Destroy(root->_left);
Destroy(root->_right);
delete root;
}
拷贝构造函数
BSTree(const BSTree<K>& t)
{
_root = Copy(t._root);
}
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;
}
赋值函数重载
BSTree<K>& operator=(BSTree<K> t)
{
swap(t._root, _root);
return *this;
}
全部代码
#pragma once
#include <iostream>
using namespace std;
template <class K>
struct BSTreeNode
{
BSTreeNode(const K& key)
{
_key = key;
_left = nullptr;
_right = nullptr;
}
BSTreeNode<K>* _left;
BSTreeNode<K>* _right;
K _key;
};
template <class K>
class BSTree
{
typedef BSTreeNode<K> Node;
public:
~BSTree()
{
Destroy(_root);
_root = nullptr;
}
// BSTree() : _root(nullptr) {}
// 等价于上面的无参构造函数
BSTree() = default;
BSTree(const BSTree<K>& t)
{
_root = Copy(t._root);
}
BSTree<K>& operator=(BSTree<K> t)
{
swap(t._root, _root);
return *this;
}
bool insert(const K& key)
{
// a. 树为空,则直接新增节点,赋值给root指针
if (_root == nullptr) {
_root = new Node(key);
return true;
}
// b. 树不空,按二叉搜索树性质查找插入位置,插入新节点
Node* cur = _root, * prev = nullptr;
while (cur) {
if (key < cur->_key) {
prev = cur;
cur = cur->_left;
}
else if (key > cur->_key) {
prev = cur;
cur = cur->_right;
}
else {
// key的值和树中某个节点的值相同,返回false
return false;
}
}
// 找到了一个合适的位置,此时需要链接,注意链接位置
cur = new Node(key);
if (key < prev->_key) {
prev->_left = cur;
return true;
}
else {
prev->_right = cur;
return true;
}
}
bool insertR(const K& key)
{
return _insertR(_root, key);
}
bool find(const K& key)
{
Node* cur = _root;
while (cur) {
if (key < cur->_key)
cur = cur->_left;
else if (key > cur->_key)
cur = cur->_right;
else
return true;
}
return false;
}
bool findR(const K& key)
{
return _findR(_root, key);
}
bool erase(const K& key)
{
Node* cur = _root, * prev = nullptr;
while (cur) {
if (key < cur->_key) {
prev = cur;
cur = cur->_left;
}
else if (key > cur->_key) {
prev = cur;
cur = cur->_right;
}
else {
// 1.左为空,prev指向cur的_right,但是prev的_left还是_right需要判断
if (cur->_left == nullptr) {
if (cur == _root) _root = cur->_right;
else {
if (prev->_left == cur) prev->_left = cur->_right;
else prev->_right = cur->_right;
delete cur;
}
}
// 2.右为空
else if (cur->_right == nullptr) {
if (cur == _root) _root = cur->_left;
else {
if (prev->_left == cur) prev->_left = cur->_left;
else prev->_right = cur->_left;
delete cur;
}
}
// 其他情况,需要"找保姆"
else {
// 找右树的最小节点
Node* minRight = cur->_right, * prevMinRight = cur;
while (minRight->_left) {
prevMinRight = minRight;
minRight = minRight->_left;
}
cur->_key = minRight->_key;
/*if (prevMinRight == cur) prevMinRight->_right = minRight->_right;
else prevMinRight->_left = minRight->_right;*/
// 这里也需要判断,因为不能保证prevMinRight是否是cur
if (prevMinRight->_right == minRight) prevMinRight->_right = minRight->_right;
else prevMinRight->_left = minRight->_right;
delete minRight;
}
return true;
}
}
return false;
}
bool eraseR(const K& key)
{
return _eraseR(_root, key);
}
void InOrder()
{
_InOrder(_root);
}
protected:
void _InOrder(Node* root)
{
if (root == nullptr) return;
_InOrder(root->_left);
cout << root->_key << ' ';
_InOrder(root->_right);
}
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) _findR(root->_right, key);
else if (root->_key > key) _findR(root->_left, key);
else return true;
}
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* maxLeft = root->_left;
while (maxLeft->_right != nullptr) maxLeft = maxLeft->_right;
swap(root->_key, maxLeft->_key);
// 转换成子问题去删除
return _eraseR(root->_left, key);
}
delete del;
return true;
}
}
void Destroy(Node* root)
{
if (root == nullptr) return;
Destroy(root->_left);
Destroy(root->_right);
delete root;
}
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;
}
private:
Node* _root = nullptr;
};