二叉搜索树/二叉排序树(代码实现)(c++)

BSTree

  • 二叉排序树概念
    • 代码部分
  • BSTree框架
    • 查找操作
    • 插入操作
    • 删除操作**
    • 默认成员函数
    • 完整代码
  • BSTree性能分析

二叉排序树概念

二叉搜索树又称二叉排序树(BSTree, Binary Search Tree),它或者是一颗空树,或者是具有以下性质的二叉树:

  • 若它的左子树不为空,则左子树上所有结点的值都小于根结点的值
  • 若它的右子树不为空,则右子树上所有结点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

在这里插入图片描述

代码部分

BSTree框架

//创建二叉树结点
template<class K>
struct BSTNode
{struct BSTNode<K>* _left;struct BSTNode<K>* _right;K _key;//构造函数BSTNode(const K& key):_key(key),_left(nullptr),_right(nullptr){}
};template<class K>
class BSTree
{typedef BSTNode<K> Node;//.....private:Node* _root = nullptr;
};

查找操作

a、从根开始比较,查找,比根大往右走查找,比根小往左走。
b、最多查找高度次,走到空,还没找到,这个值就不存在。

非递归:

	//查找bool Find(const K& key){Node* cur = _root;while (cur){if (cur->_key > key) cur = cur->_left;else if (cur->_key < key) cur = cur->_right;else return true;}return false;}

递归:利用树的特性。

//暴露接口的函数bool EFind(const K& key){return _EFind(_root, key);}bool _EFind(Node* root, const K& key){if (root == nullptr)return false;if (root->_key > key)  {return _EFind(root->_left, key);}else if (root->_key < key){return _EFind(root->_right, key);}else{return true;}}

插入操作

a. 树为空,直接新增新节点,赋值给root指针
b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

非递归:

	//插入bool Insert(const K& key){//空if (nullptr == _root){_root = new Node(key);return true;}//不空Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{return false;}}//找到插入位置if (parent->_key > key){//左边插入parent->_left = new Node(key);}else{//右边插入parent->_right = new Node(key);}return true;}

递归版本:利用指针的引用!!

	bool EInsert(const K& key){return _EInsert(_root, key);}//指针的引用!!!bool _EInsert(Node*& root, const K& key){if (root == nullptr){root = new Node(key);return true;}if (root->_key > key)return _EInsert(root->_left, key);else if (root->_key < key)return _EInsert(root->_right, key);else  //相等{return false;}}

删除操作**

首先查找元素是否在二叉搜索树中,若不存在,则返回,否则要删除的结点可能分下面四种情况:
a. 要删除的结点无孩子结点
b.要删除的结点只有左孩子
c.要删除的结点只有右孩子
d.要删除的结点有左、右孩子结点
表面上有四种,但是实际上情况a可以与b、c情况合并,因此真正删除的情况如下:

  • 情况b:删除该节点且使被删除结点的双亲结点指向被删除结点的左孩子结点
    在这里插入图片描述

  • 情况c:删除该结点,并且使被删除结点的双亲结点指向被删除结点的右孩子结点。
    在这里插入图片描述

  • 情况d:找到被删除结点中序遍历的前一个(或者后一个)结点,将他们俩的值交换,交换后的那个结点。就变成了b\c两种情况。

在这里插入图片描述

非递归版本:

	//删除bool Erase(const K& key){Node* parent = nullptr;Node* cur = _root;//先找要删除的结点while (cur){if (cur->_key > key){parent = cur;cur = cur->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else//找到了{//左右孩子都没有,就是叶子,其实可以和b、c两种情况合并if (cur->_left == nullptr && cur->_right == nullptr){if (cur == _root){_root = nullptr;}else if (parent->_left == cur){parent->_left = nullptr;}else if (parent->_right == cur){parent->_right = nullptr;}delete cur;}else  //不是叶子{//只有左为空if (cur->_left == nullptr){if (parent == nullptr)   //防止最开始找到parent为空{_root = cur->_right;}else{if (parent->_left == cur){parent->_left = cur->_right;}else if (parent->_right == cur){parent->_right = cur->_right;}}delete cur;}//只有右为空else if (cur->_right == nullptr){if (parent == nullptr)  //防止最开始找到parent为空{_root = cur->_left;}else{if (parent->_left == cur){parent->_left = cur->_left;}else if (parent->_right == cur){parent->_right = cur->_left;}}delete cur;}//左右都不为空, 找右子树的最左结点代替else{parent = cur;Node* p = cur->_right;while (p->_left)  //找紧挨着的结点作替换{parent = p;p = p->_left;}cur->_key = p->_key;if (parent->_left == p)parent->_left = p->_right;else if (parent->_right == p)parent->_right = p->_right;delete p;}}return true;}}return false;}

