搜索二叉树(二叉搜索树)的实现(递归与非递归)

一、搜索二叉树的概念

 搜索二叉树又称二叉排序树,二叉搜索树,它或者是一棵空树或者是具有以下性质的二叉树:

若它的左子树不为空,则左子树上所有节点的值都小于根节点的值

若它的右子树不为空,则右子树上所有节点的值都大于根节点的值

它的左右子树也分别为搜索二叉树。 

二、搜索二叉树的操作

1. 搜索二叉树的查找

a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。

b、最多查找高度次,走到到空,还没找到,这个值不存在。

template <class K>
bool BSTree<K>::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;
}

2. 搜索二叉树的插入

a. 树为空,则直接新增节点,赋值给root指针

b. 树不空,按搜索二叉树性质查找插入位置,插入新节点

template <class K>
bool BSTree<K>::Insert(const K& key)
{//树为空,则直接新增节点,赋值给root指针if (_root == nullptr){_root = new node(key);return true;}node* parent = nullptr;node* cur = _root;while (cur)//找到key该去的位置{parent = cur;if (cur->_key < key)//大就往右走{cur = cur->_right;}else if (cur->_key > key)//小就往左走{cur = cur->_left;}else//有相等的值了无法再插入了{return false;}}if (parent->_key < key){parent->_right = new node(key);}else{parent->_left = new node(key);}return true;
}

3.搜索二叉树的删除

删除的情况最为复杂,首先查找元素是否在搜索二叉树中,如果不存在,则返回, 否则要删除的结点分下面四种情况:

a. 要删除的结点无孩子结点

b. 要删除的结点只有左孩子结点

c. 要删除的结点只有右孩子结点

d. 要删除的结点有左、右孩子结点

看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程 如下:

情况a:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点--直接删除

情况b:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点--直接删除

情况c:在它的右子树中寻找中序下的第一个结点(关键码最小),或者在它的左子树中寻找中序下的第一个结点(关键码最大)用它的值填补到被删除节点中,再来处理该结点的删除问题--替换法删除。

template <class K>
bool BSTree<K>::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//找到了就跳出循环{break;}}if (cur == nullptr)//cur走到空就意味着没找到{return false;}if (cur->_left == nullptr)//左为空 {if (cur == _root){_root = cur->_right;}else if (cur == parent->_left){parent->_left = cur->_right;}else if (cur == parent->_right){parent->_right = cur->_right;}delete cur;return true;}else if (cur->_right == nullptr)//右为空{if (cur == _root){_root = cur->_left;}else if (cur == parent->_left){parent->_left = cur->_left;}else if (cur == parent->_right){parent->_right = cur->_left;}delete cur;return true;}else//左右都不为空,去找它左树最大的节点替换它的值,再删除左树最大的节点//下面的图有做说明{node* parent = nullptr;node* leftMax = cur;while (leftMax->_right)//找到左树最大的节点{parent = leftMax;leftMax = leftMax->_right;}swap(cur->_key, leftMax->_key);//交换值if (parent->_left == leftMax){parent->_left = leftMax->_left;}else{parent->_right = leftMax->_left;}delete leftMax;return true;}return false;
}

三、搜索二叉树的完整代码实现

