业务开发算法讲易先讯

之前已经学习了常用数据结构的工业级实现(包括动态数组、双向链表、双端队列、栈、哈希表、红黑树、堆),从今天开始,我们来讲讲一些经典的算法思想在工程实践中的应用。

那讲哪些算法呢?我们都知道算法是一个很大的命题,也有很多分类的方式,比如就有人总结过非常经典的五类常用算法:贪婪算法、动态规划算法、分治算法、回溯算法以及分支限界算法。力扣上的每一道算法题也有相应标签,你感兴趣的话可以到题库看一下。

不过有些算法可能只会在特定的场景下被特定的中间件所使用,比如布隆过滤器、前缀树等等,我们在后面的章节结合实际的系统或中间件来讲解;有一些算法思想应用更为广泛,我们会在这个部分学习,所以基础算法篇主要包括了贪心、分治、二分的算法思想,也会涵盖排序、搜索、字符串匹配这些更为常见的应用场景。

今天就让我们从经典的排序问题开始讲起吧。

O(n^2)的选择排序、冒泡排序、插入排序,这些常用的算法相信你应该非常熟练了;几种O(n)的算法在工程中其实也都有实际应用,你也可以自己在网上搜索资料了解学习,最好再找几道相关算法题做一做加深印象。

其中归并排序和快速排序的常用写法都可以采用递归的方式实现,背后是分治的算法思想,也就是分而治之,把大问题递归拆小然后递归得出结果。

而堆排序的思路和实现,在上一讲优先队列中我们详细讲过,相信你现在应该很容易用Java的PriorityQueue实现堆排序,主要思路其实就是建立一个堆,借助堆动态调整的能力,只需要将所有待排序元素依次入队,再依次出队直到堆元素全部出队为止;比如在小顶堆中,每次出队的都是当前最小的元素。

但只是能写出这样的排序代码,往往并不足以让你解决真实世界的工程问题。

比如有这样一个基于真实场景的经典面试题:假设现在有1TB的任意文本,请问如何能将其中出现的单词按照字母序排列,得到一个新的文本?

这个问题,你可以回答好吗?

你也许会觉得很简单呀。我们就直接用堆排序,建立一个小顶堆,然后遍历整个文本进行分词,将每个单词都依次push进堆,最后再逐一出队输出到一个文本,最后就可以得到一个按字典序升序排列的文本了。

这当然是一个正确的思路,但是,你忽略了一个至关重要的问题,就是我们的内存可能没有这么大!

这也是面试官考察这个问题的核心知识点,1TB的数据量级,意味着绝对不可能一次性将所有的数据都放入到内存中。而大部分单纯考察算法的面试题,其实都是在一个比较理想的环境下的,比如和排序相关的问题,绝大部分题目肯定会给你一个数组去存放需要排序的元素,隐含了内存可以一次性将所有数据读入的条件。

但在实际工作中,我们经常会遇到内存中放不下所有数据的排序场景。

早期可能因为内存的容量确实很小,而现在更多是因为我们需要存储的数据越来越大了,甚至不只是内存放不下,单机的硬盘可能也不够了,需要考虑分布式环境下的排序问题,比如在一个分布式数据库中进行超大表的order by操作,这往往需要花费几分钟甚至几小时的运算才能完成。

好言归正传,我们就借助这道经典面试题一起来看看如何解决大量数据的排序问题。

这个经典的算法问题我们一般称之为外部排序,这里的“外”指的其实就是外部存储的意思。

读写较慢的外存,相比快速但昂贵的内存而言,有着更低廉的成本,通常是硬盘,它可以存放更大的数据。当我们不能直接在内存中进行排序,而需要借助外存去处理极大量数据的排序时,就需要使用外部排序算法了。

如果遇到这样的面试题,首先可以来向面试官确认一下已有的硬件环境,比如面试官可能会告诉你,你现在有1GB的内存可用。那么我们知道整个1TB的文件,至少要读1024次才能遍历一遍,所以直接在内存里排序显然是不现实的。

