【数据结构】树

深入了解二叉树 (1) 深入讲解二叉树 阅读详情

引言

一直没有系统的学习“树”这一数据结构,导致对一些概念,用法模棱两可,所以现在开始系统的学习一下;

知识点总结

树

树的定义

有若干条节点和若干条边组成的数据结构;
树是一种非线性的数据结构,我们可以类比想像生活中的树,有树枝,树枝分叉处,树叶等;
在这里插入图片描述

为什么要使用树

我们来考虑一个问题,有一段线路(长度为n)出现了故障,我们要判断问题出现在那部分,一般方法就是通过一节节的测试,但是这样的话平均需要测n/2次,当n非常大时,复杂度是不能接受的;因此,需要一个更为巧妙的办法==》二分查找;
在这里插入图片描述
这样的话,查找的时间复杂度就直接变成了log2n次,复杂度大大降低了,这种方法可以用”树“来实现;

树的特点

  • 一棵树有n个节点,则可以确定有且仅有n-1条边;

常见术语

  • 节点的度,指节点的子树数;
    在这里插入图片描述
  • 叶节点,度为0的点;
  • 树的度,树中最大的节点的度;

二叉树

树的种类有很多种,其中最常用的就是二叉树;

二叉树的定义

树的度<=2的树称为二叉树;且二叉树的左右子树是严格区分的,不可随意改动;

特殊的二叉树

1.满二叉树
在这里插入图片描述
像这样的除了叶子节点,其余节点的度都为2的二叉树称为满二叉树;
2.完全二叉树
满二叉树是特殊的完全二叉树;
在这里插入图片描述

完全二叉树的性质

  • 根节点的编号为1;
  • 用数组表示完全二叉树的话,节点编号为i的左右节点存在的话,对应的编号为2i,2i+1;
  • 二叉树的i层至多有2^(i-1)个节点;

二叉树的创建

struct node{
	int data;
	node* lc;
	node* rc;//<1>
};
node* newNode(int x){
	node* Node=new node;
	Node->lc=Node->rc=NULL;//<2>
	Node->data=x;
	return Node;
}
void insert(node* &root,int x){//<5>
	if(root==NULL){
		root=newNode(x);
		return;
	}
	if(root->lc==NULL)//<3>
	  insert(root->lc,x);
    else
	  insert(root->rc,x);
}
int num[100];
node* create(int data[],int n){
	node* root=NULL;//<4>
	for(int i=0;i<n;i++)
	  insert(root,data[i]);
	return root;
}

上述代码创建出来的二叉树:
在这里插入图片描述

对上面的代码一些我自己纠结了很久的地方做个解释
<1>
node* root与node *root是一样的,都是表示root为node类型的指针;千万不要过分纠结(很难受);
<2><4>
都是为了初始化节点,NULL是一个宏定义,表示不指向任何地址的空指针;
<5>
node* &root的写法是为了能够修改二叉树(添加节点),与之相对应的是在遍历操作者就不需要使用&root,因为遍历时不需要对二叉树进行修改;
<3>
目前只会这样创建,太菜了;

二叉树的遍历

**注意:以下先,中,后都是描述根节点的位置的,比如先序遍历的顺序是根节点->左节点->右节;后序遍历的顺序是左->右->根节点;

1.先序遍历

void preorder(node* root){
	if(root==NULL)
	    return;
	printf("%d ",root->data);
	preorder(root->lc);
	preorder(root->rc);
}

先序遍历的特点:
先序遍历序列的第一个一定是根节点;

2.中序遍历

void inorder(node* root){
	if(root==NULL)
	    return;
	inorder(root->lc);
	printf("%d ",root->data);
	inorder(root->rc);
}

中序遍历的特点:
只要知道根节点,就能区分左右子树;
1.后序遍历

void postorder(node* root){
	if(root==NULL)
	    return;
	postorder(root->lc);
	postorder(root->rc);
	printf("%d ",root->data);
}

