【数据结构】二叉树算法讲解(定义+算法原理+源码)

博主介绍:✌全网粉丝喜爱+、前后端领域优质创作者、本质互联网精神、坚持优质作品共享、掘金/腾讯云/阿里云等平台优质作者、擅长前后端项目开发和毕业项目实战✌有需要可以联系作者我哦!

🍅附上相关C语言版源码讲解🍅

👇🏻 精彩专栏推荐订阅👇🏻 不然下次找不到哟

目录

一、二叉树定义(特点+结构)

二叉树算法性质:

二、算法实现(完整代码)

三、算法总结

二叉树的优点:

 二叉树的缺点:

二叉树的应用:

小结

大家点赞、收藏、关注、评论啦 !

谢谢哦!如果不懂,欢迎大家下方讨论学习哦。

一、二叉树定义(特点+结构)

二叉树是一种树形结构,每个节点最多有两个子节点,分别称为左子节点和右子节点。二叉树具有以下定义和特点:

1. 节点:二叉树是由节点构成的集合。每个节点包含三个基本信息:
   - 数据元素(或称为节点值)。
   - 指向左子节点的指针/引用。
   - 指向右子节点的指针/引用。

2. 根节点: 二叉树中的一个节点被称为根节点,它是整个树的起始节点。一棵二叉树只有一个根节点。

3. 叶子节点:没有子节点的节点被称为叶子节点(或叶节点)。

4. 父节点和子节点: 每个节点都有一个父节点,除了根节点。父节点指向它的子节点。

5. 深度:一个节点的深度是从根节点到该节点的唯一路径的边的数量。根节点的深度为0。

6. 高度/深度: 一棵二叉树的高度(或深度)是树中任意节点的最大深度。

7. 子树:二叉树中的任意节点和它的所有子孙节点组成的集合被称为子树。

8. 二叉搜索树(BST):在二叉搜索树中,每个节点的左子树中的节点值都小于该节点的值,而右子树中的节点值都大于该节点的值。

9. 满二叉树:如果一棵深度为k,且有2^k - 1个节点的二叉树被称为满二叉树。

10. 完全二叉树:对于一棵深度为k的二叉树,除了最后一层外,其它各层的节点数都达到最大值,且最后一层的节点都集中在左边,被称为完全二叉树。

二叉树的定义为:

