7.数和二叉树
7.1 树
7.1.1 树的定义和基本术语
(1) 树
是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合;把它叫做树是因为它看起来像一颗倒挂的树,也就说说它是根朝上,而叶是朝下的.
(2) 结点的度(Degree)
树的结点包含一个数据元素以及若干指向其子树的分支,结点拥有的子树树称为结点的度;
(3) 非终端结点或分支结点
度不为0的结点;
(4) 终端结点或叶子(Leaf)
度为0的结点;
(5)深度(Depth)或高度
树中结点的最大层次
(6)树的度
一棵树中,最大的结点的度;
(7)森林(Forest)
是由m(m>=0)棵互不相交的树的集合.
7.1.2 树的表示
(1)双亲表示法;
struct Node{
TDataType _data; //双亲位置指针域
struct Node* _parent; //双亲结点
};
优缺点:便于找到双亲位置,不利于找到孩子的位置
(2)孩子表示法;
struct Node{
TDataType _data;
struct Node* child1;
struct Node* child2;
struct Node* child3;
};
优缺点:便于找到孩子位置,不利于找到双亲的位置
(3)双亲孩子表示法;
即双亲表示法+孩子表示法;
(4)孩子兄弟表示法.
typedef int DataType;
struct Node{
DataType _data; //结点中的数据域
struct Node* _firstchild1; //第一个孩子结点
struct Node* _pNextBrother; //指向其下一个兄弟结点
};
7.1.3 树的特点
(1)在任何一棵非空树中,有且仅有一个特定的称为根(Root)的结点;
(2)当n>1时,其余结点可分为m(m>0)个互不相交的有限集T1,T2,...Tm,其中每一个集合本身又是一棵树,并且称为根的子树.
7.2 二叉树
7.2.1 二叉树的定义
一棵二叉树是结点的一个有限集合,该集合或者为空;
或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成的.
7.2.2 二叉树的性质
(1) 在二叉树的第i层上至多有2^(i-1)个结点(i>=1);
(2) 深度为k的二叉树至多有(2^k)-1个结点(k>=1);
(3) 任何一棵二叉树T,如果其终端结点数为n0,度为2的结点数为n2,则n0 = n2 +1;
(4)具有n个结点的完全二叉树的深度k为log2(n)+1上取整;
(5) 如果对一棵有n个结点的完全二叉树(其深度为log2(n)+1)的结点按层序编号(从第1层到第log2(n)+1层,每层从左往右),则对任意结点i(1=<i<=n),有
a.若i > 0; 双亲序号:(i - 1) / 2;
i = 0, i为根结点编号, 无双亲结点;
b.若2i+1<n,左孩子序号:2i+1,否则无左孩子;
c.若2i+2<n,右孩子序号:2i+2,否则无右孩子;
7.2.3 二叉树的存储结构
(1) 顺序存储结构
顺序存储结构就是使用数组来存储,用一组地址连续的存储单元依次自上而下,自左至右存储完全二叉树上的结点元素,这种顺序存储结构仅适用于完全二叉树.
struct BinaryTreeNode{
struct BinTreeNode* _pLeft; //指向当前结点的左孩子;
struct BinTreeNode* _pRight; //指向当前结点的右孩子
BTDataType _data; //当前结点值域
};
(2) 链式存储结构
用链表来表示一棵二叉树,即用链来指示元素的逻辑关系,通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针域分别用来给出该结点左孩子和右孩子所在的连接点的存储地址,,链式结构又分为二叉链和三叉链表,当前以二叉链为主,高阶红黑树会使用三叉链表.
struct BinaryTreeNode{
struct BinTreeNode* _pParent;//指向当前结点的双亲
struct BinTreeNode* _pLeft; //指向当前结点的左孩子;
struct BinTreeNode* _pRight; //指向当前结点的右孩子
BTDataType _data; //当前结点值域
};
7.2.4 特殊的二叉树
(1) 完全二叉树
可以对满二叉树的结点进行连续编号,预定编号从根节点起,自上而下,自左至右,由此可以完全引出完全二叉树的定义,深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时,称之为完全二叉树.
(2) 满二叉树
一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树,也就是说,如果一个二叉树的层数为k,且结点的总数数(2^k)-1,则它就是满二叉树,满二叉树是一种特殊的完全二叉树.
7.2.5 二叉树的顺序存储结构(堆heap)
(1) 堆的定义
如果有一个关键码的集合k={k0,k1,k2,...,kn-1},把它的所有元素按照完全二叉树的顺序存储方式存储在一个一维数组中,并满足:ki<=k2i+2(ki>=k2i+2)i=0,1,2...,则称为小堆或(大堆),将根结点最大的堆叫做最大堆或大根堆,根结点最小的堆叫做最小堆或小根堆.
(2) 堆的性质
堆中某个结点的值总是不大于或不小于其父结点的值;
堆总是一颗完全二叉树;
堆顶元素一定是堆中所有元素中最大或最小的.
(3) 堆的基本操作
堆的创建
堆的向下调整算法
前提条件:左右子树必须是一个堆,才能调整;
堆的插入
判断空间是否足够;
插入的元素是否符合堆的特性;
最后再使用向上调整算法进行实现.
堆的删除
指删除堆顶的元素,将堆顶的数据根最后一个数据一换,然后再删除数组最后一个数据,再进行向下调整算法;
堆排序
使用堆删除的思想进行排序.
层序遍历
设二叉树的根结点所在的层数为一,层序遍历就是从所在二叉树的根结点出发,首先访问第一层的根结点,然后从左到右访问第二层上的结点,接着访问第三层上的结点,以此类推,自上而下,左至右逐层访问树的结点的过程.
(4) 堆的应用
7.2.6 二叉树的链式存储结构
(1)二叉树的遍历
遍历的定义
即按照某条搜索路径访问树中的每个结点,使得每个结点均被访问一次,而且仅被访问一次;
(2)前序,中序,后序的递归结构遍历
前序遍历
根结点-->左子树-->右子树
中序遍历
左子树-->根结点-->右子树
后序遍历
左子树-->右子树-->根结点
7.2.7 线索二叉树
线索链表
若结点有左子树,则其lchild域指示其左孩子,否则令lchild域指示其前驱;若结点有右子树,则其rchild域指示其rchild域指示其右孩子,否则令rchild域指示其后继,以这种结点构成的二叉链表作为二叉树的存储结构,称为线索链表;
线索
其中指向结点前驱和后继的指针称为线索;
加上线索的二叉树称之为线索二叉树.
对二叉树以某种次序遍历使其变为线索二叉树的过程叫做线索化.
7.3 数和森林
7.3.1 森林的定义
是由m(m>=0)棵互不相交的树的集合.
7.3.2 森林与二叉树的转换
(1) 森林转换成二叉树
先序遍历
(2) 二叉树转换成森林
后序遍历
7.3.3 树和森林的遍历
(1) 树的遍历
线序遍历森林
(2) 森林的遍历
中序遍历森林
7.4 树与等价问题
如果结合S中的关系R是自反的,对称的和传递的,则成它为一个等价关系;
7.5 赫夫曼树(Huffman)及其应用
7.5.1 定义
赫夫曼树
假设有n个权值{w1,w2,...,wn},试构造一棵有n个叶子结点的二叉树,每个叶子结点带权为w1,则其中带权路径长度WPL最小的二叉树称作最优二叉树或者赫夫曼树;
路径长度
从树中一个结点到另外一个结点之间的分支构成这两个结点之间的路径,路径上的分支数目称作分支路径.
树的路径长度
是从树根到每一个结点的路径长度之和;
树的带权路径长度
即树中所有叶子结点的带权路径长度之和;
7.5.2 赫夫曼算法
(1) 根据给定的n个权值{w1,w2,...,wn}构成n棵二叉树的集合F={T1,T2,...,Tn},其中每棵二叉树Ti中只有一个带权为wi的根结点,其左右子树均空;
(2) 在F中国选择两棵根结点的权值孙的树最为左右子树构造一棵新二叉树,且置新的二叉的根结点的权值为其左右子树上根结点的权值之和;
(3) 在F中删除这两棵树,同时将新得到的二叉树加入F中;
(4) 重复(2)和(3)直到F只含有一棵树为止,这棵树就是赫夫曼树.
7.5.3 赫夫曼编码
二进制的前缀编码
7.5.4 赫夫曼树的应用
7.6 回溯法与数的遍历
7.6.1 回溯法
是设计递归过程中的一种重要方法,它的求解过程实质上是一个先序遍历一棵"状态树"的过程,只是这棵树不是遍历前预先建立的,而是隐含在遍历过程中.
7.7 树的计数
DS_(7.数和二叉树)
最新推荐文章于 2023-10-25 11:03:43 发布