当前位置: 首页 > news >正文

二叉树进阶

一、二叉搜索树

1.二叉搜索树的概念

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

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

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

1.3 它的左右子树也都是二叉搜索树

2.二叉搜索树的操作

int a[]={8,3,1,10,6,4,7,14,13};

2.1 二叉搜索树的节点的定义

二叉树的每个不为空的节点都存储着左孩子和右孩子节点的指针,以及当前节点的值

template<class T>
//一个节点的构造
struct BSTNode
{BSTNode(const T& data = T()):_right(nullptr), _left(nullptr), _data(data){}BSTNode<T>* _right;		//左孩子节点的指针BSTNode<T>* _left;		//右孩子节点的指针T _data;			//当前节点的值
};

2.2 二叉搜索树的结构

二叉搜索树的具体操作是被设为公开的,根节点是被设为私有的,只能在类内才能访问。

template<class T>
//搜索二叉树
class BSTree
{typedef BSTNode<T> Node;	//将节点名字进行重命名
public://....private:Node* _root;			//先存一个根节点的指针,并且为私有
};

2.3 二叉搜索树的查找

方法:从根开始比较查找,比根大的前往右树继续查找,比根小的往左树继续查找。

返回结果:最多查找高度次,找到返回true,没找到返回false。

//查找,找到返回true,没找到返回false
bool Find(const T& value)
{//用一个临时节点储存根Node* cur = _root;//当cur不为空时就继续找while (cur){//当value大于根节点的值,去右树找if (cur->_data < value){cur = cur->_right;}else if (cur->_data > value){//当value小于根节点的值,去左树找cur = cur->_left;}else{//当value等于根节点的值return true;}}//没找到return false;
}

2.4 二叉搜索树的插入

树为空则直接new一个新节点并初始化给根节点

树不为空则寻找要插入的位置后再进行插入

bool Insert(const T& value)
{//当根节点为空时,直接new一个节点并初始化为value并赋给根if (_root == nullptr){_root = new Node(value);return true;}//当根节点不为空时//二叉搜索树有一个特点,右孩子比根节点的值大,左孩子比根节点的值小//创建一个临时变量cur存储当前节点,和一个储存cur上一个节点的临时变量Node* parent = nullptr;Node* cur = _root;//寻找value应该要插入的位置while (cur != nullptr){//当value大于根节点的值,value要插入到cur的右树里面去if (cur->_data < value){parent = cur;cur = cur->_right;}else if(cur->_data > value){parent = cur;cur = cur->_left;}else{//搜索二叉树不允许有相同的值的存在return false;}}//找到要插入的位置后//parent为要插入的节点的父亲,但不确定要插入到父亲的哪个孩子上,所以还要进行比较一下if (parent->_data < value){//插入到右孩子处parent->_right = new Node(value);return true;}else{//插入到左孩子处parent->_left = new Node(value);return true;}
}

2.5 二叉搜索树的删除

首先要查找要删除的值是否在树中,如果不在树中则直接返回false,如果在树中又要分以下四中情况进行讨论。

情况1:要删除的节点没有左右孩子

情况2:要删除的节点只有左孩子

情况3:要删除的节点只有右孩子

情况4:要删除的节点同时有左孩子和右孩子

实际情况下情况1可以和情况2或3进行合并,因此真正的删除操作如下:

处理情况2的方法:储存该节点的值,并将该节点的左孩子给与其父节点,然后删除该节点

处理情况3的方法:储存该节点的值,并将该节点的右孩子给与其父节点,然后删除该节点

处理情况4的方法:先找到该节点右子树中最小的值的节点(最左节点),然后替换这两个节点的值,将最左节点的右孩子给最左节点的父节点,然后删除最左节点;当然也可以先找到该节点左子树中的最大值的节点(最右节点),然后进行相似的操作。

