目录
树结构是一类重要的非线性数据结构。
树的定义
树是n个节点的有限集,可以为空(n=0);
当n≠0时:
1.有且仅有一个根节点
2.除根节点外,其余节点可分为m(m>0)个互不相交的有限集,其中每个集合又是一棵树,称为根的子树;
PS.树的结构定义是一个递归的定义,即在树的定义有用到树的定义。
基本术语
结点:树中的独立单元;
结点的度:结点拥有的子树;
树的度:各结点度的最大值;
叶子\终端结点:度为0的结点;
非终端结点:度不为0;
双亲和孩子:结点的子树根称为该节点的孩子,该结点为孩子的双亲;
兄弟:同一个双亲的孩子之间互称兄弟;
祖先:从根到该结点所经分支上所有结点;
子孙:以某一结点为根的子树中的所有结点;
层次:从根开始定义,每一层加一;
堂兄弟:双亲在同一层的结点;
树的深度:树中结点的最大层;
有序树:树中结点个子树,从左至右有顺序,不能互换;
无序树:...
森林:m(m>=0)棵互不相交的树的集合;
二叉树
性质解释:
性质1:二叉树每个结点上最多连两棵树,所以第i层的最大结点数是第i-1层上的2倍,以此类推;
性质2:将每一层最大结点数相加;
性质3:设二叉树结点总数为n,二叉树的度小于等于2,设n1为度为1的结点,n2度为2的结点,n0度为0、也就是叶子结点;
n=n0+n1+n2;
除了根结点,每个结点连有一个双亲,所有边数为2*n2+n1=n-1;
n=2*n2+n1+1=n0+n1+n2;
n0=n2+1;
性质4:2^(k-1)<=n<2^k;
顺序存储
从根起,按层序存储,自上而下,从左到右;
这种存储结构只适用于完全二叉树,对于一般二叉树,更适合链式存储;
链式存储
二叉树的遍历
1.先序遍历递归算法
void PreorderTraverse(BiTree T){
if(T){
cout<<T->data;
PreorderTraverse(T->lchild);
PreorderTraverse(T->rchild);
}
}
2.中序遍历递归算法
void InOrderTraverse(BiTree T){
if(T){
InOrderTraverse(T->lchild);
cout<<T->data;
InOrderTraverse(T->rchild);
}
}
3.后序遍历递归算法
void PostorderTraverse(BiTree T){
if(T){
PostorderTraverse(T->lchild);
PostorderTraverse(T->rchild);
cout<<T->data;
}
}
线索二叉树
树和森林
树的存储结构
1.双亲表示法
以一组连续的存储单元存储树的结点,每个结点除了数据域data外,还有一个parent域指示双亲结点的位置。
2.孩子表示法
由于树的每个结点可能有多棵子树,则可用多重链表,即每个结点多个指针域,其中每个指针指向一棵子树的根节点。
PS,孩子表示法便于涉及孩子操作的实现,双亲表示法则便于双亲的实现。
3.孩子兄弟法
又称二叉树表示法,或二叉链表表示法,即以二叉链表做树的存储结构。链表中结点的两个链域分别指向该结点的第一个孩子节点和下一个兄弟结点(左孩子,右兄弟)。
便于将一般的树转换成为二叉树进行操作,利用二叉树的算法实现对树的操作。
森林与二叉树的转换
森林转换成二叉树
1.加线:在兄弟之间加一连线;
2.断线:对每个结点,除了其左孩子,除去与其它孩子的连线;
3.旋转:将树转换成二叉树;
二叉树转换成森林
1.断线:从根节点开始,每个结点与右孩子的连线断开;
2.加线:断开的右孩子作为兄弟结点与双亲相连;
3.旋转:二叉树转换为树;
哈夫曼树及其应用
基本概念
哈夫曼树又称最优树,是一类带权路径长度最短的树。
1.路径:从一个结点到另一个结点的分支;
2.路径长度:路径上的分支数目;
3.树的路径长度:从树根到每一个路径长度之和;
4.权:对结点赋值,这棵树为带权树;
5.结点的带权路径长度:从该结点到树根之间的路径长度与结点上权的乘积;
6.树的带权路径长度:所有叶子结点的带权路径长度和;
PS,在哈夫曼树中,权值越大的结点离根节点越近;
哈夫曼编码
基本概念
1.前缀编码:在一个编码方案中,任何一个编码都不是其他编码的前缀,则该编码为前缀编码;
2.哈夫曼编码:将哈夫曼树的每个左分支赋0,右分支赋1(左0右1),则从根到每个叶子的路径上,各分支赋值分别构成一个二进制编码;
哈夫曼编码的两个性质
1.哈夫曼编码是前缀编码;
2.哈夫曼编码是最优前缀编码;