热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:数据结构十分钟带你入门树结构!

篇首语:本文由编程笔记#小编为大家整理,主要介绍了数据结构十分钟带你入门树结构!相关的知识,希望对你有一定的参考价值。

篇首语:本文由编程笔记#小编为大家整理,主要介绍了数据结构十分钟带你入门树结构!相关的知识,希望对你有一定的参考价值。








文章目录


  • 前言
  • 一、树的定义
  • 二、专业术语
  • 三、树的分类
  • 四、二叉树的存储
    • 1.连续存储(完全二叉树)
    • 2.连续存储的优缺点
    • 3.链式存储

  • 五、森林的存储
  • 六、二叉树的遍历
  • 七、树应用的简单介绍
  • 八、链式二叉树三种遍历顺序详解(代码实现)
    • 1.目标树结构
    • 2.主函数
    • 3.代码构建树
    • 3.先序中序后序函数






前言
一、树的定义

1.专业定义:
<1> 有且只有一个根节点。
<2> 由若干个互不相干的子树&#xff0c;这些子树本身也是一棵树通俗的定义。


1.通俗的定义&#xff1a;
<1> 树是由节点和边组成的。
<2> 每个节点只有一个父亲节点但可以有多个子节点。
<3> 有一个节点例外&#xff0c;该节点没有父亲节点&#xff0c;此节点称为根节点。


二、专业术语

1.深度
从根节点到最底层节点的层数称为深度&#xff0c;根节点是第一层。


2.叶子结点
没有子节点的节点


3.非终端节点
实际就是非叶子节点


4.度
最大子节点的个数称为度


三、树的分类

1.一般树
任意一个节点的子节点的个数不受限制。



2.二叉树
任意一个子节点的个数最多是二&#xff0c;且子节点的位置不可更改。





<1> 满二叉树&#xff1a;在不增加树的层数的情况下无法在多添加一个节点的二叉树就是满二叉树



在这里插入图片描述



<2> 完全二叉树&#xff1a;如果只是删除了满二叉树最底层最右边的连续若干个节点&#xff0c;这样形成的二叉树就是完全二叉树。

在这里插入图片描述



3.森林
n个互不相交的树的集合


在这里插入图片描述



四、二叉树的存储

1.连续存储&#xff08;完全二叉树&#xff09;



在这里插入图片描述



改造后的存储结果&#xff1a;
在这里插入图片描述






2.连续存储的优缺点

优点&#xff1a;查找某个父节点和子节点&#xff08;包括判断有无子节点&#xff09;速度很快。



缺点&#xff1a;太耗内存空间。



3.链式存储

每个节点包含三个域&#xff0c;两个指针域和一个数值域。其中两个指针域用来指向两个孩子节点&#xff0c;数值域保存节点信息。

在这里插入图片描述



在这里插入图片描述



五、森林的存储

1.存储思路
将森林转化为二叉树在进行存储
设法保证任意一个节点的&#xff1a;
<1> 左指针指向他的第一个孩子。
<2> 右指针指向他的下一个兄弟节点
<3> 将各个树的根节点互相看做兄弟节点。
2.例图如下

在这里插入图片描述




转换为二叉树之后的存储结构&#xff1a;

在这里插入图片描述



六、二叉树的遍历

1.先序遍历&#xff08;先访问根节点&#xff09;
先访问根节点。
再访问左子树。
最后访问右子树。

原理图&#xff1a;


在这里插入图片描述

例图&#xff1a;

在这里插入图片描述



2.中序遍历&#xff08;中间访问根节点&#xff09;
先访问左子树。
中间访问根节点。
最后访问右子树。

原理图&#xff1a;

在这里插入图片描述



例图&#xff1a;

在这里插入图片描述



3.后序遍历&#xff08;最后访问根节点&#xff09;
先访问左子树。
再访问右子树。
最后访问根节点。



原理图&#xff1a;
在这里插入图片描述



例图&#xff1a;

在这里插入图片描述




七、树应用的简单介绍

<1> 树是数据库中数据组织的一种重要形式。

<2> 操作系统父子进程本身就是一棵树。

<3> 面向对象语言类的继承关系本身就是一棵树。




八、链式二叉树三种遍历顺序详解&#xff08;代码实现&#xff09;

1.目标树结构



在这里插入图片描述


2.主函数

#include
#include
struct TreeNode {
char data;
struct TreeNode * pLchild; //p是指针,Lchild是左孩子
struct TreeNode * pRchild;
};
struct TreeNode * CreatBTree();
void FirstOrderBTree(struct TreeNode *pT);//先序函数声明
void InFixOrderBTree(struct TreeNode *pT); //中序函数声明
void PostOrderBTree (struct TreeNode *pT);//后序函数声明

int main()
{
struct TreeNode *pT&#61;CreatBTree(); //定义树
printf("先序遍历结果为&#xff1a;");
FirstOrderBTree(pT);//先序
printf("\\n");
printf("中序遍历结果为&#xff1a;");
InFixOrderBTree(pT);//中序
printf("\\n");
printf("后序遍历结果为&#xff1a;");
PostOrderBTree(pT);//后序

return 0;

}

3.代码构建树