但是文件其实是可以一部分一部分读的,如果内存中一次放不下全部的数据,也许我们可以将文件分成若干段,分别读入内存中,并采用常见的内排序算法(比如堆排序),对这段可以在内存中存储的段落进行排序;得到若干个有序的文件段后,最后通过一些合并的方式,得到整体有序的文件。

当然在这个过程里会有大量的中间结果,比如那些有序的文件片段,这些我们都需要借助外存存储,这个思路就是最常见的一种外部排序的方式。

其实你会发现我们刚刚描述的想法和归并排序如出一辙,归并排序也是常用的外排实现方式,只不过我们在学习它的时候,一般都是针对数组,也就是在内存中排序的场景。

好我们用严谨的语言来重新描述一下基于归并思想的外排过程,整体分为两个阶段:

我们根据内存大小,将待排序的文件拆成多个部分,使得每个部分都是足以存入内存中的。然后选择合适的内排序算法,将多个文件部分排序,并输出到容量可以更大的外存临时文件中,每个临时文件都是有序排列的,我们将其称之为一个“顺段”。

我们对前面的多个“顺段”进行合并,思想和归并排序其实是一样的。以2路归并为例,每次都将两个连续的顺段合并成一个更大的顺段。

因为内存限制,每次可能只能读入两个顺段的部分内容,所以我们需要一部分一部分读入,在内存里将可以确定顺序的部分排列,并输出到外存里的文件中,不断重复这个过程,直至两个顺段被完整遍历。这样经过多层的归并之后,最终会得到一个完整的顺序文件。

举一个简化的例子,配合示意图理解。

假设现在有含有1000个记录的文件,而内存最多只能读取100个记录。那么我们要做的第一步就是先把1000个记录拆成十个文件,每个文件有100个记录,读入后在内存中排序得到10个有序的临时文件,并输出到外存也就是硬盘中。

然后我们进行多次归并操作,每次都把相邻的文件合并。在这个例子中可以看到只需要进行4轮归并,就得到了一个最终有序的文件。

在第一个阶段部分排序中,由于内存可以装下每个顺段的所有元素,所以几种主流的O(nlogn)的算法都是可以的,其中快速排序在大部分场景下是最快的,因此我们可以首选快速排序。

比较复杂的是归并阶段。因为内存不足以装下所有需要排序的元素,所以O(nlogn)的堆排和快排都已经没办法被应用在外排的场景中了,但基于分治思想的归并排序却依然可以很好地发挥作用。

而且相比很多其他排序方式比如选择排序、冒泡排序,归并排序O(nlogn)的复杂度已经是理论上相当好的复杂度了。当然在一些特定场景下我们也可以用一些线性排序算法比如桶排序来解决外部排序问题,感兴趣的同学可以自己搜索了解一下。

相比内存中的读写操作,在磁盘中的读写是一个慢得多的过程,两者之间可能有千倍以上的时间开销差距。所以考虑外排效率时,非常重要的一点就是我们要尽量减少从磁盘中读取数据的耗时,而这主要关系要访问多少次外存。

那我们在外存中需要读取多少次数据呢?从图中其实可以看出来,每一层我们读取外存的数据总量其实是一样的,本质上就是将所有的数据都遍历一遍。

而内存大小是一样的,所以每一层中读取外存的次数也就是一样的,那么显然关系我们读取次数的多少主要就取决于所需归并的层数了。因此,我们要做的事情就是让归并的层数越低越好。

怎么样做到这件事呢?答案很简单也很直观,就是增加更多的归并路数或者降低初始的顺段数量。

我们先算出归并层数,以2路归并为例,每次合并两个连续的顺段,如果上一层有n个顺段,到下一层就会有n/2个顺段,每一层的顺段都会减少一半,直至只剩一个顺段,也就是需要的排序结果。因而,假设初始一共有n个顺段,那么我们大致需要log2n层。