#pragma once#include <iostream>
using namespace std;template <class K>
struct BSTreeNode
{BSTreeNode* _left;BSTreeNode* _right;K _key;BSTreeNode(const K& key):_left(nullptr),_right(nullptr),_key(key){}
};template <class K>
class BSTree
{
private:BSTreeNode<K>* _root;typedef BSTreeNode<K> node;
public:BSTree():_root(nullptr){}~BSTree(){Destroy(_root);}//增删查bool Insert(const K& key);bool Find(const K& key);bool Erase(const K& key);//中序遍历void InOrder();void _InOrder(node* root);//增删查的递归实现bool InsertR(const K& key);bool _InsertR(const K& key, node*& root);//为了对节点进行修改,这里的插入和删除的节点必须用引用传,这里是一个细节 bool EraseR(const K& key);bool _EraseR(const K& key, node*& root);bool FindR(const K& key);bool _FindR(const K& key, node* root);void Destroy(node* root);
};template <class K>
bool BSTree<K>::Insert(const K& key)
{//树为空,则直接新增节点,赋值给root指针if (_root == nullptr){_root = new node(key);return true;}node* parent = nullptr;node* cur = _root;while (cur)//找到key该去的位置{parent = cur;if (cur->_key < key)//大就往右走{cur = cur->_right;}else if (cur->_key > key)//小就往左走{cur = cur->_left;}else//有相等的值了无法再插入了{return false;}}if (parent->_key < key){parent->_right = new node(key);}else{parent->_left = new node(key);}return true;
}template <class K>
bool BSTree<K>::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;
}template <class K>
bool BSTree<K>::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//找到了就跳出循环{break;}}if (cur == nullptr)//cur走到空就意味着没找到{return false;}if (cur->_left == nullptr)//左为空 {if (cur == _root){_root = cur->_right;}else if (cur == parent->_left){parent->_left = cur->_right;}else if (cur == parent->_right){parent->_right = cur->_right;}delete cur;return true;}else if (cur->_right == nullptr)//右为空{if (cur == _root){_root = cur->_left;}else if (cur == parent->_left){parent->_left = cur->_left;}else if (cur == parent->_right){parent->_right = cur->_left;}delete cur;return true;}else//左右都不为空,去找它左树最大的节点替换它的值,再删除左树最大的节点{node* parent = nullptr;node* leftMax = cur;while (leftMax->_right)//找到左树最大的节点{parent = leftMax;leftMax = leftMax->_right;}swap(cur->_key, leftMax->_key);//交换值if (parent->_left == leftMax){parent->_left = leftMax->_left;}else{parent->_right = leftMax->_left;}delete leftMax;return true;}return false;
}template <class K>
void BSTree<K>::_InOrder(node* root)
{if (root == nullptr)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);
}template <class K>
void BSTree<K>::InOrder()
{_InOrder(_root);cout << endl;
}template <class K>
bool BSTree<K>::EraseR(const K& key)
{return _EraseR(key, _root);
}template <class K>
bool BSTree<K>::_EraseR(const K& key, node*& root)
{if (root == nullptr)return false;if (root->_key < key){_EraseR(key, root->_right);}else if (root->_key > key){_EraseR(key, root->_left);}else//找到要删除的节点了{//准备开始删除node* del = root;if (root->_left == nullptr){root = root->_right;}else if (root->_right == nullptr){root = root->_left;}else{node* leftMax = root->_left;while (leftMax->_right){leftMax = leftMax->_right;}swap(root->_key, leftMax->_key);return _EraseR(key, root->_left);//交换完后去要删除节点的左子树删除最大的节点}delete del;}return true;
}template <class K>
bool BSTree<K>::FindR(const K& key)
{return _FindR(key, _root);
}template <class K>
bool BSTree<K>::_FindR(const K& key, node* root)
{if (root == nullptr){return false;}if (root->_key < key){return _FindR(key, root->_right);}else if (root->_key > key){return _FindR(key, root->_left);}else{return true;}
}template <class K>
bool BSTree<K>::InsertR(const K& key)
{return _InsertR(key, _root);
}
template <class K>
bool BSTree<K>::_InsertR(const K& key, node*& root)
{if (root == nullptr){root = new node(key);return true;}if (root->_key < key){return _InsertR(key, root->_right);}else if (root->_key > key){return _InsertR(key, root->_left);}else{return false;}
}template <class K>
void BSTree<K>::Destroy(node* root)
{if (root == nullptr)return;Destroy(root->_left);Destroy(root->_right);delete root;
}
//test.c#include "BinarySearchTree.h"int main()
{BSTree<int> bs;int arr[] = { 1,3,6,4,7,8,10,14,13 };for (auto e : arr){bs.Insert(e);}bs.InOrder();bs.EraseR(1);bs.InOrder();bs.Insert(20);bs.InsertR(9);bs.InOrder();bool ret = bs.FindR(20);cout << ret << endl;return 0;
}

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

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

相关文章

LeetCode994.腐烂的橘子

看完题我觉得这不是和上一道岛屿的题一样简单嘛&#xff0c;然后写了将近2个小时才写出来&#xff0c;我的思路就是&#xff0c;用check()先对grid检查一下&#xff0c;是否有以下情况&#xff1a; &#xff08;如果有1的周围都是空&#xff0c;则这个位置用不腐烂&#xff0c;…

cesium雷达效果(脉冲圆)

