=============
树是一种非线性结构
树的表示法:
1):树形表示法
2):括号表示法
3):文氏图表示法
4):凹入表示法
=============
二叉树:
树与二叉树的区别:
1):树中结点的最大度数没有限制,二叉树结点的最大度数为2
2):树中的结点无左右之分,二叉树有
满二叉树:深度为k且具有2k-1个结点的树
完全二叉树:深度为k且每个结点与同深度的满二叉树的编号一一对应
二叉树的性质:
1:第i层上至多有2i-1个结点(i>=1)
2:深度为k的二叉树中至多有2k-1个结点(k>=1)
1+2+22+23+..+2k-1 等比求和=2k-1
3:对于一颗非空二叉树,叶子结点个数为n0,度为2的结点个数为n2,度为1的结点个数为n1
n0=n2+1
总的结点个数为n,n=n0+n1+n2。
边的总数为B,B=n-1
又边是由度为1和度为2的结点发出的,B=n1+n2
所以 n0=n2+1
4:具有n个结点的完全二叉树的高度k为⎿log2n⏌+1
2k-1-1<n≤2k-1
5:对于有n个结点的完全二叉树,它们的编号满足:
如果i=1,则i是根节点,它没有双亲结点。如果i>1,那么它的双亲结点为i/2。
如果2i≤n,则i的左孩子结点为2i。
如果2i+1≤n,则i的右孩子结点为2i+1。
二叉树的存储结构:
顺序存储//
采用一位数组来存放二叉树的结点,只要通过数组元素的下标关系就可以确定二叉树结点间的逻辑关系
适合满二叉树和完全二叉树,它能充分利用存储空间。
链式存储//
用链表存储二叉树时,每个结点除了存储本身的数据域外,还设置了两个指针域lchild和rchild,分别指向该结点的左孩子和右孩子
有n个结点的二叉链表中,一共有2n个指针域,其中只有n-1个用来指向结点的左右孩子,其余的n+1个指针域为空。
求根和左右孩子比较容易实现,但求双亲的运算实现却比较麻烦
三叉链表//
比二叉链表的结点多了一个指针域,用于存储一个指向其双亲的指针
二叉树的遍历
遍历的递归算法
先序:根左右
中序:左根右
后序:左右根
非递归:设一个辅助栈来保存所经过的结点的地址
应用:统计二叉树中叶子结点的个数
求二叉树的深度
建立二叉树的链式存储结构
由结点先序序列和中序序列构造对应的二叉树
(只有先序序列和后序序列不能唯一确定一颗二叉树)
线索二叉树:
在有n个结点的二叉链表中,一共有2n个指针域,其中只有n-1个用来指向结点的左右孩子,其余的n+1个指针域为空。
现在把这些空域利用起来,存放指向结点的前趋或后继指针,这样的指针称为线索。
为了区分是指向左右孩子还是指向前趋和后继的指针,在原结点的基础上,增加两个标志域。
ltag=0,lchild为左指针,指向左孩子
ltag=1,lchild为左线索,指向前趋
rtag=0,rchild为右指针,指向右孩子
rtag=1,rchild为右线索,指向后继
对二叉树以某种遍历的方式使其加上线索的过程称为线索化。
有先序线索树,中序线索树,后序线索树。
实现为指针,指向左右孩子,虚线为线索,指向前趋后后继。
===============
树和森林
树的存储结构
双亲表示法:
用一维数组存储树中的每个结点,每个结点含有两个域:一是数据域,二是双亲域
parent域=-1,表示该结点无双亲结点,即根节点
孩子链表表示法:
用一维数组存储树中的每个结点,每个结点含有两个域:一是数据域,二是指针域,指针域指向,由该结点的孩子组成的单链表的首结点
单链表的结构也由两个域组成:一个存放孩子结点在一位数组中的序号,另一个是指针域,指向下一个孩子结点
孩子兄弟表示法:
树结点中设两个指针,分别指向最左孩子结点和紧邻的右兄弟结点,分别用firstchild和nextsibling
查询一个结点的所有孩子,先通过firstchild找到它的第一个孩子,再通过第一个孩子的nextsibling找到它的兄弟,再沿着nextsibling找下去,直到nextsibling为空
森林与二叉树的转换
先将树转换为孩子兄弟表示法的存储结构,将第二棵树作为第一颗树的根节点的nextsibling,将第三棵树作为第二棵树的nextsibling....
树和森林的遍历
先根遍历树:先访问树的根节点,然后依次先根遍历根每棵子树
后根遍历:先依次后根遍历每棵子树,然后访问根节点
和树对应的二叉树:左子树是孩子,右子树是兄弟
===============
哈夫曼树
带权路径长度最短的二叉树
构造哈夫曼树