树和二叉树
树是一类重要的非线性数据结构,是以分支关系定义的层次结构。
1 树的定义
- 定义:树(tree)是n(n>0)个结点的有限集T,其中:
有且仅有一个特定的结点,称为树的根(root)
当 n>1 时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,……Tm,其中每一个集合本身又是一棵树,称为根的子树(subtree) 。 - 特点:
树中至少有一个结点——根
树中各子树是互不相交的集合
- 基本术语
结点(node)——表示树中的元素,包括数据项及若干指向其子树的分支
结点的度(degree)——结点拥有的子树数
叶子(leaf)——度为0的结点
孩子(child)——结点子树的根称为该结点的孩子
双亲(parents)——孩子结点的上层结点叫该结点的双亲
兄弟(sibling)——同一双亲的孩子
树的度——一棵树中最大的结点度数
结点的层次(level)——从根结点算起,根为第一层,它的孩子为第二层
深度(depth)——树中结点的最大层次数
森林(forest)——m(m>=0)棵互不相交的树的集合
2. 二叉树
2.1 二叉树定义
- 定义:二叉树是n(n>=0)个结点的有限集,它或为空树(n=0),或由一个根结点和两棵分别称为左子树和右子树的互不相交的二叉树构成。
- 特点
每个结点至多有二棵子树(即不存在度大于2的结点)
二叉树的子树有左、右之分,且其次序不能任意颠倒。 - 基本形态
2.2 二叉树性质
性质1:在二叉树的第 i 层最多有 2i-1 个结点(i>=1)。
性质2:深度为k的二叉树至多有 2k-1 个结点(k>=1)。
性质3:对任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0=n2+1。
- 两种特殊的二叉树
1.满二叉树:
定义:一颗深度为k的2^k +1^个结点的二叉树称为满二叉树。
特点:每一层的结点数都是最大结点数。
2.完全二叉树:
定义:深度为k,有n个结点的二叉树当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时,称为完全二叉树。
特点:叶子结点只可能在层次最大的两层上出现。对任一结点,若其右分支下子孙的最大层次为L,则其左分支下子孙的最大层次必为L或L+1
。
性质4:具有n个结点的完全完全二叉树的深度为 (log2n)+1。
性质5:如果对一棵有n个结点的完全二叉树的结点按层序编号,则对任一结点i(1<=i<=n),有:
(1) 如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是i/2。
(2) 如果2i>n,则结点i无左孩子;如果2i<=n,则其左孩子是2i。
(3) 如果2i+1>n,则结点i无右孩子;如果2i+1<=n,则其右孩子是2i+1。
3. 树的存储结构
3.1 双亲表示法
实现:定义结构数组存放树的结点,每个结点含两个域:
数据域:存放结点本身信息
双亲域:指示本结点的双亲结点在数组中位置
特点:找双亲容易,找孩子难
#define M 256
typedef struct node
{
int data;
int parent;
}JD;
JD t[M];
3.2 孩子表示法
多重链表:每个结点有多个指针域,分别指向其子树的根
结点同构:结点的指针个数相等,为树的度D
结点不同构:结点指针个数不等,为该结点的度d
child1 | child2 | child3 | child4 | … | childD |
---|
data | degree | child1 | child2 | … | childd |
---|
孩子链表:每个结点的孩子结点用单链表存储,再用含n个元素的结构数组指向每个孩子链表
孩子结点:typedef struct node
{
int child; //该结点在表头数组中下标
struct node *next; //指向下一孩子结点
}JD;
表头结点:typedef struct tnode
{
int data; //数据域
struct node *fc; //指向第一个孩子结点
}TD;
TD t[M]; //t[0]不用
3.3 孩子兄弟表示法(二叉树表示法)
实现:用二叉链表作树的存储结构,链表中每个结点的两个指针域分别指向其第一个孩子结点和下一个兄弟结点。
特点
操作容易
破坏了树的层次
typedef struct node
{
int data;
struct node *fch, *nsib;
}JD;
3.4 顺序存储结构
实现:按满二叉树的结点层次编号,依次存放二叉树中的数据元素
特点:
结点间关系蕴含在其存储位置中
浪费空间,适于存满二叉树和完全二叉树
3.5 链式存储结构
二叉链表:
typedef struct node
{
int data;
struct node *lchild, *rchild;
}JD;
在n个结点的二叉链表中,有n+1个空指针域
三叉链表
typedef struct node
{
int data;
struct node *lchild,*rchild,*parent;
}JD;
4. 树与二叉树转换
4.1 将树转换成二叉树
加线:在兄弟之间加一连线
抹线:对每个结点,除了其左孩子外,去除其与其余孩子之间的关系
旋转:以树的根结点为轴心,将整树顺时针转45°
树转换成的二叉树其右子树一定为空
4.2 将二叉树转换成树
加线:若p结点是双亲结点的左孩子,则将p的右孩子,右孩子的右孩子,……沿分支找到的所有右孩子,都与p的双亲用线连起来
抹线:抹掉原二叉树中双亲与右孩子之间的连线
调整:将结点按层次排列,形成树结构
4.3森林转换成二叉树
将各棵树分别转换成二叉树
将每棵树的根结点用线相连
以第一棵树根结点为二叉树的根,再以根结点为轴心,顺时针旋转,构成二叉树型结构
4.4 二叉树转换成森林
抹线:将二叉树中根结点与其右孩子连线,及沿右分支搜索到的所有右孩子间连线全部抹掉,使之变成孤立的二叉树
还原:将孤立的二叉树还原成树