后序遍历的特点:
序列的最后一个是根节点;

总结
只有知道中序遍历序列,才可能唯一确定一棵二叉树,因为先序/后序节点只能确定根节点的位置,不能把左右节点分开;

4.层序遍历

void layerorder(node* root){
	queue<node*>q;
	q.push(root);
	while(!q.empty()){
		node* curr=q.front();
	     	q.pop();
		cout<<curr->data<<" ";
		if(curr->lc!=NULL){
			q.push(curr->lc);	
		}
		if(curr->rc!=NULL){
			q.push(curr->rc);
		}
	}
}

重建二叉树

我们经常会见到这样的问题:给定一个二叉树的中序序列,和先序/后序/层次序列的一种,重建这个二叉树;其中,先序等三种序列的作用是确定树的根节点位置,中序遍历序列的作用是区分左右节点;
以下面的例题来解释:

问题描述
定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。
输入样例
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
输出样例
4 1 6 3 5 7 2

问题分析
在这里插入图片描述
代码展示

#include<bits/stdc++.h>
using namespace std;
struct node{
	int data;
	node* lc;
	node* rc;//<1>
};
node* newNode(int x){
	node* Node=new node;
	Node->lc=Node->rc=NULL;//<2>
	Node->data=x;
	return Node;
}
int post[100],in[100];
vector<int>ans;
node* JudgeByPostAndIn(int PostL,int PostR,int inL,int inR){
	//当前树的后序序列:[PostL,PostR],中序序列:[inL,inR]

	if(PostL>PostR)//??什么情况会 > 
	   return NULL;
	   node* root=newNode(post[PostR]);//创建节点! 
	 int k=inL;
	 while(in[k]!=post[PostR])k+=1;
	 //找到中序序列中root的位置	
	 int numLeft=k-inL;//左子树个数 
	 root->lc=JudgeByPostAndIn(PostL,PostL+numLeft-1,inL,k-1);
	 root->rc=JudgeByPostAndIn(PostL+numLeft,PostR-1,k+1,inR);  
	 return root;
}
void layorder(node* root){
	queue<node*>q;
	q.push(root);
	while(!q.empty()){
		node* curr=q.front();
		q.pop();
		ans.push_back(curr->data);
		if(curr->lc!=NULL)q.push(curr->lc);
		if(curr->rc!=NULL)q.push(curr->rc);
	}
}
int main(){
	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)scanf("%d",&post[i]);
	for(int i=1;i<=n;i++)scanf("%d",&in[i]);
   node* root=JudgeByPostAndIn(1,n,1,n);
   layorder(root);
   for(int i=0;i<ans.size();i++){
   	if(i!=0)printf(" ");
   	printf("%d",ans[i]);
   }
   return 0;
   
}

数据结构 B树系列 每个节点最多有m个子节点,其中m是一个正整数。根节点除外,其他节点至少有⌈m/2⌉个子节点。每个节点中的键值按照非降序排列。对于节点中的键值k,如果有n个子节点,那么节点中的n-1个键值将把节点分为n个区间,第i个区间的键值小于k,第i+1个区间的键值大于等于k。所有叶子节点位于同一层,且不包含任何键值信息,可以看作是外部存储的块。每个非叶子节点中的键值个数比子节点个数少1。每个节点中的键值个数满足:⌈m/2⌉-1 阅读详情

相关推荐

JWT实战:5分钟搞定Spring Boot集成JWT认证(含完整代码示例)

本文详细介绍了如何在Spring Boot中快速集成JWT认证,提供完整的代码示例和配置指南。通过JWT实现无状态认证,解决分布式系统中的会话管理问题,提升系统扩展性和安全性。涵盖令牌生成、验证、Spring Security整合及生产级优化方案。

weixin_29327525的博客 456

二叉树是不是树?