同样的道理,如果进行k路归并,每一层的顺段数量都会变成上一层的1/k,所以就大概只需要logk(n)层即可完成整个归并。比如一个5路归并的例子。

所以,为了增加归并路数,也就是尽量增加k。

另外为了降低初始n个顺段的数量,我们会做的事情也很简单,就是在第一次进行逐段内排序的时候尽可能多地将数据读入内存中并进行内排。

但是增加k的大小,其实也会导致每次归并的时候合并的成本变大,一个显著的问题就是在k路归并中,我们需要从k个元素中选择出最小的元素,代价比2路归并的更高。如果用最暴力的方式,遍历k个元素,每次选择最小的元素的过程将产生O(k)的时间复杂度,这一定程度上会抵消前面通过增加k减少磁盘IO所带来的时间提升。

但是我们仔细想想这个问题,选择k个元素中的最小元素,显然有优于暴力遍历O(k)复杂度的算法。比如,上一讲介绍的堆就可以解决这个问题。

而败者树,则是解决从k个元素中选取最小元素并可以动态更新的另一种方法,也是更广泛运用于多路归并中的算法,我们来学习一下它的思路。

败者树也被称为,淘汰赛树,也就是Tournament Tree,思想来自体育比赛。

我们知道在淘汰赛中,每一场比赛都有两个参与者,其中胜者可以晋级下一轮。整体可以画成一颗树的形状,如果看过足球比赛,相信你对这个图一点也不陌生。

败者树算法就是基于这一思想实现的,我们用叶子节点存储所有待比较的元素,对叶子结点两两比赛,在它们共同的父节点中存储失败者;然后对获胜者节点再两两比较,得到更上一层的败者,取出胜者继续往上比较,这个过程和归并的思路其实也是比较相似的;这样一层一层往上比较,最后就可以得到一颗锦标赛状的树。

因为除了叶子结点外的每一层的父节点存储的都是其子节点中的失败者,所以我们称其为败者树。根节点我们会稍微做一点特别的处理,除了在根结点存储失败者,同时,我们在根节点之上会悬挂上整棵树的最终获胜者。

我们可以给刚刚的例子画出对应的败者树,大概就是下面这个图的样子。其中根节点上的方框存储的就是整个树的胜者,也就是1,它一定是所有元素中的最小值,和锦标赛的冠军是一个意思。

至于为什么在节点中存储的是失败者,而不是获胜者呢?就留给你做课后思考题啦。事实上,在父节点中存储获胜者的树也是存在的,和你想的一样,我们也称之为胜者树。

和堆一样,我们也会需要对败者树进行类似于出队的操作;在上面的例子中,就是我们需要将1从败者树中取出,寻找下一个最小的元素。

这里有两种情况,一种是我们取出1之后,用一个新的元素替代1,另一种就是取出1之后不再添加新的元素,分别对应某一路元素被取出之后仍有元素未取完,和该路元素已经全部取出的情况。在这两种情况中,我们其实都只需要对整个树重新比赛一次即可,只是在第二种情况里,我们会用一个无限大的数字替换1,因为无限大的数字一定不会在这次重赛中胜出。

因为原来的获胜者已经被取走了,这里的父节点现在存储的其实就是这颗子树中原来的亚军,如果我们要看这次新来的选手能否能成为新的冠军,只需要和原来的亚军进行一次比较即可;当然这次比较结束后,两者中的胜者还需要到更上一层继续比较。

这个过程和运动员从市队、省队一路选拔到国家队参加奥运会的过程也是颇为神似的,希望这个例子能帮助你更好地理解败者树的工作机制。

整个过程写成伪代码如下:

