前言
我们好久没有更新数据结构的博文了,今天来更新一期树!前几期我们已经介绍了顺序表、链表,栈和队列等基本的线性数据结构并对其分别做了实现,本期我们再来介绍一个灰常重要的非线性基本结构 ---- 树型结构。
本期内容介绍
树的概念和结构
二叉树的概念和结构
一、树的概念和结构
树的概念
树是一种非线性(逻辑上非连续)的数据结构,它是由n(n >= 0)个有限结点组成的一个具有层次关系的集合!把他称为树是因为它的逻辑结构和一颗倒挂的树相似!
注意点:
(1)树中有一个特殊的结点被称为根节点,根节点没有前驱结点
(2)除了根节点以外,其余结点被分成了M(M > 0)个互不相交的集合(即子树之间不能相交)!其中每个集合又是一颗结构与树类似的子树!每颗子树的根结点有且只有一个前驱,可以有0个或多个后继!
所以综上树是更合适用递归定义的!
OK,画个图来理解一下:
注意:
树形结构中,子树与子树是不能相交的,如果相交就是我们后期介绍的图了!
除了根结点外,其余结点有且只有一个父节点
一个N个节点的树有N-1条边
树的相关概念
节点的度:一个节点含有的子树的个数被称为该节点的度;
叶子节点(终端节点):度为0的节点称为叶子结点;
非终端节点(分支节点):度不为0的节点;
父亲节点(双亲节点):若一个节点含有子节点,则这个节点称为其子节点的父节点;
子节点(孩子节点):一个节点含有的子树的根节点称为该节点的子节点;
兄弟节点:具有相同父节点的节点互称为心底节点;
树的度:一棵树中,最大节点的度被称为树的度。
节点的层次:从根节点开始定义第一层,根的子节点为第二层,依次类推!
树的高度(深度):树中节点的最大层次;
堂兄弟节点:双亲在同层的节点互成称堂兄弟节点;
节点的祖先:从根到该节点所经分支上的所有节点;
子孙:以某节点为根的子树中任一节点都称为该节点的子孙;
森林:由m(m>0)棵互不相交的树的集合称为森林;
树的表示
树结构相较于线性结构就复杂了,要存储起来也比较麻烦!既要存储值域,也要存储结点之间的关系!树的表示方式有很多种例如:双亲表示法、孩子表示法、孩子双亲表示法、孩子双亲表示法!
这里大概介绍一下,后面重要的会在介绍例如双亲表示法(并查集)和孩子表示法(图的邻接表)!
双亲表示法是:用数组存储每个节点,每个节点中存入他们的父亲节点的下标!
孩子表示法:采用顺序表个链表进行存储,顺序表存各个节点,每个节点中保存第一个孩子的头指针
这些其实都不是最优结构,最优结构是下面我要介绍的这个----孩子兄弟表示法!
孩子兄弟表示法:有两个指针域和一个数据域。一个是孩子指针域,另一个是兄弟指针域!只要是当前节点的孩子就挂到孩子节点后面,如果是兄弟节点则挂到兄弟节点的后面,这样就可以把非二叉树转换为二叉树来处理了!
typedef char DataType;
struct Node
{
struct Node* _LeftChild;
struct Node* _RightBother;
DataType _data;
};
树结构在现实中的应用
树这种结构其实在现实中应用的地方不多,最典型的就是文件系统的目录结构!
这就是Linux下的一个文件目录系统结构,他就是一棵多叉树!
二、二叉树的概念和结构
二叉树的概念
二叉树:度至多为2的树,被称为二叉树!
注意:这里是至多,也就是说度可以为0,1 , 2都可以!
二叉树是由一个根节点和左右子树构成的!
二叉树有左右之分!次序不能颠倒!
二叉树的5种特殊情况:
所有的二叉树都是由以上5中组成的!
特殊的二叉树
满二叉树:一个二叉树,如果每一层的节点数都达到最大值,则称该二叉树为满二叉树!(也就是说如果一个二叉树有K层它的节点总数是:2^k - 1就说明他是满二叉树)
完全二叉树:对于深度为K,节点数是n的二叉树,当且仅当每一个节点与深度为K的那一层的每一个编号都对应(也就是说前K-1层是满的,第K层按序号依次存放的)的树被称为完全二叉树!也就是说满二叉树实际上是完全二叉树的特例
OK,画个图理解一下:
完全二叉树是很有用的!后面我们玩的堆、堆排序、TopK问题都是基于完全二叉树实现的!
二叉树的性质
(1)若规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1)个节点
(2)若规定根节点的层数为1,则一棵高度为h的二叉树的最大节点数是2^(h) - 1
(3)若规定根节点的层数为1,则具有n个节点的满二叉树的深度h = log2(N+1)
(4)对于任意一棵二叉树,假设度为0的节点(叶子结点)的个数为n0,度为2的节点的个数为n2,则有n0 = n2 + 1
(5)对于高度为h的二叉树的节点范围是[2^(h-1), 2^(h)-1]
(6)对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于序号为i的结点有:
若i > 0,位置节点的双亲下标为:(i-1)/2,根节点无双亲
若2i+1 < n, 则左孩子的下标为2i+1,否则如果2i+1 >= n则无左孩子
若2i+1 < n, 则右孩子的下标为2i+2,否则如果2i+2 >= n则无右孩子
二叉树的存储
二叉树的存储一般分为:顺序存储和链式存储两种~!
1、顺序存储
顺序存储就是用数组来存储,一般的二叉树都是不适合用数组存的,因为会有空间的浪费,只有完全二叉树才适合用数组来存储!堆就是这样搞的(后面会介绍)!二叉树用数组存储(顺序存储)在物理上是一个数组,在逻辑上是一棵二叉树!
2、链式存储
二叉树的链式存储是指,用链表表示(存储)一棵二叉树,也就是用链表来指示各个节点的逻辑关系!一般每个节点都有三个域,一个数据域,两个指针域(左右指针域),它两分别指向二叉树的左右节点。链式存储又可以分为二叉链和三叉链,我们这里玩的是二叉链,三叉连后期在介绍,他是玩那个红黑树的!
typedef char BTDataType;
typedef struct BinaryTreeNode
{
BTDataType datal;
struct BinaryTreeNode* left;
struct BinaryTreeNode* right;
}BT;
OK,本期二叉树的基础知识就介绍到这里,我们下期再来对顺序存储和链式存储来实现!