//删除
bool Erase(const T& value)
{//先查找当前节点//用一个临时节点储存根,以及一个cur的上一个节点Node* parent = _root;Node* cur = _root;//当cur不为空时就继续找while (cur){//当value大于根节点的值,去右树找if (cur->_data < value){parent = cur;cur = cur->_right;}else if (cur->_data > value){//当value小于根节点的值,去左树找parent = cur;cur = cur->_left;}else{//当value等于根节点的值,找到了break;}}//若要删除的节点不在当前树中if (cur == nullptr){return false;}//找到了要删除的节点,又要分三种情况//情况1:当前节点既有左孩子也有右孩子,当然也有可能是根节点if (cur->_right != nullptr && cur->_left != nullptr){//处理方法:先找到右树的最左节点,然后用替换法进行删除parent = cur;Node* subLeft = cur->_right;while (subLeft->_left != nullptr){parent = subLeft;subLeft = subLeft->_left;}//交换cur和最左节点std::swap(subLeft->_data, cur->_data);if (subLeft == parent->_left){parent->_left = subLeft->_right;}else{parent->_right = subLeft->_right;}delete subLeft;return true;}else if(cur->_right==nullptr&&cur->_left!=nullptr){//情况2:当前节点只有左孩子,没有右孩子//处理办法:删除当前节点并把该节点的左孩子给父亲的左孩子if (cur == _root){_root = cur->_left;}else{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}}delete cur;return true;}else{//情况3:当前节点只有右孩子或一个孩子也没有//处理办法:删除当前节点并把该节点的右孩子给父亲的右孩子if (cur == _root){_root = cur->_right;}else{if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}}delete cur;return true;}return false;
}

2.6 二叉搜索树的遍历

二叉搜索树中序遍历的结果必定是有序的。

public:	void InOrder(){_InOrder(_root);cout << endl;}
private:void _InOrder(Node*& root){//结束条件:当当前节点为空时返回if (root == nullptr){return;}//中序遍历是左根右_InOrder(root->_left);cout << root->_data << " ";_InOrder(root->_right);}

3.二叉搜索树的应用

3.1 K模型K模型只有key作为关键码,结构中只需要存key即可,关键码即为需要搜索到的值

比如:给一个单词,判断该单词是否拼写正确,具体方法如下:

以词库中所有单词作为key构建一棵二叉搜索树,在二叉搜索树查找该单词是否存在,存在则拼写正确,不存在则拼写错误。

3.2 KV模型每一个关键码key都有一个与之对应的值value,即<Key,Value>的键值对

比如英汉词典就是中文和英文对应关系,通过英文就可以快速找到对应的中文,英文单词和其对应的中文<word,chinese>就构成一对键值对。

再比如统计单词次数,统计成功后,给定单词就可以快速找到其出现的次数,单词与其出现的次数就是<word,count>构成一对键值对。

4.二叉搜索树的性能分析

插入和删除前必须先查找,查找效率就代表了二叉树各个操作的具体性能。

对于一个有n个节点的二叉搜索树,关键码插入的顺序不同可能会导致不同结构的二叉搜索树:

最优情况下,二叉搜索树可能会接近完全二叉树,其平均查找次数为logN

最坏情况下,二叉搜索树可能会成为一只单支树,其平均查找次数为N/2

一般性能会按照最坏的情况作为标准,所以二叉搜索树的时间复杂度一般为O(N)

http://www.xdnf.cn/news/498025.html

相关文章:

  • c++重要知识点汇总(不定期更新)
  • flutter flutter run 运行项目卡在Running Gradle task ‘assembleDebug‘...
  • Linux基础开发工具二(gcc/g++,自动化构建makefile)
  • OpenCV级联分类器
  • gRPC开发指南:Visual Studio 2022 + Vcpkg + Windows全流程配置
  • ABP vNext 多租户开发实战指南
  • Uniapp开发鸿蒙应用时如何运行和调试项目
  • 中级统计师-统计学基础知识-第二章数据描述
  • 产品经理入门(2)产品体验报告
  • 深入解析SpringMVC:从入门到精通
  • uniapp自动构建pages.json的vite插件
  • 多商户商城系统源码解析:开发直播电商APP的技术底层实战详解
  • python线程相关讲解
  • uni-app 开发HarmonyOS的鸿蒙影视项目分享:从实战案例到开源后台
  • 显卡、Cuda和pytorch兼容问题
  • Rust 数据结构:HashMap
  • PostGIS实现栅格数据入库-raster2pgsql
  • 端口443在git bash向github推送时的步骤
  • 轻量、优雅、高扩展的事件驱动框架——Hibiscus-Signal
  • 【C++ Qt】布局管理器
  • redis的pipline使用结合线程池优化实战
  • Java大师成长计划之第25天:Spring生态与微服务架构之容错与断路器模式
  • Qt 强大的窗口停靠浮动
  • Javascript:WebAPI
  • React Fiber 架构深度解析:时间切片与性能优化的核心引擎
  • ARM (Attention Refinement Module)
  • spring -MVC-02
  • DeepSeek赋能电商,智能客服机器人破解大型活动人力困境
  • 数组集合互转问题
  • Ubuntu 安装 squid