struct TreeNode * CreatBTree(void)//
{
struct TreeNode* pA &#61;(struct TreeNode *) malloc(sizeof(struct TreeNode));//定义A结点
struct TreeNode* pB &#61;(struct TreeNode *) malloc(sizeof(struct TreeNode));//定义B结点
struct TreeNode* pC &#61;(struct TreeNode *) malloc(sizeof(struct TreeNode));
struct TreeNode* pD &#61;(struct TreeNode *) malloc(sizeof(struct TreeNode));
struct TreeNode* pE &#61;(struct TreeNode *) malloc(sizeof(struct TreeNode));
pA->data&#61;&#39;A&#39;; //指向他的数据域
pB->data&#61;&#39;B&#39;;
pC->data&#61;&#39;C&#39;;
pD->data&#61;&#39;D&#39;;
pE->data&#61;&#39;E&#39;;
pA->pLchild&#61;pB; //pA的左子树指向
pA->pRchild&#61;pC;
pB->pLchild&#61;pB->pRchild&#61;NULL;//pB没有孩子结点
pC->pLchild&#61;pD;
pC->pRchild&#61;NULL;
pD->pLchild&#61;NULL;
pD->pRchild&#61;pE;
pE->pLchild&#61;pE->pRchild&#61;NULL;
return pA;

}





3.先序中序后序函数

先序思路分析&#xff1a;pT->pLchild可以表示整个左子树&#xff0c;则在先序遍历的时候我可以先输出根节点&#xff0c;然后使用递归输出我的左子树&#xff0c;当左子树输出完递归结束。再用同样的方法递归出右子树。

void FirstOrderBTree(struct TreeNode *pT) //先序遍历
//先访问根节点再访问左子树最后访问右子树
{
if(pT!&#61;NULL)
{
printf("%c ",pT->data);
//pT->pLchild可以表示整个左子树
FirstOrderBTree(pT->pLchild);//采用递归算法遍历左子树

FirstOrderBTree(pT->pRchild);//再采用递归算法遍历右子树
}

}



中序思路分析&#xff1a;先递归输出左子树&#xff0c;然后输出根节点&#xff0c;最后递归输出右子树。

void InFixOrderBTree(struct TreeNode *pT) //中序遍历
//先访问左子树再访问根节点最后访问右子树
{
if(pT!&#61;NULL)
{

InFixOrderBTree(pT->pLchild);//先采用递归算法遍历左子树
printf("%c ",pT->data); // 然后遍历根节点
InFixOrderBTree(pT->pRchild);//最后采用递归算法遍历右子树
}

}



后序思路分析&#xff1a;先递归输出左子树&#xff0c;然后递归输出右子树&#xff0c;最后输出根节点。

void InFixOrderBTree(struct TreeNode *pT) //中序遍历
//先访问左子树再访问根节点最后访问右子树
{
if(pT!&#61;NULL)
{

InFixOrderBTree(pT->pLchild);//先采用递归算法遍历左子树
printf("%c ",pT->data); // 然后遍历根节点
InFixOrderBTree(pT->pRchild);//最后采用递归算法遍历右子树
}

}
void PostOrderBTree (struct TreeNode *pT) //后序遍历
//先访问左子树再访问右节点最后访问根节点
{
if(pT!&#61;NULL)
{

PostOrderBTree(pT->pLchild);//先采用递归算法遍历左子树

PostOrderBTree(pT->pRchild);//再采用递归算法遍历右子树

printf("%c ",pT->data); // 最后遍历根节点
}

}




运行结果&#xff1a;
在这里插入图片描述






推荐阅读
  • 本文介绍了指针的概念以及在函数调用时使用指针作为参数的情况。指针存放的是变量的地址,通过指针可以修改指针所指的变量的值。然而,如果想要修改指针的指向,就需要使用指针的引用。文章还通过一个简单的示例代码解释了指针的引用的使用方法,并思考了在修改指针的指向后,取指针的输出结果。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • C# 7.0 新特性:基于Tuple的“多”返回值方法
    本文介绍了C# 7.0中基于Tuple的“多”返回值方法的使用。通过对C# 6.0及更早版本的做法进行回顾,提出了问题:如何使一个方法可返回多个返回值。然后详细介绍了C# 7.0中使用Tuple的写法,并给出了示例代码。最后,总结了该新特性的优点。 ... [详细]
  • 解决Cydia数据库错误:could not open file /var/lib/dpkg/status 的方法
    本文介绍了解决iOS系统中Cydia数据库错误的方法。通过使用苹果电脑上的Impactor工具和NewTerm软件,以及ifunbox工具和终端命令,可以解决该问题。具体步骤包括下载所需工具、连接手机到电脑、安装NewTerm、下载ifunbox并注册Dropbox账号、下载并解压lib.zip文件、将lib文件夹拖入Books文件夹中,并将lib文件夹拷贝到/var/目录下。以上方法适用于已经越狱且出现Cydia数据库错误的iPhone手机。 ... [详细]
  • 本文介绍了为什么要使用多进程处理TCP服务端,多进程的好处包括可靠性高和处理大量数据时速度快。然而,多进程不能共享进程空间,因此有一些变量不能共享。文章还提供了使用多进程实现TCP服务端的代码,并对代码进行了详细注释。 ... [详细]
  • 本文介绍了解决二叉树层序创建问题的方法。通过使用队列结构体和二叉树结构体,实现了入队和出队操作,并提供了判断队列是否为空的函数。详细介绍了解决该问题的步骤和流程。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了最长上升子序列问题的一个变种解法,通过记录拐点的位置,将问题拆分为左右两个LIS问题。详细讲解了算法的实现过程,并给出了相应的代码。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • PDO MySQL
    PDOMySQL如果文章有成千上万篇,该怎样保存?数据保存有多种方式,比如单机文件、单机数据库(SQLite)、网络数据库(MySQL、MariaDB)等等。根据项目来选择,做We ... [详细]
author-avatar
haiziqian_486_834
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有