树形结构
1.二叉树
- 祖先节点:根A到根节点K的唯一路径上的任意节点,称为结点K的祖先结点。
- 度:树中一个结点的子结点个数称为该结点的度,树中结点的最大度树称为树的度。
- 层:根开始,根节点为第一层,子节点为第二层
- 深度:根节点开始自顶向下逐层累加的
- 高度:叶节点开始自底向上逐层累加的
- 高度:树中节点的最大层数
-
1.2特殊的二叉树
1.2.1满二叉树
高度为h,2^-1个结点。如果有双亲,那么双亲为[i/2];如果有左孩子,那么为2i,右孩子有2i+1。
1.2.2完全二叉树
1.2.3二叉树排序树
左子树上所有结点的关键字均小于根结点的关键字;右子树上所有结点关键字均大于根结点关键字。左右子树又各是一棵二叉排序树。
1.2.4平衡树排序树
树上任意结点的左子树与右子树深度之差不超过1;
- 性质:
- N0=N2+1;(度为0 的点=叶子节点数+1);
- 第K层是最多2^(k-1)个节点;
- 高度为H的二叉树最大多为2^H-1个节点;
2.二叉树的存储结构
2.1.顺序存储结构
二叉树的顺序存储结构就是用一组地址连续的存储单元依次自上而下、自左而右存储完全二叉树上的结点元素,即将完全二叉树上编号为i的结点单元元素存储在某个数组下标为i-1的分量中,然后通过一些方法来确定结点在逻辑上的父子与兄弟关系。
完全二叉树与满二叉树采用顺序存储比较合适。
2.2.链式存储结构
采用链表来存储一颗二叉树,二叉树中每一个结点用链表的一个链结点来存储。在二叉树中,结点结构通常包含若干数据域和若干个指针域。二叉链表至少包含3个域:数据域、左指针域lchild、右指针域rchild
2.3二叉树的遍历
按照某条搜索路径访问树中的每个结点,使得每个结点均别访问一次,而且仅被访问一次。
2.3.1先序遍历
void PreOrder(BiTree T){ if(T!=NULL){ Visit(T); PreOrder(T->lchild); PreOrder(T->rchild); } }
已知前序和中序遍历序列,可以唯一确定一颗二叉树;
已知后序遍历序列和中序遍历序列,可以唯一确定一颗二叉树。2.4线索
指向前驱和后继的指针称为线索,加上线索的二叉链表称为线索链表,相应的二叉树就称为线索二叉树(Thread Binary Tree)。
3.树和森林
森林是由若干棵树组成的,所以可以理解成:森林中的每一棵树都是兄弟,可以按照兄弟的处理办法来操作。
步骤如下:
1.把每一棵树转换成二叉树;
2.第一棵二叉树不动,从第二棵二叉树开始,依次把后一棵二叉树的根节点作为前一棵二叉树的根节点的右孩子,用线连接起来。当所有的二叉树连接起来后就得到了由森林转换来的二叉树。3.1
二叉树转换成森林:判断一棵二叉树能够成为一棵树还是森林,就是看这棵二叉树的根节点有没有右孩子,有就是森林,没有就是一棵树。
3.2树与森林的遍历
树的遍历分为2种:
1.先根遍历树,即先访问树的根节点,然后依次先根遍历根的每棵子树;
2.后根遍历,即先依次后根遍历每棵子树,然后在访问根节点。
森林的遍历分为2种:
1.前序遍历:
2.后序遍历:4.赫夫曼树
路径长度:从树中一个结点到另一个结点之间的分支构成2个结点之间的路径,路径上的分支数目称为路径长度。
赫夫曼树:带权路径长度WPL最小的二叉树称为赫夫曼树。4.1赫夫曼树的构造
1.先把有权值的叶子结点按照从小到大的顺序排列成一个有序序列,即A5,E10,B15,D30,C40;
2.取头两个最小权值的结点作为一个新结点N1的两个子结点,注意相对小的是左孩子,这里A就是左孩子,E就是N1右孩子。新结点的权值为两个叶子权值的和5+10=15;
3.将N1替换A与E,插入有序序列中,保持从小到大排列。即N1 15,B15,D30,C40;
4.重复步骤2,将N1与B作为一个新结点N2的两个子节点。因此,构造赫夫曼树的赫夫曼算法描述为:
1.根据给定的n和权值{w1,w2,w3,w4…wn}构成n棵二叉树的集合F={T1,T2,T3…Tn},其中每棵二叉树Ti中只有一个带权为wi根节点,其左右子树都为空;
2.在F中选取两棵根节点的权值最小的树作为左右子树构造一棵新的二叉树,且置新的二叉树的根节点的权值为其左右子树上根节点的权值之和。
3.在F中删除这2棵树,同时将新得到的二叉树插入到F中。
4.重复2,3,直到F合成一棵树为止。一般来说设需要编码的字符集{d1,d2,d3,…dn},各个字符在电文中出现的次数或频率集合为{w1,w2,…wn},以d1,d2,dn作为叶子节点,以{w1,w2,…wn}作为相应叶子结点的权值来构造一课赫夫曼树。赫夫曼树的左分支代表0,右分支代表1,则从根节点到叶子节点所经过的路径分支组成的0和1的序列便是该结点对应字符的编码,这就是赫夫曼编码。