然后在归并排序的每一次合并中,只需要进行replay操作,从新元素到根路径上逐一重赛。在每一层中,只需要进行一次比较。由于树是平衡的,从叶子结点到根路径仅包含 O(logk) 元素(这里高度的计算和之前讲解堆的推导是差不多的,你可以复习之前的章节)。所以,总的时间复杂度为 O(klog k) 。

现在有了败者树的加持,多路归并排序就可以比较高效地解决外部排序的问题了。对于1TB任意文本的排序问题,大致思路就是:

这里稍微补充一下,看起来我们每次从文件中只读取了一个单词,但操作系统在读文件的时候是会按页为单位读取并缓存下来的,所以某一次磁盘访问之后的若干次访问,其实都会直接命中cache,也就是说,并不是每次从败者树中取出元素时都会真的产生磁盘IO,请不用担心。

随着互联网的发展,数据量一直在稳步的提升,许多算法问题都不能只简单地考虑内存中可以存储,甚至单机磁盘可以存储的情况了。相信我们今天学习的外排算法思想,一定会给你一些解决此类问题的启发,希望你可以举一反三在实际生产中也能将算法更好地运用在有各种限制的真实环境中。

借鉴内排中归并排序的想法,我们可以实现一个多路归并的外排算法,解决内存空间不足的问题。但也因为涉及外部存储,需要重点考虑IO的成本。通过尽可能多地利用内存中的排序,得到尽量少的初始顺段,以及选择合适的多路归并参数,我们就可以做到外存访问次数尽量少了。

最后留两个思考题。

欢迎你留言与我讨论。如果有收获也欢迎你转发给身边的朋友,邀他一起学习。我们下节课见~