struct TreeNode {int val;                 // 节点值TreeNode *left;          // 左子节点指针TreeNode *right;         // 右子节点指针TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

上述定义为C++中使用类实现的二叉树节点定义,包含节点值、左子节点指针和右子节点指针。

二叉树算法性质:

你提到的这些性质描述了二叉搜索树(Binary Search Tree,BST)的一些重要特征。让我们逐一解释这些性质:

1. 将任何一个点看作Root节点,则这个点的左子树也是 Binary Search Tree:这表示二叉搜索树中每个节点的左子树都满足二叉搜索树的性质,即左子树上的节点值小于当前节点的值。

2. 将任何一个点看作Root节点,则这个点的右子树也是 Binary Search Tree:类似地,这表明每个节点的右子树都是一个二叉搜索树,右子树上的节点值大于当前节点的值。

3. Binary Search Tree中的最小节点,一定是整棵树中最左下的叶子节点:这是因为最小节点不会有左子节点,只能一直沿着左子树往下走,直到叶子节点。

4. Binary Search Tree中的最大节点,一定是整棵树中最右下的叶子节点:同样,最大节点不会有右子节点,只能一直沿着右子树往下走,直到叶子节点。

这些性质是二叉搜索树在节点排列和结构上的特点,它们使得在二叉搜索树上执行搜索、插入和删除等操作更加高效。通过遵循这些性质,可以确保在整个树结构中维持有序性,使得二叉搜索树成为一种常用的数据结构。

二、算法实现(完整代码)

通过二叉树实现A、B、C、D的简单应用

#include<iostream>
using namespace std;
typedef char DataType;
struct BiNode
{DataType data;BiNode *lchild,*rchild;
};
//(1)假设二叉树采用链接存储方式存储,分别编写一个二叉树先序遍历的递归
//算法和非递归算法。
class BiTree
{public:BiTree(){root=Create(root);}//构造函数,建立一颗二叉树~BiTree(){Release(root);}//析构函数,释放各个节点的存储空间void Preorder(){Preorder(root);}//前序遍历二叉树void Inorder(){Inorder(root);}//中序遍历二叉树void Postorder(){Postorder(root);}//后序遍历二叉树void Levelorder(){Levelorder(root);};//层序遍历二叉树private:BiNode *root;//指向根节点的头指针BiNode *Create(BiNode *bt);//构造函数调用void Release(BiNode *bt);//析构函数调用void Preorder(BiNode *bt);//前序遍历函数调用void Inorder(BiNode *bt);//中序遍历函数调用void Postorder(BiNode *bt);//后序遍历函数调用void Levelorder(BiNode *bt);//层序遍历函数调用
};
//前序遍历
void BiTree::Preorder(BiNode *bt)
{if(bt==NULL)return;//递归调用的结束条件else{cout<<bt->data<<" ";//访问根节点bt的数据域Preorder(bt->lchild);//前序递归遍历bt的左子树Preorder(bt->rchild);//前序递归遍历bt的右子树}
}
//中序遍历
void BiTree::Inorder(BiNode *bt)
{if(bt==NULL)return;//递归调用的结束条件else{Inorder(bt->lchild);//中序递归遍历bt的左子树cout<<bt->data<<" ";//访问根节点的数据域Inorder(bt->rchild);//中序递归遍历bt的右子树}
}
//后序遍历
void BiTree::Postorder(BiNode *bt)
{if(bt==NULL)return;//递归调用的结束条件else{Postorder(bt->lchild);//后序递归遍历bt的左子树Postorder(bt->rchild);//后序递归遍历bt的右子树cout<<bt->data<<" ";//访问根节点bt的数据域}
}
//层序遍历
void BiTree::Levelorder(BiNode *bt){BiNode *Q[100],*q=NULL;int front=-1,rear=-1;//队列初始化 if(root == NULL) return;//二叉树为空,算法结束Q[++rear]=root;//根指针入队while(front!=rear){//当队列非空时 q=Q[++front];//出队cout<<q->data<<" ";if(q->lchild!=NULL) Q[++rear]=q->lchild;if(q->rchild!=NULL) Q[++rear]=q->rchild; } 
}
//创建二叉树 
BiNode *BiTree::Create(BiNode *bt)
{static int i=0;char ch;string str="AB#D##C##";ch=str[i++];if(ch=='#')bt=NULL;//建立一棵空树 else {bt=new BiNode;bt->data=ch;//生成一个结点,数据域为chbt->lchild=Create(bt->lchild);//递归建立左子树bt->rchild=Create(bt->rchild);//递归建立右子树}return bt;
}
//销毁二叉树 
void BiTree::Release(BiNode *bt)
{if(bt!=NULL){Release(bt->lchild);Release(bt->rchild);delete bt;}
}
int main()
{cout<<"创建一棵二叉树"<<endl;BiTree T;//创建一颗二叉树cout<<"---层序遍历---"<<endl;//A B C D T.Levelorder();cout<<endl;cout<<"---前序遍历---"<<endl;//A B D CT.Preorder();cout<<endl;cout<<"---中序遍历---"<<endl;//B D A CT.Inorder();cout<<endl;cout<<"---后序遍历---"<<endl;//D B C AT.Postorder();cout<<endl;return 0;
}

执行结果:

序存储的完全二叉树递归先序遍历算法描述(C++)如下:

//完全二叉树的顺序存储结构
#include <iostream>
#include <string.h>
#define MaxSize 100
using namespace std;
typedef char DataType;
class Tree{public:Tree(string str);//构造函数void createTree();//创建二叉树 void seqPreorder(int i);//先序遍历二叉树 void seqInorder(int i);//中序遍历二叉树 void seqPostorder(int i);//后序遍历二叉树 private: DataType node[MaxSize];//结点中的数据元素int num=0;//二叉树结点个数 string str;
};Tree::Tree(string str){this->str = str;
} void Tree::createTree(){for(int i = 1;i < str.length()+1 ;i++){node[i]=str[i-1];num++;}node[0] = (char)num;
}//顺序存储的完全二叉树递归先序遍历算法描述(C++)如下:
void Tree::seqPreorder(int i){if(i==0)//递归调用的结束条件return;else{cout<<"  "<<(char)node[i];//输出根结点if(2*i<=(char)node[0])seqPreorder(2*i);//先序遍历i的左子树elseseqPreorder(0);if(2*i+1<=(char)node[0])seqPreorder(2*i+1);//先序遍历i的右子树elseseqPreorder(0); } 
} //顺序存储的完全二叉树递归中序遍历算法描述(C++)如下:
void Tree::seqInorder(int i){if(i==0)//递归调用的结束条件return;else{if(2*i<=(char)node[0])seqInorder(2*i);//中序遍历i的左子树elseseqInorder(0);cout<<"  "<<(char)node[i];//输出根结点if(2*i+1<=(char)node[0])seqInorder(2*i+1);//中序遍历i的右子树elseseqInorder(0); } 
} //顺序存储的完全二叉树递归后序遍历算法描述(C++)如下:
void Tree::seqPostorder(int i){if(i==0)//递归调用的结束条件return;else{if(2*i<=(char)node[0])seqPostorder(2*i);//后序遍历i的左子树elseseqPostorder(0);if(2*i+1<=(char)node[0])seqPostorder(2*i+1);//后序遍历i的右子树elseseqPostorder(0); cout<<"  "<<(char)node[i];//输出根结点} 
} // (2)一棵完全二叉树以顺序方式存储,设计一个递归算法,对该完全二叉树进
//行中序遍历。
int main(){string str = "ABCDEFGHIJ";Tree T(str);//定义对象变量buscout<<"按层序编号的顺序存储所有结点:"<<str<<endl;T.createTree();cout<<"顺序存储的完全二叉树递归前序递归遍历:"<<endl; T.seqPreorder(1);cout<<endl; cout<<"顺序存储的完全二叉树递归中序递归遍历:"<<endl; T.seqInorder(1);cout<<endl; cout<<"顺序存储的完全二叉树递归后序递归遍历:"<<endl; T.seqPostorder(1);cout<<endl; return 0;
}

三、算法总结

二叉树的优点:

1. 快速查找: 在二叉搜索树(BST)中,查找某个元素的时间复杂度是O(log n),这使得二叉树在查找操作上非常高效。

2. 有序性:BST保持元素的有序性,对于某些应用场景,如快速查找最小值、最大值或在某一范围内的值,二叉树非常有用。

3. 容易插入和删除:在BST中,插入和删除操作相对容易,不需要像其他数据结构一样频繁地移动元素。

4. 中序遍历:通过中序遍历二叉搜索树,可以得到有序的元素序列,这对于某些应用(如构建有序列表)很方便。

