二叉树的基本概念以及应用(遍历、堆、哈夫曼树、二叉判定树、二叉搜索树、二叉平衡树) 完全二叉树 在完全二叉树中,只有最下面两层的结点的度可以小于2,最下面一层的叶子结点编号连续集中在靠左的位置上。 满二叉树 一棵深度为𝑘,并且有2^𝑘−1个节点的二叉树,为满二叉树。 二叉树的性质 在非空二叉树的第i层上最多有个2^(𝑖−1)节点 深度为𝑘的二叉树最多有2^𝑘−1个节点 具有n个节点的完全二叉树的深度k=⌊log_2 (n) ⌋+1=⌈log_2 (n+1) ⌉ 二叉树的遍历 先序遍历:若二叉树为空,则空操作返回;否则①先访问根结点;②然后先序遍历左子树;③先序遍历右子树。 中序遍历:若二叉树为空,则空操作返回;否则①中序遍历根结点的左子树;②接着访问根结点;③中序遍历根结点的右子树。 后序遍历:若二叉树为空,则空操作返回;否则①后序遍历根结点的左子树;②后序遍历根结点的右子树;③最后访问根结点。 层次遍历:先访问第一层的结点,再对第二层的所有结点从左往右依次访问,直到访问完最后一层的所有结点。 (注意:先序、中序、后序都是递归实现即可,层次遍历类似于广度优先搜索,需要使用队列结构) 由“先序+中序”或者“后序+中序”的遍历结果可以得到唯一的一颗二叉树。 先/后序确定当前根节点:先序序列的第一个素为根节点,后序序列的最后一个素为根节点; 中序遍历结果确定左右子树的节点范围:在中序序列中找到根节点所在位置,前面的是左子树,后面的是右子树 struct Node///结点 { int data; int lc, rc; }node[maxn*2]; ///还要算上内部节点的开销,所以开两倍maxn int tot;///统计已经建立的顶点数量 int create(int len, int pre_st, int in_st) ///递归建树 { if (len == 0) return -1; int me = tot++; node[me].data = pre[pre_st];///先序序列第一个素为根结点 for (int left = 0; left < len; ++left) { if (in[in_st+left] == pre[pre_st]) { node[me].lc = create(left, pre_st + 1, in_st);///建左子树 node[me].rc = create(len – left – 1, pre_st + left + 1, in_st + left + 1); return me; } } } vector<int>post; void postorder(int root) ///后序遍历 { if(root!=-1) { postorder(node[root].lc); postorder(node[root].rc); post.push_back(node[root].data); } } 堆 二叉堆是完全二叉树。二叉堆满足二个特性:1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。一般都用数组来表示堆,i结点的父结点下标就为(i-1)/2。它的左右子结点下标分别为2i+1和2i+2。 插入素 目前数组所存素0->n-1,新插入的素都将插入到n位置上,然后再从(n-1)/2父结点开始从下至上调整最大堆。 void Insert_heap(int a[], int i) { for (int j = (i – 1) / 2; (j >= 0 && i != 0)&& a[i] > a[j]; i = j, j = (i – 1) / 2) Swap(a[i], a[j]); }///(i-1)/2表示父结点 删除素 对堆的删除都是取出堆顶素(最大、最小素),此时先将n-1位置上的素放到堆顶0号位置,再对0->n-2这样的堆进行从上至下的调整。 ///从i节点开始调整,n为节点总数。从0开始计算i节点的子节点为 2*i+1, 2*i+2 void AdjustDown(int a[], int i, int n) { int j, temp; temp = a[i]; j = 2 * i + 1;///左孩子 while (j < n) { if (j + 1 < n && a[j + 1] > a[j]) //在左右孩子中找最大的 j++; if (a[j] <= temp)///最大的孩子也比父节点小 break; a[i] = a[j]; //把较大的子结点往上移动,替换它的父结点 i = j; j = 2 * i + 1; } a[i] = temp; } //在最大堆中删除数 void Delete_heap(int a[], int n) { Swap(a[0], a[n – 1]); AdjustDown(a, 0, n – 1); } 哈夫曼树 概念: 扩充二叉树:只存在度为0和2的结点组成的二叉树; 结点间的路径长度:树中一个结点到另一个结点所包括的边的数目; 树的内路径长度:从根到所有非叶子结点的路径长度之和; 树的外路径长度:从根到所有叶子结点的路径长度之和; 树的路径长度之和:从根到树 的所有结点的路径长度之和; 结点的带权路径长度:从根到该结点的路径长度与该结点的权值乘积; 树的带权路径长度WPL:树中所有叶子结点的带权路径长度之和 定理:设I和E分别是一棵扩充二叉树的内路径长度和外路径长度,n是树中非叶子结点的数目,则E=I+2n 哈夫曼树的特点: 哈夫曼树的结点个数不能是偶数(因为扩充二叉树只有度为0和2的结点); 一棵哈夫曼树的加权路径长度等于其中所有分支结点(不包括叶子结点)的权值之和; 哈夫曼树是带权路径长度最短的扩充二叉树,权值越大的结点离根结点越近 构建哈夫曼树: 用给定的权值构建n个左右子树都为空的二叉树,所有结点都包含在F集合中;从F中选择权值最小和次最小的两棵树作为左右子树(规定左子树比右子树小),然后构建新的二叉树,新二叉树的权值为左右子树权值之和,在F中删除左右子树权值,把新生成的结点权值加入其中;然后重复上述操作,直到F中只有一个结点即为根结点。 假设哈夫曼树中有n个叶子结点,则哈夫曼树中总共有2n-1个结点。实际存储时采用一维数组存储,0号存储单不使用,1->n号单分别存储叶子结点,n+1->2n-1单存储哈夫曼树形成过程中的非叶子结点。 typedef struct { ElementType Data;///结点的数据域 int w; ///结点的权值 int parent,lchild,rchild; }HFMTNode; void CreateHFMTNode(HFMTNode Ht[],int N) { int i,j,k,lmin,rmin;///lmin和rmin为最小权值的两个结点位置 int min1,min2;///min1和min2为最小两个结点的权值 for(i=1;i<2N;i++)///初始化数组 Ht[i].parent=Ht[i].lchild=Ht[i].rchild[i]=-1; for(i=N+1;i<2N;i++)///n+1->2n-1的位置存储新生成的非叶子结点 { min1=min2=MAX; lmin=rmin=-1; for(k=1;k<=i-1;k++)///寻找当前最小的两个结点 { if(Ht[k].parent==-1)///该结点还没被构造二叉树 { if(Ht[k].w<min1) { min2=min1;rmin=lmin; min1=Ht[k].w;lmin=k; } else if(Ht[k].w<min2) { min2=Ht[k].w;rmin=k; } } } Ht[lmin].parent=i;Ht[rmin].parent=i; Ht[i].w=Ht[lmin].w+Ht[rmin].w; Ht[i].lchild=lmin;Ht[i].rchild=rmin; } } 哈夫曼编码: 给使用频率较高的字符进行较短的编码,是一种可变长编码,同时哈夫曼编码也是一种前缀编码(任何一个字符编码都不是其它字符编码的前缀),可以保证解码不会产生二义性。一边规定左分支为0,右分支为1 二叉判定树 二叉判定树是用于描述解决问题的思路。二叉判定树的根结点是有序表中序号为mid=(n+1)/2的记录,左子树是与有序表1->mid-1的范围存储,根结点的右子树是mid+1]-> n相对应的位置。左子树都比根结点小,右子树都比根结点大。(注意:二叉判定树的形态只与表中素个数n有关,与表中素的关键字无关) 平均搜索长度: 搜索成功:As(n)=(每层结点数 × 比较次数(层数) / n 搜索失败:Af(n)=(每层外节点数×比较次数(上一层层数))/(n+1) 二叉搜索树 概念:所有结点的关键字的值都不一样,左子树都比根结点小,右子树都比根结点大,而且根结点的左右子树也都是二叉搜索树。 若中序遍历二叉搜索树,会得到一个关键字递增排列的有序序列。 已知一棵二叉搜索树的先序遍历序列,可以唯一确定一棵二叉树。 删除结点: 待删除的结点没有子树:直接删除 待删除的结点仅有一颗子树:用唯一子树覆盖父结点,原本指向被删除结点的指针改为指向被删除结点的子树 待删除的结点有两颗子树:使待删除结点的左子树代替被删除的结点,将被删除结点的右子树放置于被删除结点的左子树的最右边 二叉平衡树 可以是空树 假如不是空树,任何一个结点的左子树与右子树都是平衡二叉树,并且高度之差的绝对值不超过1 二叉平衡树是建立在二叉搜索树的基础上,为了维护二叉搜索树的高度,设置了平衡因子 调整二叉平衡树: 从新插入结点回溯,找到第一个非平衡结点标为s,s向下的子树为r s-r为LL型:以r为结点向上提; s-r为LR型:再将r的孩子标为u,以u为根结点,r和s分别为u的孩子(根据左小右大的原则分布)
2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/35209.html