THE END
0.数据结构——多路平衡归并与败者树败者树是一种特殊的完全二叉树,它可以看作是锦标赛树(也称胜者树)的变形。在锦标赛树中,每个内部节点保存其两个子节点中的"胜者"(关键字较小的记录);而在败者树中,每个内部节点保存的是"败者"(关键字较大的记录),最终的胜者保存在树根的父节点中。 jvzquC41dnuh0lxfp0tfv8}kcqyb7;6345:67=8431gsvrhng1jfvjnnu17669624::
1.胜者树和败者树锦标赛树是胜者树吗本文详细介绍了胜者树和败者树的概念及应用,重点阐述了这两种数据结构如何帮助快速找到最大或最小值,并通过实例展示了它们在k路归并排序中的作用。 转自:http://blog.csdn.net/whz_zb/article/details/7425152 胜者树与败者树 胜者树和败者树都是完全二叉树,是树形选择排序的一种变型。每个叶子结点相当于一个选手jvzquC41o0hmqp3euft/pny1uwtngwliocom1jwvkerf1mjvckrt1@:499=6
2.堆排序与归并排序|Diffday堆排序的后半部分算法中,就是一个很明确的,多个值中选取极值,取出极值,更新根,然后修复堆的过程。在多路归并排序中,每次取出极值后,堆长度未变 胜者树 树排,全称可叫树形选择排序,因为其排序过程和体育比赛中的8进4, 4进2, 2争冠非常相似,所以树排又称为锦标赛排序,且树排中用到的树就是胜者树(8进4,4进2,2争冠嘛) 树排算法很简单:jvzq<84o0foghmf{0eun1.J7'C6&:?*G8'>F'B7'G7+CC.=H'G:&DA*:G'K6'KI';4+F7.G;'D<&G?*:G'?3'N:'DC+9H7mvon
3.#多路平衡归并排序(胜者树败者树)腾讯云开发者社区多路归并排序用作大数据集合的排序,通常因为内存资源不足,只能分段排序。 多路归并通常结合二叉树进行排序即败者树与胜者树。 胜者树:每次筛选最小值作为根结点 败者树:每次筛选最大值作为根节点 平衡指将大集合平分为多个相同元素个数的集合,唯一与置换置换选择排序的不同之处 jvzquC41enuvf7ygpekov7hqo0io1mjxgnuqg{4ctvodnn4372792B
4.排序算法详解稳定性:就选择排序方法来讲是稳定的,但教程中实现的方法是不稳定的 可用于链式存储结构 移动记录次数较少,当每一记录占用的空间较多时,此方法比直接插入排序快 8.4.2、树形选择排序 树形选择排序,又称锦标赛排序(理解即可) 转载于,又做了些更改树形选择排序 jvzquC41dnuh0lxfp0tfv8hjqpmzcwla1cxuklqg1fkucrqu1371999928
5.winnertree胜者树Loull在树形选择排序中,利用锦标赛思想建立的树称为胜者树。 1、每个非终端节点存储的是左右孩子节点中的优胜者。 2、通过减少比较次数,提高效率。 3、胜者树就是一颗特殊的线段树。 一、构建树 Procedure buildmint; 复杂度 O(n)vari,j,k:longint;begini:=N; j:=N+n-1;{其中N 为大于等于 n 的最小 2 jvzquC41yy}/ewgnqiy/exr176?3;=7:81v05@=278>/j}rn
6.胜者树与败者树胜者树和败者树都是完全二叉树,是树形选择排序的一种变型。每个叶子结点相当于一个选手,每个中间结点相当于一场比赛,每一层相当于一轮比赛。 不同的是,胜者树的中间结点记录的是胜者的标号;而败者树的中间结点记录的败者的标号。 胜者树与败者树可以在log(n)的时间内找到最值。任何一个叶子结点的值改变后,利用jvzquC41dnuh0lxfp0tfv8|j|a€c1jwvkerf1mjvckrt1@9473;3
7.一文读懂胜者树与败者树腾讯云开发者社区胜者树和败者树是在排序和归并排序算法中常用的两种数据结构,它们在大规模数据排序中具有高效性和良好的稳定性。本篇博客将详细介绍这两种数据结构。 1.为什么要使用外部排序? 外部排序是用于对超出计算机内存容量的大型数据集进行排序的一种算法。在排序过程中,需要将数据集分成多个较小的子集,并在内存中对每个子集进jvzquC41enuvf7ygpekov7hqo1jfxnqqrgx0c{ykenk04;8:856
8.排序(二)键索引桶排序位示图败者树等(图文详解败者树)本文深入探讨了排序算法的不同类型,包括比较排序与非比较排序。详细介绍了键索引计数法、基数排序、桶排序等非比较排序算法的工作原理及其应用场景,并对比了它们与快速排序等比较排序算法的优缺点。 排序(二) 以上排序算法都有一个性质:在排序的最终结果中,各元素的次序依赖于它们之间的比较。我们把这类排序算法称为jvzquC41dnuh0lxfp0tfv8~cpiezwujk1cxuklqg1fkucrqu14=35@=2;
9.#树形选择排序(锦标赛排序)腾讯云开发者社区# 树形选择排序(锦标赛排序) # 原理 代码语言:javascript 代码运行次数:0 运行 AI代码解释 将无序集合进行两两分组排序,将找出的每组的最小值再进行两两排序,以此模式直到找出最小的值,将这个值纪录下来并从第一次两两分组的排序集合中移除这个值,然后进行第二轮,直到排序结束。 代码语言:javascript 代码运行次数:0 运行 AI代码解 jvzquC41yy}/eutwf0zfpljpv0ipo8igxgrprnw1ctzjeuj13762:99
10.锦标赛排序希尔排序 ShellSort() 选择排序(SelectionSort.h) 1.简单选择排序 SimpleSelectionSort(int *array, int length) 2.锦标赛排序(树选择排序)TournamentSort(int *array, int length) 或 TreeSelectionSort(int *array, int length) 3.堆排序 HeapSort(int *array, int length) 交换排序(ExchangeSort.h) 1.jvzquC41yy}/k}j{g0ipo8wguq{sen4w2363:<699/;37=:2:
11.#置换选择排序腾讯云开发者社区# 树形选择排序(锦标赛排序) 排序原理 # 树形选择排序(锦标赛排序) # 原理将无序集合进行两两分组排序,将找出的每组的最小值再进行两两排序,以此模式直到找出最小的值,将这个值纪录下来并从第一次两两分组的排序集合中移除这个值,然后进行第二轮,直到排序结束。原始集合:{5,2,4,6,8,1,9,7,10,3} 第一jvzquC41enuvf7ygpekov7hqo1jfxnqqrgx0c{ykenk03>53:2<
12.外排序外排序的第一步是什么本文介绍了外排序算法,一种处理大规模数据集的排序方法。当数据量超过内存容量时,外排序利用磁盘存储来实现数据排序。文章详细阐述了外排序的基本流程,包括通过多次读取和排序内存中的数据块,最终将所有数据合并成一个有序文件的过程。 外排序(External sorting)是指能够处理极大量数据的排序算法。通常来说,外排序处理jvzquC41dnuh0lxfp0tfv8hjngrf2:571cxuklqg1fkucrqu1:<58A69
13.电子教案《数据结构(C++版)(第二版)》李根强.ppt树形选择排序(Tree Selection Sorting),又称锦标赛排序(Tournament Sorting),是一种按照锦标赛的思想进行选择排序的方法。首先对n个记录的排序码进行两两比较,然后在其中?n/2?个较小者之间再进行两两比较,如此重复,直到选出最小排序码为止。 例如,给定排序码50,37,66,98,75,12,26,49,树形选择排序的过程见图jvzquC41oc~/dxtm33>/exr1jvsm1;5431623:4736:33:5662643:50ujzn
14.数据结构试卷(手动组卷).doc试对这种序列讨论各种简单排序方法的时间复杂度。 (6分)[47] 试问:按锦标赛排序的思想,决出八名运动员之间的名次排列,至少需编排多少场次的比赛(应考虑最坏的情况) (7分)[48]不难看出,对长度为n的记录序列进行快速排序时,所需进行的比较次数依赖于这n个元素的初始排列。试问:当n为7时,在最好情况下需进行jvzquC41oc~/dxtm33>/exr1jvsm1;5431722@4:34=18<5262652<80ujzn
15.pg破解版无限金币在线玩官方版pg破解版无限金币在线玩最新版V.2.78.87 安卓版-2265安卓网-对阵活塞前瞻,谢泼德面临巨大考验,活塞去年5号秀或成火箭难题】🔵支持:32/64bi🔵系统类型:(官方)官方网站IOS/Android通用版/手机APP(2025APP下载)《pg破解版无限金币在线玩》虽然夏季联赛的比赛,对于火箭队这支去年已经打入季后赛,并且拿到常规赛西部第jvzq<84t0unbpmtpifkkw{jpjg4dqv4
16.外部排序(败者树置换选择排序最佳归并树)4)赢者树与败者树 外部排序可能会考查相关概念、方法和排序过程。外部排序的算法比较复杂,不会在算法设计上进行考查。 一、外部排序的基本概念与方法 外部排序指待排序文件较大,内存无法一次全部存储,需存放在外存的文件的排序。 1. 基本概念 在许多应用中,经常需要对大文件进行排序,因为文件中的记录很多,无法将整个文件jvzquC41dnuh0lxfp0tfv8|gkzooa=>494:658ftvkimg8igvcomu86633725=<
17.数据结构与算法系列随笔分类海米傻傻数据结构与算法系列——排序(6)_树形选择排序 摘要:1. 工作原理(定义) 树形选择排序(Tree Selection Sort),又称锦标赛排序(Tournament Sort),是一种按照锦标赛思想进行选择排序的方法。 首先对n个记录的关键字进行两两比较,然后在其中[n/2](向上取整)个较小者之间再进行两两比较,如此重复,直至选出最小关键jvzquC41yy}/ewgnqiy/exr1jconk|mcujg0ejygiqxz1:98:4:20qyon
18.败者树的概念败者树的高度败者树是一种树形数据结构,用于高效地查找集合中最小(或最大)的元素。它特别适用于需要频繁进行查找最小值操作的场景,例如在锦标赛、优先队列或堆排序算法的优化中。 不同于二叉堆,败者树更侧重于快速找到最小值,而非高效地插入或删除元素。 核心思想: jvzquC41dnuh0lxfp0tfv8|gkzooa=>5646968ftvkimg8igvcomu86649:56;9
19.最完整数据结构外部排序指南:从败者树到置换选择排序实战排序阶段:对每个子文件进行内部排序 归并阶段:多遍归并有序子文件得到最终结果 败者树:优化多路归并的核心数据结构 败者树(Loser Tree)是实现多路平衡归并的高效数据结构,相比传统锦标赛树可将比较次数从O(nm)降低至O(nlogm)(n为数据量,m为归并路数)。 jvzquC41dnuh0lxfp0tfv8lkvdrpih52;960c{ykenk0fnyckny03>97;5974
20.算法排序(2)锦标赛排序扬羽流风算法-排序(2)锦标赛排序 用完全二叉树定义胜者树,前n-1个结点t[1]~t[n-1]为内部结点(胜者),后n个结点e[1]~e[n]是参赛者。 t数组存的是参赛者编号,即e[t[0]]才是最终胜者的值 template <classT>classWinnerTree{public:constT maxValue=9999; WinnerTree(intTreeSize=20):maxSize(TreeSize),njvzquC41yy}/ewgnqiy/exr1{cth{~qkwhkoi8u132=32:650jznn
21.完全二叉堆与左式堆详解锦标赛排序 可见,锦标赛树是将叶子节点中的较小者作为根来连接叶子节点,并逐步比较至根。所有的内部节点都是与兄弟节点比较的优胜者。 锦标赛树每个叶子节点都是选手,内部节点记录比赛的胜者(较小者),而败者树相反,父节点记录比赛中的失败者,然后胜者继续参与下一轮比赛,最后增设根节点的父节点来记录冠军。 jvzquC41dnuh0lxfp0tfv8vsa5639@75;1gsvrhng1jfvjnnu1715:=:7:?
22.内部排序算法1(插入排序)2. 适用于单链表的排序方法有:直接插入排序、气泡排序、简单选择排序、归并排序和基数排序。 3. 适用于树形排序的排序方法有:锦标赛排序(胜者树)、多路归并排序(败者树)、 二叉查找树排序、堆排序等。 排序算法的介绍 1. 插入排序 思路 将待排序的子序列中的一个元素按其排序码的大小插入到已经排好序的有序子jvzquC41dnuh0lxfp0tfv8z233=96=>71cxuklqg1fkucrqu19695;87:
23.胜者树分析如何实现可以保证锦标赛排序的稳定性?假设选大者作为胜者,如果两个孩子相等的时候,我们选择秩更大的节点,作为父节点。就是说创建一个结构体,额外保存一下秩的信息。每次比较,我们不仅比较数值的大小,如果数值相等的时候,我们根据秩的大小来确认节点之间的先后顺序,保证锦标树排序的稳定性。 jvzquC41dnuh0lxfp0tfv8Q5328379:881gsvrhng1jfvjnnu1766?;2:4?
24.面试刷题107csigan笔记堆排序比其他排序好在那里?(时间)稳定性?快排什么时候O(nlgn)退化O(n^2),堆一直O(nlgn)。后来大佬说他没有说时间,说的是排序稳定性。那么堆不是稳定的,都怪电话听不清,这锅我不背啊。 海量数据找TopN。锦标赛排序,败者树。大根堆,小根堆。 完全二叉树,满二叉树。红黑树的几个性质。 jvzquC41dnuh0lxfp0tfv8|yz{7:;>4ctvodnn4fgvgjn|432487;;85