1. 树和二叉树是两种不同的树形结构,二叉树不是树的特殊形式。2. 二叉树也不是 度为 2的有序树。

m0_51736802的博客 8243

LibTV本地部署:AI漫剧创作完整解决方案与实战指南

如果你正在关注AI漫剧创作这个赛道,可能会发现一个有趣的现象:市面上的AI视频工具要么功能单一,要么云端服务昂贵且存在内容审核风险。而今天要介绍的LibTV本地部署方案,或许能为你打开一扇新的大门。 这个方案的核心是Seedance2.0与豆包AI的本地化集成,它真正解决的是创作者对内容自主权、成本控制和创作效率的三重需求。与红果、抖音等平台提供的标准化AI工具相比,本地部署意味着你可以完全掌控生成过程,不受平台规则限制,更重要的是——所有数据都在本地,不存在内容泄露风险。 1. 这篇文章真正要解决的问题

weixin_28745309的博客 523

【PTA】【数据结构与算法】树的基本概念

这里是从PTA平台整理的【树的基本概念】题目集

葑鈊丶 8158

【已验证】基于STM32F407与AD9833的幅频特性测试装置设计与实现

本文详细介绍了基于STM32F407微控制器和AD9833 DDS芯片的低成本幅频特性测试装置设计与实现方法。通过扫频原理,该装置能自动生成正弦波信号,测量滤波器等电路的输出幅度变化,并在LCD屏幕或示波器上绘制幅频特性曲线。文章提供了从硬件选型、CubeMX工程配置、关键驱动代码编写到数据处理与可视化的完整教程,帮助电子爱好者与工程师快速搭建实用的滤波器测试工具。

weixin_35649491的博客 120

Chapter 19 Digital Phase-Locked Loops

数字锁相环 Digital Phase-Locked Loops, 就是根据原来时钟信号, 产生新的时钟信号, which is locked or synchronized. (align 参考时钟边沿 or 在中间)

2304_76736886的博客 973

数据结构复习——二叉树的表示及遍历

一、常用概念 1.一棵有N个结点的树有N-1条边 2.结点的度:结点的子树个数 3.树的度:树的所有结点中最大的度数 4.一棵树采用  firstChild-nextSibling 表示方法可以转换为二叉树 5.二叉树的子树有左右之分,二叉树有5中基本形式 6.满二叉树:深度为k,共有2^k-1个结点 7.完全二叉树:按序号对应 二、二叉树遍历 typedef struct tr

three__stones的博客 689

在Pycharm中配置Pyqt5工具(2023年新版教程)

在Pycharm中配置Pyqt5相关的三个工具:QtDesigner、PyUIC、PYRCC

网络技术和Python 2万+

数据结构之树

本篇只涉及树的概念范围和应考思路,不涉及具体结构或算法的实现与思考 1.树 在计算器科学中,树(英语:tree)是一种抽象数据类型或是实现这种抽象数据类型的数据结构,用来模拟具有树状结构性质的数据集合。它是由n(n>0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点: ①每个节点有零个或多个子节...

lishinho的博客 6万+

PCIe设备内存访问实战:从ioremap到DMA映射的完整流程解析

本文深入解析了PCIe设备内存访问的完整流程,涵盖从CPU通过ioremap访问设备寄存器,到设备通过DMA映射高效读写主机内存的核心机制。详细探讨了虚拟地址、物理地址与总线地址的转换关系,对比了一致性与流式DMA映射的适用场景及同步要点,并阐述了IOMMU在安全与效率中的作用,为驱动开发者提供了实战代码与关键陷阱分析。

weixin_29201933的博客 506

Arch Linux双系统安装避坑指南:从Windows分区到桌面环境全流程

本文提供了一份详尽的Arch Linux与Windows双系统安装避坑指南。内容涵盖从安装前的UEFI环境确认、BitLocker处理、分区规划,到Live环境进入、基础系统安装、GRUB引导配置,再到显卡驱动安装、KDE/GNOME桌面环境部署及中文化设置的全流程。重点解决了双系统安装中的核心痛点,帮助用户在不破坏现有Windows系统的前提下,顺利完成Arch Linux的安装。

nice1的博客 535

【数据结构】数据结构中常用的树

声明:本文汇总了数据结构中一些常用的树,主要内容来自《数据结构(严蔚敏版)》和《算法导论》这两本教材。本文主要归纳出数据结构中常见的树的概念与简单的性质,并未给出具体的操作,如插入、删除、查找等。1、树的定义首先给出树的相关定义:树(tree)是包含n(n>0)个结点的有穷集,其中: 1)每个元素称为结点(node); 2)有一个特定的结点被称为根结点或树根(root); 3)除根结点之外的其