递归版本:该思路很巧妙,注意学习

	bool EErase(const K& key){return _Erase(_root, key);}bool _Erase(Node*& root, const K& key){//先找keyif (root == nullptr){return false;}if (root->_key > key){return _Erase(root->_left, key);}else if (root->_key < key){return _Erase(root->_right, key);}else{//找到了Node* del = root;if (root->_left == nullptr){root = root->_right;}else if (root->_right == nullptr){root = root->_left;}else{// 左右都不为空,找左子树最右边的Node* minNode = root->_left;while (minNode->_right){minNode = minNode->_right;}swap(root->_key, minNode->_key);//交换完删再删除结点,精华部分return _Erase(root->_left, key);}delete del;return true;}}

默认成员函数

//构造函数//BSTree():_root(nullptr){}BSTree() = default;  //强制生成默认构造函数//拷贝构造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(_root, t._root);return *this;}//析构~BSTree(){Destory(_root);}void Destory(Node*& root){//后续递归if (root == nullptr){return;}Destory(root->_left);Destory(root->_right);delete root;root = nullptr;}

完整代码

//BSTree.h#pragma once
//创建二叉树结点
template<class K>
struct BSTNode
{struct BSTNode<K>* _left;struct BSTNode<K>* _right;K _key;//构造函数BSTNode(const K& key):_key(key),_left(nullptr),_right(nullptr){}
};template<class K>
class BSTree
{typedef BSTNode<K> Node;
public://BSTree():_root(nullptr){}BSTree() = default;  //强制生成默认构造函数//拷贝构造BSTree(const BSTree<K>& t){_root = Copy(t._root);}//赋值运算符重载BSTree<K>& operator=(BSTree<K> t){swap(_root, t._root);return *this;}~BSTree(){Destory(_root);}//插入bool Insert(const K& key){//空if (nullptr == _root){_root = new Node(key);return true;}//不空Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_key < key){parent = cur;cur = cur->_right;}else if (cur->_key > key){parent = cur;cur = cur->_left;}else{return false;}}//找到插入位置if (parent->_key > key){//左边插入parent->_left = new Node(key);}else{//右边插入parent->_right = new Node(key);}return true;}bool EInsert(const K& key){return _EInsert(_root, key);}bool EFind(const K& key){return _EFind(_root, key);}bool EErase(const K& key){return _Erase(_root, key);}//查找bool Find(const K& key){Node* cur = _root;while (cur){if (cur->_key > key) cur = cur->_left;else if (cur->_key < key) cur = cur->_right;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->_left;}else if (cur->_key < key){parent = cur;cur = cur->_right;}else//找到了{//叶子if (cur->_left == nullptr && cur->_right == nullptr){if (cur == _root){_root = nullptr;}else if (parent->_left == cur){parent->_left = nullptr;}else if (parent->_right == cur){parent->_right = nullptr;}delete cur;}else  //不是叶子{//只有左为空if (cur->_left == nullptr){if (parent == nullptr)   //防止最开始找到parent为空{_root = cur->_right;}else{if (parent->_left == cur){parent->_left = cur->_right;}else if (parent->_right == cur){parent->_right = cur->_right;}}delete cur;}//只有右为空else if (cur->_right == nullptr){if (parent == nullptr)  //防止最开始找到parent为空{_root = cur->_left;}else{if (parent->_left == cur){parent->_left = cur->_left;}else if (parent->_right == cur){parent->_right = cur->_left;}}delete cur;}//左右都不为空, 找右子树的最左结点代替else{parent = cur;Node* p = cur->_right;while (p->_left){parent = p;p = p->_left;}cur->_key = p->_key;if (parent->_left == p)parent->_left = p->_right;else if (parent->_right == p)parent->_right = p->_right;delete p;}}return true;}}return false;}void InOrder(){_InOrder(_root);}protected:void Destory(Node*& root){//后续递归if (root == nullptr){return;}Destory(root->_left);Destory(root->_right);delete root;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;}void _InOrder(const Node* root){if (root == nullptr) return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}bool _EFind(Node* root, const K& key){if (root == nullptr)return false;if (root->_key > key){return _EFind(root->_left, key);}else if (root->_key < key){return _EFind(root->_right, key);}else{return true;}}//指针的引用!!!bool _EInsert(Node*& root, const K& key){if (root == nullptr){root = new Node(key);return true;}if (root->_key > key)return _EInsert(root->_left, key);else if (root->_key < key)return _EInsert(root->_right, key);else  //相等{return false;}}bool _Erase(Node*& root, const K& key){//先找keyif (root == nullptr){return false;}if (root->_key > key){return _Erase(root->_left, key);}else if (root->_key < key){return _Erase(root->_right, key);}else{//找到了Node* del = root;if (root->_left == nullptr){root = root->_right;}else if (root->_right == nullptr){root = root->_left;}else{// 左右都不为空,找左子树最右边的Node* minNode = root->_left;while (minNode->_right){minNode = minNode->_right;}swap(root->_key, minNode->_key);//交换完删再删除结点return _Erase(root->_left, key);}delete del;return true;}}
private:Node* _root = nullptr;
};

BSTree性能分析

在这里插入图片描述
最好的情况如左图:插入删除效率都是O(logn)
最坏的情况如右图:插入删除效率是O(n),这样就失去了二叉树的优点。

因此后面会介绍AVL树和红黑树!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/325843.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DNs服务学习笔记

DNS&#xff1a;域名系统&#xff08;英文&#xff1a;Domain Name System)是一个域名系统&#xff0c;是万维网上作为域名和IP地址相互映射的一个分布式数据库&#xff0c;能够使用户更方便的访问互联网&#xff0c;而不用去记住能够被机器直接读取的IP数串。类似于生活中的11…

计算机毕业设计-----ssm+mysql实现的JavaWeb酒店管理系统

项目介绍 本项目为基于ssmmysql实现的JavaWeb酒店管理系统; 主要功能包括&#xff1a; 管理员登录,收入统计,客房管理,商品管理,客房预订,住宿登记,财务统计,旅客管理,接待对象管理等功能。 环境需要 1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上…

Efficient Classification of Very Large Images with Tiny Objects(CVPR2022补1)

文章目录 Two-stage Hierarchical Attention SamplingsummaryOne-stageTwo-Stage内存需求 Efficient Contrastive Learning with Attention Sampling Two-stage Hierarchical Attention Sampling summary 从一个大图像中按照指定的低分辨率比例和位置提取出一个小图块 一阶段…

C#编程-实现继承

C#允许您通过扩展现有类的功能以创建新类来实现继承。 从基类创建派生类 使用以下语法在C#中创建派生类: class <derived_class>:<base_class>{...}确定继承的层次结构 要确定继承层次结构,必须检查派生类与基类之间的关系种类。确保派生类是一种基类。 请考虑以…

基于Springboot的旅游管理系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的旅游管理系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

数据结构(JS实现)

目录 链表链表的特点链表中的常见操作单链表append(data)尾部追加新节点toString()输出链表的节点数据插入节点insert(position,data)get(position)获取链表指定位置节点的数据indexOf(data)查找对应数据节点的位置update(position, newData)更新指定位置节点数据removeAt(posi…

稿件代写3个不可或缺的步骤让你事半功倍-华媒舍

作为一个需求频繁的作者&#xff0c;你可能会面临大量的稿件代写任务。但是&#xff0c;你是否曾经为提高文章质量而苦恼过&#xff1f;是否希望在有限的时间内完成更多的代写任务&#xff1f;本篇文章将向你介绍三个不可或缺的稿件代写步骤&#xff0c;帮助你事半功倍&#xf…

NGUI基础-三大基础控件之Sprite精灵图片

目录 Sprite是什么 如何创建Sprite 参数相关 Atlas Sprite Material Fixed Aspect Type Simple(普通模式&#xff09; Sliced(切片模式&#xff09; Tiled(平铺模式&#xff09; Filled(填充模式&#xff09; 常见的填充模式有以下几种&#xff1a; Advanced(高级…

基于多反应堆的高并发服务器【C/C++/Reactor】(中)创建并初始化TcpServer实例 以及 启动

对于一个TcpServer来说&#xff0c;它的灵魂是什么&#xff1f;就是需要提供一个事件循环EventLop(EventLoop)&#xff0c;不停地去检测有没有客户端的连接到达&#xff0c;有没有客户端给服务器发送数据&#xff0c;描述的这些动作&#xff0c;反应堆模型能够胜任。当服务器和…

Stable Diffusion架构的3D分子生成模型 GeoLDM - 测评与代码解析

之前&#xff0c;向大家介绍过3D分子生成模型 GeoLDM。 GeoLDM按照Stable Diffusion架构&#xff0c;将3D分子生成的扩散过程运行在隐空间内&#xff0c;优化了基于扩散模型的分子生成。可能是打开Drug-AIGC的关键之作。让精确控制分子生成有了希望。 详见&#xff1a;分子生成…

抖音本地生活团购运营商家培训教程课件ppt

【干货资料持续更新&#xff0c;以防走丢】 抖音本地生活团购运营商家培训教程课件ppt 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 部分资料预览 添加图片注释&#xff0c;不超…

[SwiftUI]工程最低适配iOS13

问题&#xff1a; 新建工程&#xff0c;选择最低支持iOS13报错&#xff1a; main() is only available in iOS 14.0 or newer Scene is only available in iOS 14.0 or newer WindowGroup is only available in iOS 14.0 or newer 解决&#xff1a; 注释掉上面代码&#x…