【C++】30h速成C++从入门到精通(二叉树)

news2025/1/13 10:01:19

说明

为什么要在C++当中单独再次提及数据结构中的二叉树:

  1. map和set特性需要先铺垫二叉搜索树,而二叉搜哦书也是一种树形结构

  1. 二叉搜索树的特性了解,有助于更好的理解map和set特性

  1. 二叉树中部分面试题有难度

  1. 有些OJ使用C语言实现比较麻烦

二叉搜索树

概念

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

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

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

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

操作

查找:

  • 若根节点不为空:

  • 根节点key==查找key,返回ture

  • 根节点key > 查找key,去到其左子树继续查找

  • 根节点key < 查找key,去到其右子树继续查找

  • 否则返回false

插入:

  • 树为空,直接插入,返回true

  • 树不为空,按二叉树性质查找插入位置,插入新节点

删除:

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

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

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

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

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

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

  • 情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点

  • 情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点

  • 情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点中 再来处理该结点的删除问题

模拟实现(请仔细阅读代码):

#include<iostream>
#include<assert.h>
#include<vector>
#include<vld.h>
using namespace std;

template<class Type>
class BST;

template<class Type>
class BSTNode
{
    friend class BST<Type>;
public:
    BSTNode(Type d=Type(),BSTNode<Type>*left=nullptr,BSTNode<Type>*right=nullptr)
        :data(d),leftChild(left),rightChild(right)
    {}
    ~BSTNode()
    {}
private:
    Type data;
    BSTNode<Type> *leftChild;
    BSTNode<Type> *rightChild;
};

template<class Type>
class BST
{
public:
    BST():root(nullptr)
    {}
    ~BST()
    {
        Destroy();
    }
public:
    BSTNode<Type>* Find(const Type &key)const
    {
        return Find(root, key);
    }
    bool Insert(const Type &v)
    {
        return Insert(root, v);
    }
    bool Remove(const Type &key)
    {
        return Remove(root, key);
    }
    Type Min()const
    {
        return Min(root);
    }
    Type Max()const
    {
        return Max(root);
    }
    void SortPrint()const
    {
        SortPrint(root);
    }
    void Destroy()
    {
        Destroy(root);
    }
protected:
    BSTNode<Type>* Find(BSTNode<Type> *t, const Type &key)const
    {
        if(t==nullptr || t->data==key)
            return t;

        if(key < t->data)
            return Find(t->leftChild, key);
        else 
            return Find(t->rightChild, key);
    }
    void SortPrint(BSTNode<Type> *t)const
    {
        if(t != nullptr)
        {
            SortPrint(t->leftChild);
            cout<<t->data<<" ";
            SortPrint(t->rightChild);
        }
    }
    Type Min(BSTNode<Type> *t)const
    {
        assert(t != nullptr);
        while(t->leftChild != nullptr)
            t = t->leftChild;
        return t->data;
    }
    Type Max(BSTNode<Type> *t)const
    {
        assert(t != nullptr);
        while(t->rightChild != nullptr)
            t = t->rightChild;
        return t->data;
    }
    bool Insert(BSTNode<Type> *&t, const Type &v)
    {
        //1 查找插入位置
        BSTNode<Type> *p = t, *pr = nullptr;

        while(p != nullptr)
        {
            if(v == p->data)
                return false;

            pr = p;

            if(v < p->data)
                p = p->leftChild;
            else
                p = p->rightChild;
        }

        p = new BSTNode<Type>(v);

        //2 建立连接
        if(pr == nullptr)
        {
            t = p;
            return true;
        }

        if(v < pr->data)
            pr->leftChild = p;
        else
            pr->rightChild = p;
        return true;
    }

    bool Remove(BSTNode<Type> *&t, const Type &key)
    {
        //1 查找节点
        if(t == nullptr)
            return false;
        if(key < t->data)
            Remove(t->leftChild, key);
        else if(key > t->data)
            Remove(t->rightChild, key);

        else
        {
            //2删除节点
            if(t->leftChild!=nullptr && t->rightChild!=nullptr)
            {
                BSTNode<Type> *p = t->leftChild;
                while(p->rightChild != nullptr)
                    p = p->rightChild;

                t->data = p->data;
                Remove(t->leftChild, p->data);
            }
            else
            {
                //最多只有一棵子树
                BSTNode<Type> *p = t;
                if(t->leftChild != nullptr)
                    t = p->leftChild;
                else
                    t = p->rightChild;
                delete p;
            }

            return true;
        }
    }

    void Destroy(BSTNode<Type> *&t)
    {
        if(t != nullptr)
        {
            Destroy(t->leftChild);
            Destroy(t->rightChild);
            delete t;
            t = nullptr;
        }
    }
private:
    BSTNode<Type> *root;
};

应用

  1. k模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。