 二叉树的缺点:

1. 平衡性:如果不平衡,二叉搜索树的性能可能下降为线性级别,而不再是对数级别。因此,需要采取额外的措施来保持树的平衡,如 AVL 树或红黑树。

2. 对数据分布敏感: 对于某些特定的数据分布,比如按顺序插入的数据,可能导致二叉搜索树退化成链表,性能下降。

二叉树的应用:

1. 数据库索引:在数据库中,二叉搜索树被广泛应用于构建索引结构,以加速数据的检索。

2. 表达式解析:二叉树可用于构建表达式树,用于解析和求解数学表达式。

3. 哈夫曼编码:二叉树用于构建哈夫曼树,实现有效的数据压缩算法。

4. 文件系统:在文件系统的目录结构中,可以使用二叉树来组织和管理文件。

5. 网络路由:用于构建路由表,支持快速而有效的网络数据包路由。

6. 编译器设计: 语法分析阶段通常使用二叉树来构建语法树,以便后续的编译步骤。

7. 游戏开发:在游戏开发中,二叉树可以用于实现场景图、动画系统等。

8. 排序算法:一些排序算法,如快速排序,就是通过构建和操作二叉树来实现的。

总体而言,二叉树在计算机科学领域的应用非常广泛,它的特性使得它适用于多种数据管理和搜索场景。在实际应用中,需要根据具体情况选择合适的二叉树变体以及适当的平衡策略。

大家点赞、收藏、关注、评论啦 !

谢谢哦!如果不懂,欢迎大家下方讨论学习哦。

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

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

相关文章

Java - 深入四大限流算法:原理、实现与应用

文章目录 Pre概述简单计数器原理实现测试优缺点 滑动窗口算法原理实现测试优缺点 漏桶算法原理实现测试优缺点 令牌桶算法原理实现测试优缺点 小结 Pre 深入理解分布式技术 - 限流 并发编程-25 高并发处理手段之消息队列思路 应用拆分思路 应用限流思路 SpringBoot - 优雅…

画眉(京东科技设计稿转代码平台)介绍

前言 随着金融App业务的不断发展&#xff0c;为了满足不同场景下的用户体验及丰富的业务诉求&#xff0c;业务产品层面最直接体现就是大量新功能的上线及老业务的升级&#xff0c;随之也给研发带来了巨大的压力&#xff0c;所以研发效率的提升就是当前亟需解决的问题&#xff…

QGIS生成热力图

目录 1 QGIS介绍 2 实现效果 3 具体步骤 3.1 获取北京市地图&#xff08;区县级&#xff09; 3.1.1 方法一&#xff1a;直接找到北京市地图 3.1.2 方法二&#xff1a;若没有单独的北京市地图&#xff0c;从中国地图上提取 3.2 获取数据 3.3 导入数据 1 QGIS介绍…

数据结构之使用顺序表写出通讯录

前言 昨天我们踏入了数据结构的深山&#xff0c;并且和顺序表battle了一番&#xff0c;虽说最后赢了&#xff0c;但同时也留下了一个问题&#xff1a;如何从顺序表的增删查改加强到通讯录的的增删查改&#xff0c;别急&#xff0c;今天就带你一探究竟。 一.回顾与思考 我们昨…

geemap学习笔记053:纹理特征

前言 纹理特征通常描述了遥感影像中像素之间的空间关系和变化&#xff0c;对于地物分类、目标检测以及图像分割等遥感应用非常有价值。本节将会介绍Earth Engine中提供的一些纹理特征计算方法&#xff0c;包括熵和灰度共生矩阵。 1 导入库并显示数据 import ee import geema…

【UE5】第一次尝试项目转插件(Plugin)的时候,无法编译

VS显示100条左右的错误&#xff0c;UE热编译也不能通过。原因可能是[名字.Build.cs]文件的错误&#xff0c;缺少一些内容&#xff0c;比如说如果要写UserWidget类&#xff0c;那么就要在 ]名字.Build.cs] 中加入如下内容&#xff1a; public class beibaoxitong : ModuleRules …

自己本机Video retalking制作数字人

首先需要注意的是&#xff0c;这个要求你的笔记本显存和内存都比较大。我的电脑内存是64G&#xff0c;显卡是8G&#xff0c;操作系统是Windows 11&#xff0c;勉强能够运行出来&#xff0c;但是效果不是很好。 效果如下&#xff0c;无法上传视频&#xff0c;只能通过图片展示出…

[分章:阅读]《我的第一本算法书》

第一章数据结构 1.链表 1、数据结构之一&#xff0c;线性排列数据&#xff0c;指针链接数据&#xff1b;访问O&#xff08;n&#xff09;&#xff0c;删除/添加O&#xff08;1&#xff09; 2、类似链条。 2.数组 1、线性排列数据&#xff0c;含数据下标&#xff08;即索引&…

Ubuntu20.04.3LTS桌面版与Window10双系统并存

Ubuntu20.04.3LTS桌面版与Window10双系统并存 文章目录 Ubuntu20.04.3LTS桌面版与Window10双系统并存1.分区与安装1. 硬盘分区1. 一般用途2. 服务器用 2. 操作系统版本及分区信息3. 安装时创建用户4. 安装后修改root设置用户密码&#xff1a;3. 安装时指定ip4. 设置静态IP 2. 安…

Java线程池七大参数详解和配置(面试重点)

一、corePoolSize核心线程数 二、maximunPoolSize最大线程数 三、keepAliveTime空闲线程存活时间 四、unit空闲线程存活时间的单位 五、workQueue线程工作队列 1、ArrayBlockingQueue FIFO有界阻塞队列 2、LinkedBlockingQueue FIFO无限队列 3、PriorityBlockingQueue V…

【代码随想录】刷题笔记Day54

前言 差单调栈就结束代码随想录一刷啦&#xff0c;回家二刷打算改用python补充进博客&#xff0c;小涛加油&#xff01;&#xff01;&#xff01; 647. 回文子串 - 力扣&#xff08;LeetCode&#xff09; 双指针法 中心点外扩&#xff0c;注意中心点可能有一个元素可能有两个…

Supervised Contrastive 损失函数详解

有什么不对的及时指出&#xff0c;共同学习进步。(●’◡’●) 有监督对比学习将自监督批量对比方法扩展到完全监督设置&#xff0c;能够有效地利用标签信息。属于同一类的点簇在嵌入空间中被拉到一起&#xff0c;同时将来自不同类的样本簇推开。这种损失显示出对自然损坏很稳…

【Linux C | 进程】进程终止、等待 | exit、_exit、wait、waitpid

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

【Kafka】开发实战和Springboot集成kafka

目录 消息的发送与接收生产者消费者 SpringBoot 集成kafka服务端参数配置 消息的发送与接收 生产者 生产者主要的对象有&#xff1a; KafkaProducer &#xff0c; ProducerRecord 。 其中 KafkaProducer 是用于发送消息的类&#xff0c; ProducerRecord 类用于封装Kafka的消息…

仅使用K-M法+Cox比例风险模型就能发二区文章 | SEER公共数据库周报(1.17)

欢迎各位参加本周中山大学著名卫生统计学家方积乾教授公益直播讲座&#xff01; 就在本周三晚&#xff0c;主题为“真实世界研究与RCT研究”&#xff0c;欢迎各位预约参加&#xff01; SEER&#xff08;The Surveillance, Epidemiology, and End Results&#xff09;数据库是由…

回溯算法篇-01:全排列

力扣46&#xff1a;全排列 题目分析 这道题属于上一篇——“回溯算法解题框架与思路”中的 “元素不重复不可复用” 那一类中的 排列类问题。 我们来回顾一下当时是怎么说的&#xff1a; 排列和组合的区别在于&#xff0c;排列对“顺序”有要求。比如 [1,2] 和 [2,1] 是两个不…

柔性数组和C语言内存划分

柔性数组和C语言内存划分 1. 柔性数组1.1 柔性数组的特点&#xff1a;1.2 柔性数组的使用1.3 柔性数组的优势 2. 总结C/C中程序内存区域划分 1. 柔性数组 也许你从来没有听说过柔性数组&#xff08;flexible array)这个概念&#xff0c;但是它确实是存在的。 C99 中&#xff…

力扣740. 删除并获得点数

动态规划 思路&#xff1a; 选择元素 x&#xff0c;获得其点数&#xff0c;删除 x 1 和 x - 1&#xff0c;则其他的 x 的点数也会被获得&#xff1b;可以将数组转换成一个有序 map&#xff0c;key 为 x&#xff0c; value 为对应所有 x 的和&#xff1b;则问题转换成了不能同…

Postman基本使用、测试环境(Environment)配置

文章目录 准备测试项目DemoController测试代码Interceptor模拟拦截配置 Postman模块简单介绍Postman通用环境配置新建环境(Environment)配置环境(Environment)设置域名变量引用域名变量查看请求结果打印 Postman脚本设置变量登录成功后设置全局Auth-Token脚本编写脚本查看conso…

即插即用篇 | UniRepLKNet:用于音频、视频、点云、时间序列和图像识别的通用感知大卷积神经网络 | DRepConv

大卷积神经网络(ConvNets)近来受到了广泛研究关注,但存在两个未解决且需要进一步研究的关键问题。1)现有大卷积神经网络的架构主要遵循传统ConvNets或变压器的设计原则,而针对大卷积神经网络的架构设计仍未得到解决。2)随着变压器在多个领域的主导地位,有待研究ConvNets…