数据结构二叉树常考性质及详细解析(一)(C语言版)

版权声明:原创文章仅供大家学习使用,严禁转载 https://blog.csdn.net/qq_41809589/article/details/86561854

树型结构是一类非常重要的非线性结构,它可以很好地描述客观世界中广泛存在的具有分支关系或层次特性的对象,在计算机领域里有着广泛应用。
树是以分支关系定义的层次结构,树的定义如下:树(Tree)是n(n≥0)个结点的有限集T,如果n = 0,称为空树;否则:有且仅有一个称为树的(root)的结点。当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,……Tm,其中每一个集合本身又是一棵树,称为根的子树(subtree)。对于非空树,其特点:树中至少有一个结点——根,树中各子树是互不相交的集合。
在这里插入图片描述
结点(node):包括数据元素及若干指向其子树的分支。(划重点专用
结点的度(Degree):结点拥有的子树数。(划重点专用
叶子(Leaf)(或终端结点):度为0的结点。(划重点专用
非终端结点(或分支结点):度不为0的结点。
树的度:树内各结点的度的最大值。(划重点专用
孩子(Child)、双亲(Parent):结点的子树的根称为该结点的孩子,相应地,该结点称为孩子的双亲。(划重点专用
兄弟:同一个双亲的孩子之间互称兄弟。
结点的层次(Level):设根为第1层,它的孩子为第2层,依次类推。(划重点专用
堂兄弟:其双亲在同一层的结点互称为堂兄弟。
树的深度(高度):树中结点的最大层次数。(划重点专用
结点的祖先:从根结点到该结点所经分支上的所有结点。
结点的子孙:以某结点为根的子树中的任一结点都称为该结点的子孙。
有序树和无序树:树中各结点的子树从左到右有次序(不能互换),称该树为有树,否则为无序树。(有序树:第一个孩子、第二个孩子,…,最后一个孩子)。
森林:m(m不为0)棵互不相交的树构成的集合。
在这里插入图片描述
【二叉树】

二叉树:二叉树或为空树,或是由一个根结点加上两棵分别称为左子树和右子树的、互不交的二叉树组成。
二叉树的递归定义:其左右子树又都是二叉树。

二叉树的基本特征
1、每个结点最多只有两棵子树。
2、子树有左右之分,其次序不能任意颠倒。

二叉树重要性质:(划重点专用
性质1:在二叉树的第 i 层上至多有2的i-1 次方个结点。(i≥1)
性质2:深度为 k 的二叉树至多有 2的k次方减1个结点(k≥1)。
性质3:对任何一棵二叉树,若它含有n0 个叶子结点、n2 个度为 2 的结点,则必存在关系式:n0 = n2+1。
证明(性质3):设二叉树上结点总数 n = n0 + n1 + n2 …①
又设二叉树上分支总数为 b ,则:
从前驱 (入支)角度(从下向上) 有b= n-1 … ②
从后继(出支)角度(从上向下) 有 b=n1+2n2 +0*n0 …③
从而有: n0 + n1 + n2 – 1= n1+2n2
由此, n0 = n2 + 1 。

满二叉树:指的是深度为k且含有2k – 1 个结点的二叉树。特点:每一层上的结点数都是最大结点数。
完全二叉树:一颗二叉树中所含的 n 个结点与满二叉树中编号为 1 至 n 的结点一一对应(编号和位置一一对应)。
特点:
1.叶子结点只可能在层次最大的两层上出现。
2. 对任一结点,若其右分支下子孙的最大层次为l,则其左分支下子孙的最大层次必为l 或l+1。下面这个就是一个完全二叉树,由定义可知,满二叉树是完全二叉树,反过来则不一定。
在这里插入图片描述

性质4:具有 n 个结点的完全二叉树的深度为:[log2n]+1 。
证明:
设完全二叉树的深度为 k ,则根据第二条性质得 :
2k-1 -1 < n ≤ 2k -1 或 2k-1 ≤ n < 2k ,
两边取对数得: k-1 ≤ log2 n < k ,
因为 k 只能是整数,因此, k =[log2n] + 1 。

性质5
若对含 n 个结点的完全二叉树从上到下且从左至右进行 1 至 n 的编号,则对完全二叉树中任意一个编号为 i 的结点:
(1) 若 i=1,则该结点是二叉树的根,无双亲;否则,编号为 [i/2] 的结点为其双亲结点;
(2) 若 2i>n,则该结点无左孩子结点,否则,编号为 2i 的结点为其左孩子结点;
(3) 若 2i+1>n,则该结点无右孩子结点,否则,编号为2i+1 的结点为其右孩子结点。
在这里插入图片描述

【二叉树的存储结构】:同线性表一样,二叉树有顺序存储和链式存储两种方式。

   二叉树的顺序存储:二叉树的顺序存储表示是用一组连续存储空间(一维数组)依次从上到下、从左到右存储完全二叉树中的所有结点,亦即完全二叉树编号为 i 的结点存到一维数组的第 i-1 的位置中。若该二叉树为非完全二叉树,则必须将相应位置空出来或用0补充,使存放的结果符合完全二叉树形状。为方便存储常需要把二叉树中补充成完全二叉树形状,如下图所示。
在这里插入图片描述
在这里插入图片描述
极端情况:深度为k的二叉树是仅有k个结点的右单分支,需要长度为2k 的一维数组。在这里插入图片描述
可以看出二叉树的顺序存储只适合完全二叉树使用,其它二叉树都会造成内存浪费。

二叉树的链式存储:链式存储分为两种:二叉链表和三叉链表。

二叉链表:因为二叉树的数据元素之间的关系任一个结点,最多有两个孩子(直接后继元素),故设计特别的存储单元,将一个结点分成三部分,一部分存放结点本身数据,另外两部分为指针,分别存放左、右孩子的地址。
在这里插入图片描述
结论:在n个结点的二叉链表中,有n+1个空指针域。因为一个结点有两个指针域,n个结点之间有n-1条线,即n-1个指针域被使用,故有n+1个空的指针域。

结点定义

#define TElemType  char //二叉树的数据元素类型:char
typedef  struct BiTNode { // 结点结构
    TElemType      data;
    struct BiTNode  *lchild, *rchild; 
    // 左右孩子指针
} BiTNode, *BiTree;

讲到这儿了就简单说一下三叉链表,这个比二叉链表稍微多了一点东西,使用频率不太高,但它弥补了二叉链表不容易访问父亲结点的缺陷。

三叉链表在这里插入图片描述
结点定义

typedef struct TriTNode { // 结点结构
      TElemType  data;
      struct TriTNode  *lchild, *rchild;               // 左右孩子指针
      struct TriTNode  *parent;           //双亲指针 
   } TriTNode, *TriTree;

可以看出多了一个指向父亲结点的指针,实现了访问父亲结点的功能。

二叉树的使用及功能太多啦,一个博客实在不容易写完,也不容易消化,我就按照深度把它划分成几个博客的内容了,要了解更多用法,请看下一篇。下一篇会涉及到根据两种遍历方法确定一个二叉树及包含空结点的序列确定一个二叉树等等更多的内容,开始深度剖析二叉树。

猜你喜欢

转载自blog.csdn.net/qq_41809589/article/details/86561854