比如给一个简单的单词word,判断该单词是否正确,具体方式如下:

  • 在单词集合中的个每个单词作为key,构建一个二叉搜索树

  • 在二叉树中寻找是否存在,是则正确,否则错误

  1. kv模型:每一个关键码key都有与之对应的value,即<key,value>的键值对,该种方式在现实生活中非常常见,比如英汉词典就是中英对应的关系

template<class K, class V>
struct BSTNode
 {
 BSTNode(const K& key = K(), const V& value = V())
 : _pLeft(nullptr) , _pRight(nullptr), _key(key), _Value(value)
 {}
 BSTNode<T>* _pLeft;
 BSTNode<T>* _pRight;
 K _key;
 V _value
 };
template<class K, class V>
class BSTree
 {
 typedef BSTNode<K, V> Node;
 typedef Node* PNode;
public:
 BSTree(): _pRoot(nullptr)
 {}
 // 同学们自己实现,与二叉树的销毁类似
 ~BSTree();
 // 根据二叉搜索树的性质查找:找到值为data的节点在二叉搜索树中的位置
 PNode Find(const K& key);
 bool Insert(const K& key, const V& value)
 {
 // ...
 
 PNode pCur = _pRoot;
 PNode pParent = nullptr;
 while (pCur)
 {
 pParent = pCur;
 if (key < pCur->_key)
 pCur = pCur->_pLeft;
 else if (key > pCur->_key)
 pCur = pCur->_pRight; // 元素已经在树中存在
 else
 return false;
 }
 // ...
 return true;
 }
 bool Erase(const K& key)
 {
 // ...
 return true;
 }
private:
 PNode _pRoot;
 };

性能分析

插入和删除必须查找,查找效率代表了二叉搜索树中各个操作的性能

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Kubernetes14:Helm为了部署像微服务这种的大型项目

Kubernetes14&#xff1a;Helm介绍&#xff08;为了部署像微服务这种的大型项目&#xff09; 1、Helm的引入 (1)之前方式部署应用基本过程 编写yaml文件 1、deployment kubectl create deployment nginx --imagenginx --dryrun -o yaml > nginx.yaml2、Service kubect…

Web前端:前端开发人员的职责有哪些?

前端开发&#xff0c;就是要创造上面提到的网站面向用户的部分背后的代码&#xff0c;并通过建立框架&#xff0c;构建沉浸性的用户体验。前端工程师还需要确保网站在各种浏览器和设备上都能正常运行&#xff0c;并且能够根据用户需求不断优化和改进网站。前端开发人员的角色和…

【C语言进阶】文本与二进制操作文件,优化通讯录。

前言&#xff1a;上篇文章&#xff0c;我们已经学习了有关本地磁盘文件的常用文件操作&#xff0c;已经能够对本地文件进行调用与读写。我们磁盘中还存在着一些内容用二进制存储的文件&#xff0c;这也就是我们今天将要讲解的内容。一、文本文件与二进制文件根据数据的组织形式…

SpiderFlow爬虫获取网页节点

SpiderFlow爬虫获取网页节点 一、SpiderFlow 文档地址&#xff1a;https://www.spiderflow.org/ 二、问题&#xff1a;获取一篇文章的标题、来源、发布时间、正文、下载附件该怎么获取&#xff1f; 举例&#xff1a;【公示】第三批智能光伏试点示范名单公示 三、抓取网页步骤…

Heatmap-based Out-of-Distribution Detection 论文阅读

原文地址 概要 我们的工作将分布失调【out-of-distribution,OOD】检测作为神经网络输出解释问题进行研究。我们学习了一种热图【heatmap】表示&#xff0c;用于检测OOD图像&#xff0c;同时可视化ID和OOD的图像区域。给定一个训练过的固定分类器&#xff0c;我们训练一个解码…

ArrayList源码分析(JDK17)

ArrayList类简介类层次结构构造无参构造有参构造添加元素add&#xff1a;添加/插入一个元素addAll:添加集合中的元素扩容mount与迭代器其他常见方法不常见方法不常见方法的源码和小介绍常见方法的源码和小介绍积累面试题ArrayList是什么&#xff1f;可以用来干嘛&#xff1f;Ar…

funkyheatmap | 用这个包来完美复刻Nature Biotechnology的高颜值神图吧!~

1写在前面 天气开始暖和了☀️&#xff0c;发现旅游的人好多啊&#xff01;~&#x1f972; 不知道自己什么时候能有时间出去看看外面的世界&#xff0c;实在是太忙了。&#x1f637; 最近用到的有个包感觉很不错&#xff0c;分享给大家&#xff0c;funkyheatmap包。&#x1f61…

进程与多线程(入门)

什么是线程 要了解什么是线程&#xff0c;得先知道什么是程序。 程序&#xff1a;为完成特定任务&#xff0c;用某种语言编写的一组指令的集合。 例如&#xff0c;QQ&#xff0c;Steam&#xff0c;亦或者java写的helloword。 这些都是程序 了解了程序&#xff0c;还得清楚什么…

