二叉树
- 定义
二叉树是n(n>=0)个结点的有限集合,该集合或者为空集(称为空 二叉树),或者由一个根节点和两个互不相交的,分别称为根节点的左子树和右子树组成 - 二叉树的特点
- 最多有两棵子树
- 左子树和右子树都是有顺序的,次数不能随意颠倒
- 即使树中某个结点只有一棵子树,也要区分它是左子树还是右子树
- 二叉树的五种基本形态
- 空二叉树
- 只有一个根结点
- 只有左子树
- 只有右子树
- 满二叉树(既有左子树又有右子树)
特殊的二叉树
- 斜树: 顾名思义,斜树就是斜着的树,所有的结点都只有左子树的二叉树叫左斜树,所有的结点都只有右子树的二叉树叫右斜树,这两者统称为斜树
特点:斜树有一个很明显的特点,就是每一层都只有一个结点,结点的个数与二叉树的深度相同(线性表结构就可以理解为是是树的一种极其特殊的树的表现形式) - 满二叉树: 在一颗二叉树中,所有的分支结点都存在左子树和右子树,并且所有的叶子结点都在同一层上,这样的二叉树叫做满二叉树
特点:叶子结点只能出现在最下一层,出现在其他层就不可能达到平衡了;非叶子节点的度一定是2;在同样深度的二叉树中,满二叉树的结点个数最多,叶子数最多 - 完全二叉树:对于一棵有n个结点的二叉树按层序编号,如果编号为i(1<=i<=n)的结点与满二叉树的编号为i的结点在二叉树中的位置完全相同,则这棵二叉树称为完全二叉树
特点: 叶子结点只能出现在最下两层;最下层的叶子一定集中在左部连续位置;倒数第二层,若存在叶子结点,一定都在右部连续位置;如果结点度为1,该结点只有左 孩子,即不存在只有右子树的情况;同样结点数的二叉树,完全二叉树的深度最小
二叉树的性质
- 在二叉树的i层上,至多右2i-1个 结点
- 深度为k的二叉树至多有2k-1个结点
- 对于任何一颗2叉树T,如果其终端结点(叶子结点)数为n0,度为2的结点数为n2,那就有 n0 = n2+1
- 具有n个结点的完全二叉树的深度为[log2n]+1([x]表示不大于x的最大整数)
- 对于一棵有n个结点的完全二叉树(其深度为[log2n]+1)按层序编号(从第一层到[log2n]+1层,每层从左到右),对于任一结点i(1<=i<=n)有:
- 如果i=0,则 i是根节点,无双亲,若i>=1,则其双亲的结点是[i/2]
- 如果2i > n ,则 结点i无左孩子(i结点为叶子结点),否则其左孩子是2i
- 如果2i+1 > n,则结点i无右孩子,否则其右孩子为2i+1
二叉树的存储结构
- 二叉树的顺序存储结构,就是用一维数组存储二叉树中的结点,并且结点的存储位置,也就是数组的下标要能体现结点之间的逻辑关系,比如双亲与孩子的关系,左右兄弟的关系等
- 对于完全二叉树来说
- 对于一般二叉树来说,我们也可以按照满二叉树的编号进行排列,只要把不存在的点用’ ^ ‘表示(’ ^ '只是一种表示,说没有结点存储)
考虑一种极端情况,若一棵深度为k的右斜树,它只有k个结点,但是要分配2k-1个存储空间,显然是很浪费存储空间的,所以顺序结构一般只存储完全二叉树
- 对于完全二叉树来说
- 二叉链表
顺序结构的适用性不强,那么就考虑链式存储结构,二叉树的每个结点有两个孩子,所以它设计一个数据域和两个指针域是比合理的,我们称这样的链表为二叉链表
示意图如下:
遍历二叉树
- 定义
二叉树的遍历(traversing binary tree)是指从根节点出发,按照某种次序,依次访问二叉树中的所有结点,使得每个结点被访问一次且仅被访问一次 - 二叉树的遍历方式
- 前序遍历
规则是若二叉树为空,则空操作返回,否则先访问根节点,然后前序遍历左子树,然后前序遍历右子树
- 中序遍历
规则是若树为空,则返回空操作,否则从根节点开始(注意: 并不是首先访问根节点),中序遍历左子树,然后是访问根节点,最后中序遍历右子树
- 后序遍历
规则是若树为空,返回空操作,否则从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根节点
- 层序遍历
规则是若树为空,则空操作返回,否则从树的第一层,也就是根节点开始访问,从上而下逐层遍历,在同一层中,按从左到右的顺序逐个访问
- 前序遍历
推导遍历结果
- 已知前序遍历和中序遍历,可以确定唯一一棵二叉树
- 已知后序遍历和中序遍历,可以确定唯一一棵二叉树
- 只知道前序遍历和后序遍历确定不了唯一一棵二叉树
推导的技巧: 把几个结点当成一个整体来考虑其合理性,然后在逐个考虑(就不举例了,多做几道题就会了)
树,森林,二叉树的转换
- 将树转换为二叉树
- 加线,在所有兄弟结点之间加一条线
- 对树中的每一个结点,只保留它与第一个孩子结点的连线,删除他与其他孩子结点的连线
- 层次调整,以树的根节点为轴心,将整棵树顺时针调整一定的角度,使之结构层次分明,注意第一个孩子是二叉树结点的左孩子,兄弟转换过来的孩子是结点的右孩子
- 森林转换为二叉树
森林是由若干棵树组成的,所以可以理解为森林中的每一棵树都是兄弟,可以按照兄弟的处理方法来操作- 把每棵树转化为二叉树
- 第一棵二叉树不动,从第二棵二叉树开始,依次把后一棵二叉树的根节点作为前一棵二叉树根节点的右孩子,用线连起来,当所有的二叉树连起来就得到了由森林转换来的二叉树
- 二叉树转换为树
二叉树转换为树,是树转换为二叉树的逆过程,也就是反过来做而已- 加线,若某结点的左孩子结点存在,则将这个左孩子结点的右孩子结点,右孩子结点的右孩子结点,右孩子结点的右孩子结点…反正就是左孩子结点的n个右孩子结点都作为此结点的孩子,将该结点与这些右孩子结点依次用线连起来
- 去线,删除原二叉树中所有结点与其右孩子结点的连线
- 层次调整,使之层次结构分明
- 二叉树转换为森林
判断一棵二叉树能够转换为树还是转换为森林,标准很简单,那么就是看这个二叉树根节点上有没有右孩子,有就是森林,没有就是一棵树,转换成森林步骤如下- 从根节点开始,若右孩子存在,则把与右孩子结点的连线删除,在查看分离后的二叉树,若右孩子存在,则连线删除,直到所有右孩子的连线都删除为止,得到分离的二叉树
- 在将每棵分离的二叉树转换为树即可
树与森林的遍历
- 树的遍历分为两种形式
- 先根遍历,先访问树的根结点,在依次遍历树的每棵子树
- 后根遍历,先依次遍历每棵子树,然后在访问根结点
- 森林的遍历也是两种形式
- 前序遍历,先访问森林中的根节点,然后在依次先根遍历每棵子树,在依次用同样的方式遍历除去第一棵树,其他树组成的森林
- 后序遍历,先访问森林中的第一棵树,后序遍历每棵子树,然后在访问根节点,在依次用同样的方式遍历除去第一棵树其它树组成的森林
赫夫曼树及其应用
-
定义
赫夫曼树又称最优二叉树,是一种带权路径长短最短的二叉树,所谓的带权路径长度就是树中所有叶结点的权值乘上其到根节点的路径长度(若根节点为0层,叶节点到根节点的路径长度为叶节点的层数),树的路径长度是根节点到每一个叶子结点的路径长度之和记作WPL
-
构建赫夫曼树的方法
- 根据给定的n个权值{w1,w2,w3,…wn}构成的n棵二叉树的集合F={T1,T2,T3,…Tn},其中每棵二叉树Ti中只有一个带权为wi的根节点,其左右子树均为空
- 在F中选择两个权值较小的结点构成一个新的二叉树,二叉树的根节点的 权值是两个较小的权值之和,然后将新构成的权值放进F中,相对应的刚刚取出来的两个较小的权值就成为了新权值的一部分(较小的权值为左结点),也就是说在F中删除掉刚刚取出来的两个权值较小的二叉树
- 重复 步骤2,直到只剩下一棵树为止
-
赫夫曼树的应用就是赫夫曼编码
本文是学习大话数据结构的学习笔记