数据结构:树
数据结构–树类型及树的基本概念
http://blog.csdn.net/xiaojie_570/article/details/53894362
树(Tree)
是一种“一对多“的数据结构,是n(n>=0)个结点的有限集,n=0时称为空树。
在任意一棵非空树中:
1)有且仅有一个特定的称为根(root)的结点。
2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,….,Tm, 其中每一个集合本身又是一棵树,并且称为根的子树(SubTree)
根: 树的顶端结点
结点的子树的根称为该结点的孩子(Child),该结点称为孩子的双亲(Parent)
孩子:当远离根(Root)的时候,直接连接到另外一个结点的结点被称之为孩子(Child);
双亲:相应地,另外一个结点称为孩子(child)的双亲(parent)。
兄弟:同一个双亲(Parent)的孩子(Child)之间互称为兄弟(Sibling)。
祖先:从根(Root)到该结点所经分支(Branch)上的所有结点。
子孙:以某结点为根的子树中的任一结点
边(Edge): 一个结点和另一个结点之间的连接
结点的度(Degree):结点拥有的子树个数
树的度:是树内各结点的度的最大值。
结点:包含一个数据元素及若干指向其子树的分支
叶结点(Leaf)或终端结点:度为0的结点(没有孩子的结点)
分支结点(内部结点/中间结点)或非终端结点:度不为0的结点(至少有一个孩子的结点)
路径:连接结点和其后代的结点之间的(结点,边)的序列。
路径长度:从树的一个结点到另一个结点之间的分支构成两个结点之间的路径,路径上的分支数目称为路径长度(其实就是两个结点之间的线有多少根)
树的路径长度:从树根到每一个结点的路径长度之和
结点之间的带权路径长度:从树的一个结点到另一个结点之间的分支上的权值的总和
树的带权路径长度:树中所有叶子结点的带权路径长度之和
结点的层次(Level): 从根(Root)开始定义起,根为第一层,根的孩子为第二层。以此类推,若某结点在第i层,那么其子树的根就在第i+1层,依次递增。其双亲在同一层的结点互为堂兄弟。
结点的高度: 是该结点和某个叶子之间存在的最长路径上的边的个数。
结点的深度: 是从树的根结点到该结点的边的个数。
树的高度: 树的高度是其根结点的高度。
树的深度:树中结点的最大层次
有序树(OrderedTree):树中每个结点的各子树是从左到右有次序的(即不能互换);
否则称为无序树(UnorderedTree)。
森林 森林是n(>=0)棵互不相交的树的集合(对树中每个结点而言,其子树的集合即为森林)
树和森林的概念相近。删去一棵树的根,就得到一个森林;反之,加上一个结点作树根,森林就变为一棵树。
线性表、树结构:
线性表:
第一个数据元素无前驱
最后一个数据元素无后继
中间元素:一个前驱、一个后继
树结构:
根节点:无双亲,唯一
叶结点:无孩子
中间结点:一个双亲多个孩子
树的存储结构:双亲表示法、孩子表示法、孩子兄弟表示法(这个表示法充分利用了二叉树的特性和算法来处理这棵树)
二叉树:
每个结点最多有两个子树的树结构,子树被称作“左子树”和“右子树”
二叉树一些性质和概念
1、二叉树不存在度大于2的结点
2、左右子树是有顺序的,即使某结点只有一棵子树,也要区分它是左子树还是右子树
3、二叉树具有五种基本形态:
空二叉树、只有一个根节点、只有左子树、只有右子树、左右子树都有
4、二叉树第i层上至多有2^(i-1)个结点(i≥1)
5、深度为k的二叉树至多有2^k - 1个结点(k≥1),此时为满二叉树
6、对任何一棵二叉树T,如果其叶子结点数为n0,度为2的结点数为n2,则n0 = n2 + 1。
推导:设结点数为n,可以知道结点间连接线数为n-1。于是有两个式子:n-1 = n1 + 2*n2 和 n = n0 + n1 +n2,联合解出n0 = n2 + 1
7、具有n个结点的完全二叉树的深度为log2n向下取整然后加1 => 通过满二叉树2^n - 1可以推出
8、对于完全二叉树,在有左右子结点的情况下,设根结点的编号是n(这个编号从1开始),则左孩子的编号是2n,右孩子的编号是2n+1
斜树:
所有的结点都只有左子树或右子树,结点的个数与二叉树的深度相同
满二叉树:
除了叶子结点之外的每一个结点都有两个孩子,每一层(当然包含最后一层)都被完全填充,所有的分支结点(非叶子)都存在左子树和右子树,
并且所有的叶子都在同一层(完全对称,非叶子结点的度一定是2,结点数是2^n - 1)
一颗树深度为h,最大层数为k,深度与最大层数相同,k=h;
它的叶子数是: 2^h
第k层的结点数是: 2^(k-1)
总结点数是: 2^k-1 (2的k次方减一)
完全二叉树:除了最后一层之外的其他每一层都被完全填充,并且所有结点都保持向左对齐(满二叉树一定是完全二叉树,反之则不成立。如果某结点的度为1,则该结点只有左孩子)
二叉树的存储结构
1) 顺序存储:
用一维数组存储。对于一般的二叉树则会耗费很多存储空间(如有5层的斜树,只有1,2,4,8,16这几个索引值是存了值的,其他空间都没有作用)
2) 二叉链表:
一个结点用(左孩子指针, 右孩子指针, 数据域)来表示,如果没有孩子结点,则指针域指向空即可,可以节省很多空间(若有必要添加”指向父结点指针“,构造三叉链表)
二叉树的遍历
由于(链表结构的)二叉树没有明确的“次序”一说(不存在唯一的前驱和后继关系),所以只要是按照某种次序依次访问二叉树中所有结点,使得每个结点被访问且仅被访问一次就是二叉树的遍历。
前序遍历,中序遍历,后序遍历,层序遍历
前序遍历:先访问根结点,然后前序遍历左子树,再前序遍历右子树 //“序”针对的是根结点的访问时机
中序遍历:先中序遍历根结点的左子树,然后访问根结点,再中序遍历右子树
后序遍历:先后序遍历根结点的左子树,然后后序遍历右子树,再访问根结点
层序遍历:从上到下从左到右对结点逐个访问
性质:已知中序遍历和其他两种遍历中的其中一种,可以唯一确定一棵二叉树
二叉树的建立
需要引入“扩展二叉树”的概念,其实就是在所有的叶子结点后添加一个空指针的标记,用#表示.
赫夫曼树
给定n个权值作为n的叶子结点,构造一棵二叉树,若带权路径长度(WPL)达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树
赫夫曼树(最优二叉树)的作用是优化对树中结点的访问次数,使权值大(通常是访问次数多的)尽可能放在靠近根结点的位置 => 树的带权路径长度最短
构造方法:
假设有n个权值,则构造出的哈夫曼树有n个叶子结点。 n个权值分别设为 w1、w2、…、wn,则哈夫曼树的构造规则为:
(1) 将w1、w2、…,wn看成是有n 棵树的森林(每棵树仅有一个结点);
(2) 在森林中选出两个根结点的权值最小的树合并,作为一棵新树的左、右子树(必须满足左子树的权值低于右子树),且新树的根结点权值为其左、右子树根结点权值之和;
(3) 从森林中删除选取的两棵树,并将新树加入森林;
(4) 重复(2)、(3)步,直到森林中只剩一棵树为止,该树即为所求得的哈夫曼树
例子:
设一开始有4个结点集合,他们的权值排序后分别为 1 3 5 7,
那么先选取1和3构成一棵树的左右子树,那么他们的根结点权值为4,
再次选取4和5构成一棵树的左右子树,
依次类推重复步骤得到d中的最优二叉树。(所有初始的结点都是叶子结点)
赫夫曼编码
最优二叉树一开始的研究目的是为了解决当年远距离通信的数据传输的最优化问题,所以最优二叉树的应用在于“赫夫曼编码”,将一个符号用对应的一个编码表示,使得发送数据所用的二进制位数尽可能少。
生成赫夫曼编码的过程:将每个字符按照频率构造一棵最优二叉树,然后从根开始往左是0,往右是1,直到每个叶子结点的结果就是对应的编码