第 五章 树和二叉树
5.1 树的逻辑结构
树的定义
n(n≥0)个结点的有限集合。当n=0时,称为空树;任意一棵非空树满足以下条件:
⑴有且仅有一个特定的称为根的结点;
⑵当n>1时,除根结点之外的其余结点被分成m(m>0)个互不相交的有限集合T1,T2,… ,Tm,其中每个集合又是一棵树,并称为这个根结点的子树。
树的基本术语:
结点的度:结点所拥有的子树的个数。
树的度:树中各结点度的最大值。
叶子结点:度为0的结点,也称为终端结点。
分支结点:度不为0的结点,也称为非终端结点
孩子、双亲:树中某结点子树的根结点称为这个结点的孩子结点,这个结点称为它孩子结点的双亲结点;
兄弟:具有同一个双亲的孩子结点互称为兄弟。
路径:如果树的结点序列n1,n2, …, nk有如下关系:结点ni是ni+1的双亲(1<=i<k),则把n1,n2, …, nk称为一条由n1至nk的路径;
路径上经过的边的个数称为路径长度。
祖先、子孙:在树中,如果有一条路径从结点x到结点y,则x称为y的祖先,而y称为x的子孙
结点所在层数:根结点的层数为1;对其余任何结点,若某结点在第k层,则其孩子结点在第k+1层。
树的深度:树中所有结点的最大层数,也称高度。
层序编号:将树中结点按照从上层到下层、同层从左到右的次序依次给他们编以从1开始的连续自然数。
有序树、无序树:如果一棵树中结点的各子树从左到右是有次序的,称这棵树为有序树;反之,称为无序树。
森林:m (m≥0)棵互不相交的树的集合
树的遍历:从根结点出发,按照某种次序访问树中所有结点,使得每个结点被访问一次且仅被访问一次。
5.2 树的存储结构
双亲表示法:用一维数组来存储树的各个结点(一般按层序存储),数组中的一个元素对应树中的一个结点,包括结点的数据信息以及该结点的双亲在数组中的下标。
孩子链表表示法:把每个结点的孩子排列起来,看成是一个线性表,且以单链表存储,则n个结点共有n 个孩子链表。这 n 个单链表共有n 个头指针,这 n 个头指针又组成了一个线性表,为了便于进行查找采用顺序存储。最后,将存放n个头指针的数组和存放n个结点的数组结合起来,构成孩子链表的表头数组。
双亲孩子表示法
孩子兄弟表示法
5.3二叉树的逻辑结构
二叉树是n(n≥0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树的二叉树组成。
特点
⑴每个结点最多有两棵子树;
⑵二叉树是有序的,其次序不能任意颠倒。
二叉树的基本形态:空二叉树
只有一个根结点
根结点只有右子树
根结点只有左子树
根结点同时有左右子树
特殊的二叉树:斜树
满二叉树
完全二叉树
二叉树的基本性质
性质5-1二叉树的第i层上最多有2i-1个结点(i≥1)。
性质5-2 一棵深度为k的二叉树中,最多有2k-1个结点,最少有k个结点。
性质5-3 在一棵二叉树中,如果叶子结点数为n0,度为2的结点数为n2,则有:n0=n2+1。
性质5-4 具有n个结点的完全二叉树的深度为 log2n +1。
性质5-5 对一棵具有n个结点的完全二叉树中从1开始按层序编号,则对于任意的序号为i(1≤i≤n)的结点(简称为结点i),有:
(1)如果i>1,则结点i的双亲结点的序号为 i/2;如果i=1,则结点i是根结点,无双亲结点。
(2)如果2i≤n,则结点i的左孩子的序号为2i;
如果2i>n,则结点i无左孩子。
(3)如果2i+1≤n,则结点i的右孩子的序号为2i+1;如果2i+1>n,则结点i无右孩子。
二叉树的遍历:指从根结点出发,按照某种次序访问二叉树中的所有结点,使得每个结点被访问一次且仅被访问一次。
5.4二叉树的存储结构及实现
顺序存储结构
二叉树的顺序存储结构就是用一维数组存储二叉树中的结点,并且结点的存储位置(下标)应能体现结点之间的逻辑关系——父子关系。
二叉链表:令二叉树的每个结点对应一个链表结点,链表结点除了存放与二叉树结点有关的数据信息外,还要设置指示左右孩子的指针。
三叉链表:在二叉链表的基础上增加了一个指向双亲的指针域
中序线索链表的建立——构造函数
1.建立二叉链表,将每个结点的左右标志置为0;
2.遍历二叉链表,建立线索;
2.1 如果二叉链表root为空,则空操作返回;
2.2 对root的左子树建立线索;
2.3 对根结点root建立线索;
2.3.1 若root没有左孩子,则为root加上前驱线索;
2.3.2 若root没有右孩子,则将root右标志置为1;
2.3.3 若结点pre右标志为1,则为pre加上后继线索;
2.3.4 令pre指向刚刚访问的结点root;
2.4 对root的右子树建立线索。
5.5 二叉树遍历的非递归算法
二叉树前序遍历的非递归算法:在前序遍历过某结点的整个左子树后,如何找到该结点的右子树的根指针。
解决办法:在访问完该结点后,将该结点的指针保存在栈中,以便以后能通过它找到该结点的右子树。
5.6 树、森林与二叉树的转换
树转换为二叉树
⑴加线——树中所有相邻兄弟之间加一条连线。
⑵去线——对树中的每个结点,只保留它与第一个孩子结点之间的连线,删去它与其它孩子结点之间的连线。
⑶层次调整——以根结点为轴心,将树顺时针转动一定的角度,使之层次分明。
森林转换为二叉树
⑴将森林中的每棵树转换成二叉树;
⑵从第二棵二叉树开始,依次把后一棵二叉树的根结点作为前一棵二叉树根结点的右孩子,当所有二叉树连起来后,此时所得到的二叉树就是由森林转换得到的二叉树。
二叉树转换为树或森林
⑴加线——若某结点x是其双亲y的左孩子,则把结点x的右孩子、右孩子的右孩子、……,都与结点y用线连起来;
⑵去线——删去原二叉树中所有的双亲结点与右孩子结点的连线;
⑶层次调整——整理由⑴、⑵两步所得到的树或森林,使之层次分明。
5.7 哈夫曼树及哈夫曼编码
哈夫曼树:给定一组具有确定权值的叶子结点,带权路径长度最小的二叉树。
哈夫曼树应用——哈夫曼编码
前缀编码:一组编码中任一编码都不是其它任何一个编码的前缀。
前缀编码保证了在解码时不会有多种可能。