d3.js绘制饼状图,悬浮出现字以及点击事件

代码以及注释如下&#xff1a; const width 300; // 定义圆的宽度 const height 300; // 定义圆的高度 const radius Math.min(width, height) / 2; // 算出半径 const color d3.scaleOrdinal() .range(["#98abc5", "#8a89a6", "#6b486b&qu…

【MySQL高级篇】第05章_存储引擎

第05章_存储引擎 1. 查看存储引擎 查看mysql提供什么存储引擎 show engines;2. 设置系统默认的存储引擎 查看默认的存储引擎 show variables like %storage_engine%; #或 SELECT default_storage_engine;修改默认的存储引擎 如果在创建表的语句中没有显式指定表的存储引擎…

一分钟成为签到达人!Redis BitMap轻松解决,Spring Boot带你飞

如何实现签到功能&#xff0c;尤其是如何实现高效的签到与统计&#xff0c;是开发者们需要考虑的问题。在本篇文章中&#xff0c;我们将介绍如何利用Spring Boot整合Redis BitMap实现签到与统计。 Redis BitMap简介 在介绍如何利用Redis BitMap实现签到与统计之前&#xff0c;…

unity动画--动画绑定,转换,用脚本触发

文章目录如何制作和添加动画大概过程示例图将多组图片转化为动画放在对象身上实现动画之间的切换使用脚本触发Parameters(Trigger)如何制作和添加动画 大概过程示例图 将多组图片转化为动画放在对象身上 首先&#xff0c;我们要为我们要对象添加animator 然后我们要设置对应的…

计算机网络-应用层

文章目录前言概述Https协议(443)Http协议(80)HttpsTLS/SSL 协议TLS的四次握手总结前言 本博客仅做学习笔记&#xff0c;如有侵权&#xff0c;联系后即刻更改 科普&#xff1a; 概述 Https协议(443) 参考网址 Http协议(80) 谈到Https必然要先将httpHTTP 请求报文结构 请求…

谷粒学院开发(一):基础准备

商业模式 常见商业模式 B2C模式&#xff1a; 两个角色&#xff1a; 管理员&#xff1a;增加&#xff0c;修改&#xff0c;删除普通用户&#xff1a;查询 商家到用户&#xff0c;自己制作大量自有版权的视频&#xff0c;放在自有平台上&#xff0c;让用户付费。 这是这个项目使…

Linux下查看图片中某点的像素X、Y坐标

在做目标检测、目标追踪的任务过程中&#xff0c;我们会用到一些开源的数据集&#xff0c;比如MOT16多目标追踪数据集。这些数据集会提供数据标注文件gt.txt,里面的内容如下1,1,912,484,97,109,0,7,12,1,912,484,97,109,0,7,13,1,912,484,97,109,0,7,14,1,912,484,97,109,0,7,1…

[Openwrt]procd实现hotplug机制介绍

Linux处理hotplug事件方法kobject_uevent() 产生 uevent 事件(lib/kobject_uevent.c 中), 产生的 uevent 先由 netlink_broadcast_filtered() 发出, 最后调用 uevent_helper[] 所指定的程序来处理.uevent_helper[] 里默认指定 "/sbin/hotplug", 但可以通过 /sys/kern…

spring boot starter 实现生成行为验证码验证

最近公司有一个验证用户行为的需求&#xff0c;因此实现了一个用户行为验证码的starter&#xff0c;具体效果如下&#xff1a;代码结构如下&#xff1a;common 下面放的是公共文件枚举类generator 下面放的是生成行为验证码的相关类与扩展接口resource 下面放的是加载解析行为图…

若依代码生成器的使用

一、代码生成器的使用1.新建maven模块原则上&#xff0c;我们的业务代码和若依系统本身的系统代码是要做隔离的&#xff0c;一方面是易于之后随着若依系统升级而升级&#xff0c;另一方面则是纯粹的合理性考虑。这里新建一个ruoyi-business模块作为业务代码模块&#xff0c;新建…

Mac环境安装python

一、介绍&#xff1a; Python是跨平台的&#xff0c;它可以运行在Windows、Mac和各种Linux/Unix系统上。在Windows上写Python程序&#xff0c;放到Linux上也是能够运行的。 要开始学习Python编程&#xff0c;首先就得把Python安装到你的电脑里。安装后&#xff0c;你会得到Pyt…

LearnOpenGL-光照-4.光照贴图

本人刚学OpenGL不久且自学&#xff0c;文中定有代码、术语等错误&#xff0c;欢迎指正 我写的项目地址&#xff1a;https://github.com/liujianjie/LearnOpenGLProject 文章目录光照贴图漫反射贴图例子1镜面光贴图例子2 采样镜面光贴图小结什么是光照贴图光照贴图如何影响颜色光…