【数据结构】树的概念及结构


前言

这个话题的文章主要围绕二叉树进行讲解,由于涉及数据结构——二叉树的知识点和算法内容较多,所以我会将二叉树的内容分成多个博客,由浅入深的讲解。这篇博客的内容是:树的概念及结构,目的是引出大家对树的初步认识。

一.树的概念

在这里插入图片描述
在这里插入图片描述
上面有两张树的图片,一张是我们生活中的树,另一张是数据结构上的树(逻辑上)。可见,树的结构同我们之前学习的栈和队列的结构不同,树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成的一个具有层次关系的集合。把这种数据结构叫做树,是因为它看起来像一棵倒挂的树,根在顶部,叶子在底部。

1.树有一个特殊的结点,称为根结点,根结点是没有前驱结点的;
2.除根节点外,其余结点被分为M(M>0)个互不相交的的集合T1,T2,…,Tm,其中每一个集合Ti(1<=i<=m)又是一棵结构与树类似的子树。每棵子树的根节点有且仅有一个前驱结点可以有0个或多个后继。即任何一个结点都有0~N个孩子;
3.因此,树是递归定义的;

4.在这里插入图片描述

二.树在实际生活中的应用

在这里插入图片描述

为了能够让我们更形象的理解树的概念,我们认识几个树在实际生活中的应用。

1.B-Tree,B±Tree在文件系统的目录树结构;
2.二进制尝试-几乎在每个高宽带路由器中用于存储的路由器表,路由搜索引擎;
3.二进制空间分区-几乎在所有3D视频游戏中都使用,以确定需要渲染哪些对象;
4.二进制搜索树-用于许多不断输入、离开数据的搜索应用程序中,例如许多语言库中的map等;
5.海量数据并发查询,二叉树复杂度低,二叉排序树既有链表的好处,又有数组的好处,在处理大批量的动态数据比较有用;
6.哈夫曼编码,来源于哈夫曼树,即带权路径长度最短的树,又为最优二叉树;
7.C++ STL中的set/multiset,map,以及Linux虚拟内存管理,都输通过红黑树去实现的。查找最大(最小)的k个树,红黑数中查找/删除/插入,时间复杂度都值需要O(logN)。

三.树的相关知识点

在这里插入图片描述

节点的度:一个节点含有的子树的个数称为该节点的度, 如上图:A的为6
叶节点或终端节点:度为0的节点称为叶节点; 如上图:B、C、H、I…等节点为叶节点
分支节点或非终端节点:度不为0的节点; 如上图:D、E、F、G…等节点为分支节点
双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点; 如上图:A是B的父节点
孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点; 如上图:B是A的孩子节点
兄弟节点:具有相同父节点的节点互称为兄弟节点; 如上图:B、C是兄弟节点(注意这里指的是亲兄弟)
树的度:一棵树中,最大的节点的度称为树的度; 如上图:树的度为6
节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推,上图一共有4个层次
树的高度或深度:树中节点的最大层次; 如上图:树的高度为4
堂兄弟节点:双亲在同一层的节点互为堂兄弟;如上图:H、I互为堂兄弟节点
节点的祖先:从根到该节点所经分支上的所有节点;如上图:A是所有节点的祖先,Q的祖先有J,E,A,P的祖先与Q一样
子孙:以某节点为根的子树中任一节点都称为该节点的子孙。如上图:所有节点都是A的子孙
森林:由m(m>0)棵互不相交的树的集合称为森林;

四.树的表示

树的结构,相对于线性表就比较复杂了,要存储的方式也比较麻烦。我们既要保存数据域,也要保存结点和结点之间的关系,实际中树有很多种表示方式,如:双亲表示法,孩子表示法,孩子双亲表示法以及孩子兄弟表示法等。我们这里使用的是最常用的孩子兄弟表示法:一个结点准备两个指针域,一个数据域,从父结点开始,一直链接最左边的第一个孩子,然后亲兄弟之间,从最大的那个孩子开始,用兄弟指针相互链接。举一个抽象的例子,双亲接连生了两个孩子,但是他们只带一个最大的那个孩子,然后让他们最大的那个孩子去带他们的二孩子,二孩子总共生了三个孩子,但是他也只带他最大的那个孩子,即D,然后让D带E,E带F。。。
在这里插入图片描述

这里我们由浅入深的去定义一下树的结构

//树的度为N,即最大结点的度
//静态
#define N 5
struct TreeNode
{
   int data;
   struct TreeNode* childArr[N];
   int childSize;
};
//动态
struct TreeNode
{
   int data;
   //顺序表存储孩子结点指针,用到了二级指针,很麻烦
   struct TreeNode** childArr;
   int childSize;
   int childCapacity;
};

合理的定义方式:

typedef int DataType;
struct TreeNode
{
   struct TreeNode* firstchild;//指向左边第一个孩子
   struct TreeNode* nextbro;//指向亲兄弟
   DataType data;//结点中的数据域
};

伪代码:递归遍历整棵树:但是递归的太深会有栈溢出这个缺点。

void PrintTree(struct TreeNode* parent)
{
   if(parent==NULL)
   {
      return;
   }
   printf(parent);
   TreeNode* cur=parent->firstchild;
   while(cur)
   {
      PrintTree(cur);
      cur=cur->next;
   }
}
  • 8
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

_麦子熟了

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

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

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

打赏作者

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

抵扣说明:

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

余额充值