cesium雷达效果(脉冲圆) 下面富有源码 实现思路 使用ellipse方法加载圆型,修改ellipse中‘material’方法重写glsl来实现当前效果 示例代码 index.html <!DOCTYPE html> <html lang="en"><head>

RT-Thread基于STM32H743的网络通信调试

使用STM32H743开发网络通信&#xff0c;本以为会很简单&#xff0c;实际却遇到好多问题&#xff0c;记录一下&#xff0c;以备后续查看。 1.新建工程&#xff0c;系统版本选择的是4.1.1&#xff0c;芯片型号是STM32H743IIK6. 2.修改系统时钟&#xff0c;使用外部25MHz晶振&…

复旦大学EMBA深度链接深圳科创产业:聚焦智联,产融未来

作为科创成就的经济大区&#xff0c;深圳南山区通过跨界创新研发生态链条&#xff0c;领跑科创产业创新&#xff0c;以187.5平方公里的面积&#xff0c;雄踞着204家上市公司&#xff0c;地均生产总值产出达到了40.7亿元&#xff0c;相当于每平方公里出产超过1家上市公司&#x…

从C语言的面向过程编程过渡理解面向对象编程风格中的封装

黑发不知勤学早&#xff0c;白首方悔读书迟 专栏推荐Easyx学习实践 有所收获希望大家能够三连哇&#xff01;&#xff01;&#xff01; 在C语言中&#xff0c;我们解决一个问题通常是采用在了解了问题如何解决后&#xff0c;设置一个一个的函数&#xff0c;依次调用实现不同的功…

解决:微软在登录时总是弹出需要家长或监护人同意才能使用该账户并且不断循环?

目录 问题来源&#xff1a; 解决办法&#xff1a; 问题来源&#xff1a; 我的edge浏览器账号登录&#xff0c;一直弹出来需要家长或监护人同意才能使用&#xff0c;然后按照提示操作&#xff0c;会一直循环&#xff0c;是个无穷循环。 解决办法&#xff1a; 参考&#xff1…

Qt6版使用Qt5中的类遇到的问题解决方案

如果有需要请关注下面微信公众号&#xff0c;会有更多收获&#xff01; 1.QLinkedList 是 Qt 中的一个双向链表类。它提供了高效的插入和删除操作&#xff0c;尤其是在中间插入和删除元素时&#xff0c;比 QVector 更加优秀。下面是使用 QLinkedList 的一些基本方法&#xff1a…

电子电器架构 —— 车载网关边缘节点总线转换

电子电器架构 —— 车载网关边缘节点路由转发策略 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 PS:小细节,本文字数3000+,详细描述了网关在车载框架中的具体性能设置。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 没有人关注你。也无…

信号完整性分析基础知识之有损传输线、上升时间衰减和材料特性(十):有损传输线在时域中的表现

如果高频衰减大于低频衰减&#xff0c;随着信号传输&#xff0c;上升时间将会增加。上升时间通常定义为边沿在最终值的 10% 到 90% 之间过渡的时间。这假设信号的边缘轮廓看起来有点高斯分布&#xff0c;中间是最快的斜率区域。对于该波形&#xff0c;10%−90% 的上升时间是有意…

使用SpringBoot Actuator监控应用

使用SpringBootActuator监控应用 微服务的特点决定了功能模块的部署是分布式的&#xff0c;大部分功能模块都是运行在不同的机器上&#xff0c;彼此通过服务调用进 行交互&#xff0c;前后台的业务流会经过很多个微服务的处理和传递&#xff0c;出现了异常如何快速定位是哪个…

Windows上搭建一个网站(基本生产环境)

前言 本博客记录的是Windows上一次网站搭建的过程&#xff0c;主要是在前端采用的是React&#xff0c;后端采用的是Flask&#xff0c;记录一下生产版本搭建流程和坑点&#xff0c;供有缘人一起进步&#xff0c;当然本博客还存在很多不足。 前端项目构建生产版本 以React为例…

【原创】java+swing+mysql鲜花购物商城设计与实现

前言&#xff1a; 本文主要介绍了鲜花购物商城的设计与实现。首先&#xff0c;通过市场需求&#xff0c;我们确定了鲜花商场的功能&#xff0c;通常的商城一般都是B/S架构&#xff0c;然而我们今天要用javaswing去开发一个C/S架构的鲜花商城&#xff0c;利用开发技术和工具&am…