C++ | 二叉搜索树

🦌云深麋鹿
专栏C++ | 用C语言学数据结构 | Java

回顾:上一篇我们结束了 多态,接下来这篇文章让我们进入到 二叉搜索树 的学习,体会新的设计思路吧~

放个目录

  • [一 概念](#一 概念)
  • [二 性能分析](#二 性能分析)
    • [2.1 二叉搜索树性能分析](#2.1 二叉搜索树性能分析)
    • [2.2 二分查找](#2.2 二分查找)
  • [三 二叉搜索树的插入](#三 二叉搜索树的插入)
    • [3.1 上代码](#3.1 上代码)
    • [3.2 测试](#3.2 测试)
  • [四 二叉搜索树的查找](#四 二叉搜索树的查找)
    • [4.1 上代码](#4.1 上代码)
    • [4.2 测试](#4.2 测试)
  • [五 二叉搜索树的删除](#五 二叉搜索树的删除)
    • [5.1 四种情况](#5.1 四种情况)
    • [5.2 上代码](#5.2 上代码)
    • [5.3 测试](#5.3 测试)
  • [六 二叉搜索树的其他实现](#六 二叉搜索树的其他实现)
    • [6.1 析构函数](#6.1 析构函数)
      • [6.1.1 _destory](#6.1.1 _destory)
      • [6.1.2 析构函数](#6.1.2 析构函数)
      • [6.1.3 测试](#6.1.3 测试)
    • [6.2 拷贝构造](#6.2 拷贝构造)
    • [6.3 赋值重载](#6.3 赋值重载)
      • [6.3.1 代码](#6.3.1 代码)
      • [6.3.2 测试](#6.3.2 测试)
  • [七 二叉搜索树key和key/value使用场景](#七 二叉搜索树key和key/value使用场景)
    • [7.1 key搜索场景](#7.1 key搜索场景)
    • [7.2 key/value搜索场景](#7.2 key/value搜索场景)

一 概念

二叉搜索树⼜称⼆叉排序树。

性质

  1. 若它的左子树不为空,则左子树上所有结点的值都小于等于根结点的值。
  2. 若它的右子树不为空,则右子树上所有结点的值都大于等于根结点的值。
  3. 它的左右子树也分别为⼆叉搜索树。
  4. ⼆叉搜索树中可以⽀持插入相等的值,也可以不⽀持插入相等的值,后续会提到具体实现。

二 性能分析

2.1 二叉搜索树性能分析

  1. 最优情况下,⼆叉搜索树为完全⼆叉树,其高度(即时间复杂度)为: logN。
  2. 最坏情况下,二叉搜索树为单枝,其高度(即时间复杂度)为: N。
  3. 总结:⼆叉搜索树增删查改时间复杂度为 O(N)

2.2 二分查找

二分查找时间复杂度为logN,但是有两⼤缺陷:

  1. 需要存储在⽀持下标随机访问的结构中,并且有序。
  2. 插入和删除数据效率很低(因为存储在下标随机访问的结构中,插入和删除数据⼀般需要挪动数据)。

三 二叉搜索树的插入

  1. 树为空。
  2. 树不为空,按⼆叉搜索树性质,插入值比当前结点大往右走,插入值比当前结点小往左走。
  3. 如果支持插入相等的值,插入值跟当前结点相等的值可以往右走,也可以往左走。

3.1 上代码

cpp 复制代码
bool insert(const K& key) {
    if (!_root) {
        _root = new Node(key);
        return true;
    }
	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 {
			return false;
		}
    }
	cur = new Node(key);
    if (parent -> _key > key) {
        parent->_left = cur;
    }else{
        parent->_right = cur;
    }
    return true;
}

当前不支持插入已出现过的值。

3.2 测试

cpp 复制代码
wyzy::BSTree<int> tree;
int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
for (auto e:a) {
    tree.insert(e);
}
tree.inOrder();

运行:

四 二叉搜索树的查找

4.1 上代码

cpp 复制代码
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;
}

跟插入类似的逻辑,只不过这里找到相等的就可以结束了。

4.2 测试

插入代码同上。

cpp 复制代码
while (cin >> x) {
    if (tree.find(x)) {
        cout << "find it" << endl;
    }
    else {
        cout << "not find it" << endl;
    }
}

运行:

测试涉及operator bool把iostream对象转换成bool值。

五 二叉搜索树的删除

5.1 四种情况

  1. 要删除结点N左右孩子均为空。
  2. 要删除的结点N左孩子为空,右孩子结点不为空。
  3. 要删除的结点N右孩子为空,左孩子结点不为空。
  4. 要删除的结点N左右孩子结点均不为空。
    对应删除逻辑:
  5. 直接删除。
  6. 把右孩子交给父结点。
  7. 把左孩子交给父结点。
  8. 找 左子树的最大结点/右子树的最小结点 替代被删位置。

5.2 上代码

cpp 复制代码
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 {
			break;
		}
    }
    if (cur) {
		if (!cur -> _left) {
			if (!parent) {
				_root = cur->_right;
			}else if (cur == parent->_left) {
				parent->_left = cur->_right;
			}else{
				parent->_right = cur->_right;
			}
			delete cur;
		}
		else if (!cur->_right) {
			if (!parent) {
				_root = cur->_left;
			}else if (cur == parent->_left) {
				parent->_left = cur->_left;
			}
			else {
				parent->_right = cur->_left;
			}
			delete cur;
		}
		else {
            Node* mR_parent = cur;
			Node* minRight = cur->_right;
			while (minRight-> _left) {
				mR_parent = minRight;
				minRight = minRight->_left;
			}
			swap(cur->_key, minRight->_key);
			if (mR_parent == cur) {
				mR_parent->_right = minRight->_right;
			}
			else {
				mR_parent->_left = minRight->_right;
			}
			delete minRight;
		}
		return true;
    }
    return false;
}

5.3 测试

插入代码依旧。

cpp 复制代码
for (auto e : a) {
    tree.erase(e);
    tree.inOrder();
}

运行:

六 二叉搜索树的其他实现

6.1 析构函数

6.1.1 _destory

需要有个递归函数我们另外写一个_destory:

cpp 复制代码
void _destory(Node* root) {
    if(!root){
        return;
    }
    _destory(root->_left);
    _destory(root->_right);
    delete root;
}

6.1.2 析构函数

析构里调用_destory:

cpp 复制代码
~BSTree() {
    _destory(_root);
    _root = nullptr;
}

6.1.3 测试

依旧上面那棵树:

cpp 复制代码
wyzy::BSTree<int> tree;
int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
for (auto e:a) {
    tree.insert(e);
}

调试:

画出来这样:

调试:

6.2 拷贝构造

6.2.1 默认构造

这里需要显式定义默认构造。

走初始化列表:

cpp 复制代码
BSTree(){}

或者强制默认生成:

cpp 复制代码
BSTree() = default;

6.2.2 上代码

(1)辅助函数_constructor
cpp 复制代码
void _constructor(Node* root) {
    if(!root){
        return;
    }
    insert(root->_key);
    _constructor(root->_right);
    _constructor(root->_left);
}

老生常谈的递归了。

(2)_constructor
cpp 复制代码
BSTree(const BSTree& tree) {
    _constructor(tree._root);
}

6.2.3 测试

cpp 复制代码
wyzy::BSTree<int> tree1;
int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
for (auto e : a) {
	tree1.insert(e);
}
wyzy::BSTree<int> tree2(tree1);
tree1.inOrder();
tree2.inOrder();

调试:

运行:

6.3 赋值重载

6.3.1 代码

复用。

cpp 复制代码
BSTree& operator=(const BSTree& tree) { 
    if (tree._root != nullptr) {
        _destory(_root);
        _root = nullptr;
    }
    _constructor(tree._root);
    return *this;
}

6.3.2 测试

cpp 复制代码
wyzy::BSTree<int> tree1;
wyzy::BSTree<int> tree2;
int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };
for (auto e : a) {
	tree1.insert(e);
}
tree2 = tree1;
tree1.inOrder();
tree2.inOrder();

调试:

运行:

七 二叉搜索树key和key/value使用场景

7.1 key搜索场景

  • 识别车牌号。

7.2 key/value搜索场景

  • 简单中英字典。
  • 商场停车场。
  • 统计文章单词出现次数。

二叉搜索树 的学习就到这里,下一篇我们上新的容器 map&set ,很快会更出来~


相关推荐
永远睡不够的入2 小时前
C++11新特性详解(上):从列表初始化到右值引用
开发语言·c++
枫叶丹42 小时前
【HarmonyOS 6.0】AVCodec Kit:OH_AVDataSource回调中传递用户自定义数据的深度解析
开发语言·华为·harmonyos
c++圈来了个新人2 小时前
C++类和对象(中)
c语言·开发语言·数据结构·c++·考研·算法
格林威2 小时前
面阵相机 vs 线阵相机:堡盟与海康相机选型差异全解析+python实战演示
开发语言·人工智能·python·数码相机·计算机视觉·视觉检测·工业相机
思麟呀2 小时前
5种IO模型
linux·运维·服务器·c++
Go away, devil2 小时前
Java——IO
java·开发语言
oscar9992 小时前
OpenCode Go :为开放编码模型准备的低价订阅方案
开发语言·后端·golang
王老师青少年编程2 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【删数问题】:删数问题2
c++·算法·贪心·csp·信奥赛
.千余2 小时前
【Linux】开发工具2:vim
linux·服务器·开发语言·学习