数据结构与算法分析
以数据结构与算法分析这本书,来写的,再次学习一下数据结构和算法
红尘不染
我想把代码写的像诗一样优雅
展开
-
数据结构与算法分析结束篇
后两章的不写了,结束此栏目原创 2021-05-02 10:53:08 · 77 阅读 · 0 评论 -
第十章回溯算法(三连棋,极大极小值,α-β剪枝)
博弈树:在进行游戏时,双方轮流选择,每次执行一个步骤。所有可能的步骤就构成了一棵博弈树。终端位置:通过考察盘面能够确定这局棋输赢的位置。如果一个位置不是终端位置那么该位置的值通过递归地假设双方最优棋步而确定的。极小极大策略:极小极大策略常用于二人博弈游戏,目的是寻找最优的方案使得自己能够利益最大化。基本思想就是假设博弈的双方都足够聪明,一方总是能选择最有利于自己的方案,使得自己胜率值极大,而另一方总会选择最不利对手的方案,使得对手的胜率值极小。对于计算机下棋,一个最重要的因素看来是程序能够向前看的棋原创 2021-05-02 10:49:58 · 519 阅读 · 1 评论 -
第十章回溯算法(收费公路重建问题)
回溯算法(backtracking):在许多情况下,回溯算法相当于穷举搜素的巧妙实现,但性能一般不理想。但在某些情况下,它相比蛮力穷举搜索,工作量有显著的节省。在暴力穷举中,在一步内删除一大组可能性的做法叫做剪枝(pruning)。收费公路重建问题:设给定N个点p1,p2,…,pn,它们位于x轴。xi是pi的x坐标。进一步设x1 = 0,Xn = DMax(距离集合中的最大值必然是X1与Xn的距离),以及这些点是从左到右给出的。给出N个点在每一对点之间的距离。对于N个点,共有N(N-1)/2个距离。收原创 2021-04-29 17:39:14 · 710 阅读 · 0 评论 -
第十章随机化算法(素数测试)
随机化算法:在算法期间,随机数至少有一次用于决策,该算法的运行时间不只依赖特定的输入,而且依赖所发生的随机数。一个随机化算法的最坏情形运行时间几乎总是和非随机化算法的最坏情形运行时间相当,好的随机化算法没有不好的输入,而只有坏的随机数。通过随机化算法,特定的输入不再重要的。重要的是随机数,我们可以得到一个期望的运行时间。此时我们对所有的随机数取平均,而不是对所有的输入取平均。随机化算法需要生成随机数,但是真正的随机数在计算机中是不可能生成的,因为这些数将依赖以算法,从而不可能是随机的。一般来说,产生伪原创 2021-04-28 17:15:19 · 843 阅读 · 0 评论 -
第十章动态规划(最优二叉搜索树)
给定n个关键字组成的有序序列S={s1,s2,…,sn},关键字称为实结点。对每个关键字查找的概率是Pi查找不成功的结点称为虚结点,对应{e0,e1,…,en},每个虚结点的查找概率为qi。e0表示小于s1的值,en大于sn的值,所有结点查找概率之和为1。求最小平均比较次数的二叉搜索树(最优二叉搜索树)。e0<s1<e1<s2<e2…sn<en最优二叉搜索树:...原创 2019-04-25 17:41:12 · 1875 阅读 · 0 评论 -
第十章动态规划(01背包)
一个可以被数学上递归表示的问题,也可以表示成一个递归算法,在许多情形下对朴素的穷举搜索得到显著的性能改进。任何数学递归公式都可以直接翻译成递归算法,但是基本现实是编译器常常不能正确的对待递归算法,结果导致低效的算法。当我们怀疑很可能是这种情况的时候,我们必须给编译器一些帮助,将递归算法,写成非递归算法,让后者把那些子问题的答案系统的记录在一个表内,利用这种方法的一种技巧叫做动态规划(dynamic programming)。动态规划要做的就是用一个表代替递归。在递归算法中可能会对子问题重复求解,在动态规原创 2021-04-27 18:09:48 · 92 阅读 · 0 评论 -
第十章分治算法(矩阵相乘)
矩阵乘法问题:strassen算法Strassen算法的基本思想是把每一个矩阵都分为4块在求C = AB,设7个矩阵变量。M1 = (A12-A22)(B21+B22)M2 = (A11+A22)(B11+B22)M3 = (A11-A21)(B11+B12)M4 = (A11+A12)B22M5 = A11(B12-B11)M6 = A22(B21-B11)M7 = (A21+A22)B11。则 C可以通过这7个变量算出。C11 = M1+M2-M4+M6。C12 = M4+N5原创 2021-04-25 20:05:39 · 998 阅读 · 0 评论 -
第十章分治算法(大数相乘)
分治算法:分治算法由两部分组成,分和治,分是使问题规模变小,递归解决较小的问题,治是从子问题的解中构建原问题的解。传统上,在正文中至少含有两个递归调用的例程叫做分治算法,而正文中只含有一个递归调用的例程不是分治算法。我们一般坚持子问题是不相交的。在前面写的归并排序和快速排序就是分治算法的一种例程。所有有效的分治算法都是把问题分成一些子问题,每个子问题都是原问题的一部分,然后进行某些附加的工作,以算出最后的答案。分治算法解决大整数相乘。如果X = 61438521,而Y = 94736407,那么原创 2021-04-25 12:21:24 · 824 阅读 · 0 评论 -
第十章贪婪算法(哈夫曼编码)
哈夫曼编码是一种不等长的编码,频率出现高的字符,编码长度小;编码无二义性,无前缀码,任何一个字符的编码不能是另一个字符的前缀哈夫曼编码的基本思想是以字符出现的频率最为权值构建一个哈夫曼树,然后利用哈夫曼树对字符进行编码。构造一棵哈夫曼树,是将所要编码的字符作为叶子结点,该字符在文件中的使用频率作为叶子结点的权值,权值越大的叶子离根越近。哈夫曼算法采用的贪心算法的策略:每次从树的集合中取出没有...原创 2019-03-29 18:15:29 · 3200 阅读 · 0 评论 -
第九章第十四节(有向图求强分支)
有向图如果是强连通的:那么通过dfs,可以从一个顶点开始,访问到每一个节点。如果有向图不是强连通的,可以在某个未作标记的节点处开始,反复执行深度优先操作,直到所有的节点都被访问到。通过两次深度优先搜索可以检测一个有向图是否是强连通的,如果它不是强连通的,我们可以得到一些子集,它们到自身是强连通的,称它们为图中的一个强分支。查找图中强分支的算法:1.对图进行一次dfs,并对访问的顶点进行编号,然后再把G上的所有边反向,形成Gr2.对Gr执行dfs,在编号最高的顶点开始新的dfs,一次dfs执行所访问原创 2021-04-24 14:12:37 · 655 阅读 · 0 评论 -
第九章第十三节(无向图求欧拉回路)
欧拉环游:在图中找到一条路径,从起点开始,依此经过图中的所有边,一个边只能走一次,到达终点,终点和起点可以不同欧拉回路:在图中找到一条路径,从起点开始,依此经过图中的所有边,最后回到起点,一个边只能走一次。欧拉环游存在的条件:当前图是连通的,图中的恰有零个或两个顶点的度是奇数,其余顶点的度数为偶数,才会存在欧拉回路存在的条件:当前图是连通的,图中所有的顶点的度是偶数时,欧拉回路必存在。寻找欧拉回路的算法:如果从起点出发的所有边均已用完,那么图中就会有的部分遍历不到。最容易补救的方法就是找出有尚未访问原创 2021-04-24 09:56:52 · 1113 阅读 · 0 评论 -
第九章第十二节(无向连通图求割点)
深度优先搜索DFS是对先序遍历的推广。从某个顶点v开始处理v,然后递归的遍历所有与v邻接的顶点。void Dfs(Vertex v) { //处理模板 visited[v] = true; //全局布尔数组visited[]初始化成false。通过只不过那些尚未被访问的节点递归调用该函数,保证不会陷入无限循环。 for each w adjacent to v if (visited[v] = true) Dfs(W);}深度优先生成树:在一个连通的图中,调用一次Dfs就可以访原创 2021-04-22 21:39:26 · 420 阅读 · 0 评论 -
第三章第九节(优先队列)
// 链表实现优先队列#define BTree inttypedef struct Node* QNode;typedef struct Queue* linkQueue;struct Node{ BTree V; // 顶点 BTree step; // 路径 QNode next;};struct Queue{ QNode front; // 队列头 QNod...原创 2019-03-25 16:28:45 · 804 阅读 · 0 评论 -
第九章第十一节(图的遍历DFS和BFS)
邻接矩阵的DFS和BFS遍历邻接矩阵实现图#define Maxnum 100;#define Maxnum 100typedef struct ENode * Edge;struct ENode{ int V1, V2; int weight;};typedef struct GNode * Graph;struct GNode{ int Nv; // 顶点数 int...原创 2018-11-13 17:15:18 · 215 阅读 · 0 评论 -
第九章第十节(最小生成树问题,Prim算法,Kruskal算法)
最小生成树问题:最小生成树就是寻找图中含有所有顶点的边构成的树,其组成的边的权值最小,最小生成树存在当且仅当图G是连通的。解决最小生成树的两种算法,它们的区别在于最小边的选取上。prim算法:计算最小生成树的方法是一步步长成的,在每一步,都要把一个节点当作根并往上加边,这样就把相关联的顶点加到增长中的树中。算法在每一阶段都可以选择边(u,v),使得(u,v)的值是所有u在树上,但是v不在树上的边的值中的最小者,而找出一个新的顶点并把它添加到这棵树中。简单的说,prim算法就是通过每次选择与已有树相连原创 2021-04-20 19:16:22 · 279 阅读 · 0 评论 -
第九章第九节(dinic算法)
dinic算法是一种求最大流的算法,与EK算法不同,dinic算法在求增长通路的时候,先BFS进行图的分层操作,在DFS寻找增长通路的时候,榨干一条路径上的所有流量。简单的说就是,一次分层,多次增长。关于dinic算法的两个优化:1.当前弧优化,在进行寻找增长通路的过程中,记录当前处理的边,做到下一次寻找增长通路的时候,不重复寻找;2.在进行分层,如果在分层网络中找到汇点T,则停止进行分层,定义使用的数据结构#include<stdio.h>#include<stdlib.h&原创 2021-04-20 15:35:06 · 2067 阅读 · 0 评论 -
第九章第八节(链式前向星表示图)
在网上找了一些资料学习dinic算法,发现这些算法在存储图的时候,都是使用链式前向星的一种数据结构,先把这种表示图的方式学了一下链式前向星:是一种存储图的方式,用head[i],表示顶点i的第一条边的位置,tot记录边的序数(个数),edges为边集#define MAXNUM 100*100 //最大边的个数#define MAXVERTEX 100 //最大顶点的个数struct { int to; //终点 int weight; //边的权值 int next;原创 2021-04-20 15:09:27 · 116 阅读 · 0 评论 -
第九章第七节(网络流EK算法)
网络流问题:设给定容量为Cv,w的有向图G = (V,E)。这些容量可以代表通过一个管道水的流量或在两个交叉路口之间的马路上的交通流量,有两个顶点,一个是s,称为发点,一个是t,称为收点。对于任意一条边(V,W),最多有流的Cv,w个单位可以通过,在既不是发点也不是收点的中间节点v,总的进入的流必须等于总的发出的流,最大流问题就是确定从发点s到收点t之间能够通过最大流量。求解最大流的思路:从图G开始构造一个流图Gf,Gf表示算法已经达到的流,开始时,Gf的所有边都没有流,我们希望当算法终止时,Gf包含原创 2021-04-18 20:08:35 · 146 阅读 · 0 评论 -
第九章第六节(floyd算法多源有权最小路径)
需要两个矩阵D矩阵保存距离,D[i][j] 存储的就是 i 到 j 点的距离;Path矩阵保存路径;Floyd 算法不能解决有负值圈的情况;bool Floyd(Graph G,int D[][Maxnum],int Path[][Maxnum]){ int i, j, k; for (i = 0; i &amp;lt; G-&amp;gt;Nv; i++) for (j = 0; j &amp;lt;...原创 2018-11-20 15:56:55 · 216 阅读 · 0 评论 -
第九章第五节(Bellman–Ford算法)
Bellman–Ford算法与Dijkstar算法一样都是解决单源最短路径的问题;都是通过对节点的松弛操作来实现最短路径的求解,不同的是,Dijkstar算法是通过贪心思想,每次加入一个最小距离的顶点,来完成对节点的松弛操作,而Bellman–Ford算法则是简单的对所有边进行松弛操作,共|V | − 1次,其中 |V |是图的点的数量。Bellman–Ford代码代码使用邻接表实现图#define MAXNUM 65536struct { int dist; //记录距离 int path;原创 2021-04-18 12:14:53 · 91 阅读 · 0 评论 -
第九章第四节(具有负边值的图最短路径)
具有负边值的图,使用Dijkstra算法是行不通的。一旦一个顶点u被声明是已知的,那么就有可能存在一个未知顶点v,有一条回到u的负的路径,在这样的情况下,从s到v,再回到u的路径要比不过v的路径要更好这个算法只能解决没有负值圈的情况解决思路:程序开始将源点s入队列。在每个阶段让一个顶点v出队列,找到所有和v顶点相连接的顶点w,如果dw > dv+ Cv,w,则更新dw和pw,并在w在队列的时候,进入队列。重复此过程,直到队列为空。#define MAXNUM 65536struct原创 2021-04-18 10:54:40 · 273 阅读 · 0 评论 -
第九章第三节(最短路径算法)
无权最短路径问题:表示一个无权的图G。使用某个顶点s作为输入参数,找出从s到所有其他顶点的最短路径,因为边上不存在权,可以为所有的边赋以权1。无权最短路径算法,可以用广度优先搜索来实现,该方法按层处理顶点:据开始点最近的那些顶点首先被赋值,而最远的那些顶点最后被赋值。这很像树的层次遍历。输入是一个赋权图,与每条边(vi,ui)相联系的是穿越该弧的代价ci。一条路径v1,v2…vn的值是∑ci,叫做赋权路径长,而无权路径长只是路径上的边数,即N-1。单源最短路径问题:给定一个赋权图G=(V,E)和一个特原创 2021-04-17 21:53:46 · 137 阅读 · 0 评论 -
第九章第二节(拓扑排序)
拓扑排序:是对有向无圈图的顶点的一种排序。它使得如果存在一条从vi到vj的路径,那么vi在排序中必须在vj的前面。思路:一个简单的求拓扑排序的算法是先找出任意一个没有入边的顶点,然后我们显示出该顶点,并将它和它的边一起从图中删除。对图的其余部分应用同样的方法处理。实现过程:把顶点v的入度(indegree)定义为边(u,v)的条数,计算图中所有顶点的入度,记录在Indegree数组中。建立队列,扫描该数组,将入度为0的顶点,入队列。当队列不为空的时候,删除队列中的顶点v,同时删除顶点v到其它顶点的边原创 2021-04-17 16:06:03 · 181 阅读 · 0 评论 -
第九章第一节(图的定义及图的表示)
图的定义:一个图(graph) G =(V,E)由顶点(vertex)集V和边(edge)集E组成。每一条边就是一个点对(v,w),其中v,w∈V.如果点对是有序的,那么图是有向图。顶点v和w邻接,当且仅当(v,w)∈E。在一个无向图中,v和w邻接,w和v也邻接,有时边还有第三种成分,称作权或者值。路径:图的一条路径是一个顶点序列w1,w2,w3,…,wn,使得(wi,wi+1)∈E(i<= i < N)。路径上的边数等于N-1.如果图含有一条从一个顶点到它自身的边(v,v),那么路径v,v有原创 2021-04-17 11:58:42 · 149 阅读 · 0 评论 -
第八章(ADT不相交集)
输入数据是N个集合的类,每个集合含有一个元素。每个集合都有一个不同的元素,从而Si∩Sj= Ø;使得这些集合不相交。此时,有两种运算允许运行。find()返回包含给定元素的集合的名字,第二种是添加关系,如果想要添加关系(a,b)首先查看a和b是否已经有关系,对a和b执行find并检验它们是否在一个集合,若不在一个集合,使用并运算Union(),这种运算把含有a和b的集合合并为一个集合。基本数据结构:用一个数组来记录元素的父节点。数组中的每个成员P[i]表示元素i的父亲,集合的名字有根处的节点给出。原创 2021-04-16 13:58:34 · 137 阅读 · 0 评论 -
第七章第三节(快速排序)
快速排序:快速排序是已知在实践中最快的排序算法,它的平均运行时间是O(N logN)快速排序也是一种分治的递归算法。快速排序的步骤:对数组S排序1.如果S中元素个数是0或1,则返回。2.取S中任一元素u,称为枢纽元(pivot)3.将S-{u}(S中的其它元素)分为两个不相交的集合:S1 = { x ∈ S-{u} | x<= u} 和 S2= { x ∈ S-{u} | x >= u };4.返回 quickSort(S1),u,quickSort(S2)选取枢纽元策略:对S[l原创 2021-04-15 19:28:07 · 364 阅读 · 0 评论 -
第七章第二节(堆排序,归并排序)
堆排序:是利用二叉堆来进行排序的一种算法。在排序时如果是从小到大排序,则建立最大堆。如果是从大到小排序,则建立最大堆。堆排序的时间效率为O(N logN)本算法是从大到小排序排序步骤:1.将待排序数组建立最大堆2.将A[0]与数组的最后一个数据进行交换,此时最大的数据就到数组的最后一个单元3.调整堆结构,继续交换。...原创 2021-04-15 16:39:08 · 185 阅读 · 0 评论 -
第七章第一节(选择排序,冒泡排序,插入排序,希尔排序)
预备知识:每个算法都将接受一个含有元素的数组和一个包含元素个数的整数。对所有的排序,数据都将在位置0处开始。假设 < , > ,运算符的存在,除赋值运算符外,这两种运算符是仅有的允许对输入数据进行的操作,在这些条件下的排序叫做基于比较的排序。冒泡排序代码// 数组A是存放的待排序数据,N为数组的规模void BubbleSort(int a[], int N) { int i, j; int tmp, flag; //双重循环,每次从完成一次冒泡 for (i = N - 1;原创 2021-04-14 20:35:28 · 125 阅读 · 0 评论 -
第六章第四节(二项队列)
二项队列介绍:二项队列是由多个二项树组成。二项队列是一个堆序树的森林。高度为K的二项树恰好有2^k节点。二项队列从结构上来说是由高度不重复的若干个二项树构成的森林,高度不重复意味着相同高度的二项树在二项队列中最多存在一个。二项树的集合唯一的表示任意大小的优先队列。例如大小为13的优先队列可以用森林B3,B2,B0表示(8+4+1)。二项队列的堆序性:森林中的所有二项树都要保持相同的堆序性。二项队列的操作:主要是合并操作,插入是合并的特殊形式,只要创建一棵单节点树并执行一次合并即可完成插入操作原创 2021-04-13 23:09:49 · 353 阅读 · 0 评论 -
第六章第三节(斜堆)
斜堆:是左式堆的自调节形式。是具有堆序的二叉树,但是不存在对树的结构限制,所以数据结构中***没有存储零路径长度的数据***。与左式堆一样,斜堆的基本操作也是合并,但是与左式堆不同,在左式堆中,如果节点的右儿子的零路径长度大于左儿子的零路径长度,则进行交换,在斜堆合并时,不做判断,左右儿子直接进行交换。代码#include<stdio.h>#include<stdlib.h>//数据结构struct TreeNode;typedef struct TreeNode原创 2021-04-13 16:03:35 · 200 阅读 · 0 评论 -
第六章第二节(左式堆)
左式堆是在二叉堆的基础上出现的,主要是为了解决二叉堆合并的效率。二叉堆合并H1与H2的合并,依此将H2中的根节点删除并插入H1节点中,从而完成合并。左式堆的结构1.左式堆具有堆序性质,左式堆不是完全二叉树,是趋于左倾的不平衡二叉树。左式堆的性质1.把任一节点X的零路径长Npl(X)定义为X到一个没有两个儿子的节点的最短路径长,即有一个子节点或零个子节点的节点X的Npl值为0。2.对于堆中的每一个节点X,左儿子的零路径长,至少与右儿子的零路径长一样。(这个性质确保了树不平衡的要求,更偏重于使树向左原创 2021-04-12 21:41:14 · 193 阅读 · 0 评论 -
第六章第一节(二叉堆)
二叉堆堆有两个性质:结构性和堆序行,必须满足这两个性质结构性质:堆是一棵完全填满的二叉树。完全二叉树很有规律,可以用一个数组来实现,不需要用指针1.对数组中任一位置i上的元素,其左儿子在2i,其右儿子在2i+1的位置,它的父亲在i/2上堆序性质:使操作被快速执行的性质使堆序性。1.对于最小堆(最小的关键字在根上),在一个堆中,对于每一个节点X,X的父亲的关键字应小于等于X的关建字,根节点除外2.对于最大堆(最大的关键字在根上),在一个堆中,对于每一个节点X,X的父亲的关键字应大于等于X的关键字,原创 2021-04-11 12:05:07 · 83 阅读 · 0 评论 -
第五章第二节(散列开放定址法)
开放定址散列法:是另一种不用链表解决冲突的方法,在开放定址散列算法系统中,如果有冲突发生,那么就要尝试选择另外的单元,直到找出空的单元为止。公式 : hi ( X ) = ( hash(X)+F(i) ) mod TableSize关键字X的位置等于 Hash函数返回的位置在加上F(i)的位置 Mod TableSize线性探测法:F(i) = i ,这相当于逐个探测每个单元(必要时可以绕回)以查找出一个空单元。平方探测法: F(i) = i²,平方探测法冲突函数为二次函数的探测方法。F(i) =原创 2020-12-13 21:42:28 · 166 阅读 · 1 评论 -
第五章第一节(散列简介及分离链接法实现)
散列是一种用于以常数平均时间执行插入,删除,查找的技术。散列函数:将每个关键字映射到适当的单元。理想情况下,它应该运算简单并且保证任何两个不同的关键字映射到不同的单元。冲突:当两个关键字散列到同一个值的时候。key关键字,TableSize散列表大小,当散列表的大小为素数时,可以使关键字分布更加均匀,减少冲突。当key为整数时。一般采用 key % TableSize,来确定散列的位置。当key为字符串时,可以将key的每一个字符的ASCII值加起来,再 %TableSize。int Hash(原创 2020-11-22 21:15:07 · 129 阅读 · 0 评论 -
第四章第六小节(红黑树的实现)
好好看,绝对让你看明白!ok,开始先介绍一下红黑树:红黑树是平衡搜索树的一种,保证在最坏情况下操作的时间复杂度为O(lgn)。树中的每个节点包含5个属性:color,data,left,right,parent。如果一个节点没有子节点或父节点,则该节点相应指针属性的值为NIL。可以把NIL视为二叉搜索树的叶节点的指针,把带关建字的结点视为树的内部结点。看明白了吧,估计你没有。解释一下什么是NIL,就是为了编程好实现,限定树的范围,将所有的空指针都指向一个NIL,ok,来个图就明白了。为了便于处理原创 2020-11-22 11:07:20 · 450 阅读 · 0 评论 -
第四章第五小节(伸展树的实现自底向上)
伸展树的基本思想:当一个节点被访问后,它要经过一系列的树的旋转操作,被放到根上,当一个节点很深时,就存在许多的节点也相对较深,通过重新构造可以使对这些节点的进一步访问所花费的时间变上。当一个节点被访问,它可能在不久后再次被访问到,它保证从空树开始任意连续M次对树的操作最多花费O(M logN)时间什么时候调整:在进行插入时,将新插入的节点调整到树根;删除时将删除的节点调整到树根,然后删除;查找时,将新访问的节点,调整到树根。怎么样调整:情况1:x节点的父亲节点y是根节点;如果x是y的左儿子,只需要对x原创 2020-11-20 19:22:47 · 416 阅读 · 1 评论 -
第四章第四小节(树的遍历)
树的遍历,有先序,中序,后序,层次。#include<iostream>#include<time.h>#include"AvlTree.h"#include"Queue.h"using namespace std;//树的遍历,先序,中序,后序,层次//树的先序遍历,先访问父亲节点,左儿子,右儿子void printTreePreorder(AvlTree T) { if (T!=NULL) { cout << T->data <&原创 2020-11-19 14:21:52 · 98 阅读 · 0 评论 -
第四章第三小节(AVL树实现)
AVL树带有平衡条件的二叉查找树,这个平衡条件必须要保持,必须保证树的深度是O(log N),要求左右子树具有相同的高度;一棵AVL树是其每个节点的左子树和右子树的高度最多差1的二叉查找树。在进行插入或删除操作时可能会破坏平衡条件,需要对树进行修正,保证每个节点都符合平衡条件。可以通过简单的旋转保证;在插入以后,只有那些从插入点到根节点的路径上的节点的平衡可能被改变,我们可能沿着这条路径上找到根并更新平衡信息,如果有节点破坏了平衡条件,必须重新平衡树;可能造成不平衡的四种情况:1.对α的左儿子的左原创 2020-11-19 08:35:14 · 123 阅读 · 0 评论 -
第四章第二小节(二叉搜索树)
二叉查找树的性质:对于树中的每个节点X,它的左子树中所有关键字值小于X的关键字值,而它的右子树中所有关键字值大于X的关键字值。二叉查找树的平均深度是O(log N)//二叉查找树typedef int element;typedef struct treeNode* position;typedef position searchTree;//函数的声明searchTree makeEmpty(searchTree T); //清空树position find(element x,sea原创 2020-11-17 21:48:31 · 90 阅读 · 0 评论 -
第四章第一小节(表达式树的构造)
利用栈来构造表达式树,注输入的表达式为后缀表达式// stack.h中的内容//树的结构,函数已在stack.c中实现typedef struct treeNode* tPtrNode;typedef tPtrNode Tree;struct treeNode { char data; tPtrNode left; tPtrNode right;};//链表实现栈typedef tPtrNode element;typedef struct Node* PtrNode;typede原创 2020-11-17 19:22:17 · 212 阅读 · 0 评论