长相忆兮长相忆的专栏 2万+

详述 MIMIC 数据库26张数据表(一)

作者按照自身理解和实验要求对MIMIC-III的26张数据表进行整理归纳并进行介绍。

越努力 越幸运 7237

【数据结构】树的认识

正在二叉树的路上前进

adcxhw的博客 1773

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

数据结构——树的概述

引言 对于大量的输入数据,链表的线性访问时间太慢,不宜使用。本篇讨论一种简单的数据结构——树,它大部分操作的运行时间平均为O(logN)O(logN)O(logN)。数据结构中有很多树的结构,其中包括二叉树、二叉搜索树、2-3树、红黑树等等。 基本概念 树(tree)是一些节点的集合。该集合可以是空集,若不是空集,则树由称为根(root)r的节点以及0个或 多个非空的子树组成。 每颗子树的根就做根...

日积月累,天道酬勤 3165

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

树——数据结构

树、数据结构、树的定义、树的概念、树的应用、结点

b19839356939的博客 2052

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

数据结构——树

关于树的基础入门都在这,学完了你就能应付工作啦

weixin_51209821的博客 8055

【数据结构】树的定义

在计算机科学中,树(Tree)是一种重要的基础数据结构,广泛应用于许多领域,如文件系统的目录结构、数据库的索引、编译器的语法树、人工智能的决策树等。理解树的基本概念和术语,对于学习计算机科学及其相关技术具有重要的意义。本篇博客将通过清晰的定义和图示,带领大家逐步了解树的基础知识,适合初学者进行学习和掌握。

XuanRan的博客 8397

【Java数据结构】树

java集合框架:树

2303_77535762的博客 1987

数据结构——B-树、B+树、B*树

在之前,我们已经学习了很多的数据结构,当我们处理海量数据时,选择合适的数据结构变得至关重要,对于不同的数据结构它们的搜索效率也存在着很大的差异。如下种类数据格式时间复杂度顺序查找无要求O(N)二分查找有序O(log⁡2N)二叉搜索树无要求O(N)二叉平衡树(AVL树和红黑树)无要求O(log⁡2N)哈希无要求O(1)以上结构适合用于数据量相对不是很大,能够一次性存放在内存中,进行数据查找的场景。

学习日记 4411

数据结构——B树、B+树、哈夫曼树

B+树的构造类似于B树的构造但是在 **3.当一组的节点超过4个的情况下,将中间的节点提到上一层,并且原本一组分成两份。6.B+Tree 的节点上是不保存数据的,那么它保存的关键字就更多,这样一次 IO 操作,加载的关键字就更多,所以它的磁盘读写能力更强。1、B+树是B树的一种变形形式,B+树上的叶子结点存储关键字以及相应记录的地址,叶子结点以上各层作为索引使用。7.B+的叶子节点天然就是顺序存放的。2、B+树的非叶子节点具有索引值,在内存相同的情况下,能够存放更多的key,树的高度就会越低。

2301_78125917的博客 1353
上一篇: 动态代理
下一篇: 【每日一题】比较含退格的字符串
高冷小伙
博客等级 码龄7年 223粉丝 182原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

高冷小伙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值