数组长度都被划分成长度比例为1:9的两个子数组长度,这种情况下的排序时间复杂度是多少

实现/快速排序
快速排序的实现基于分治法,具体分为三个步骤。假设待排序的序列为L[m..n]。分解:序列L[m..n]被划分成两个可能为空的子序列L[m..pivot-1]和L[pivot+1..n],使L[m..pivot-1]的每个元素均小于或等于L[pivot],同时L[pivot+1..n]的每个元素均大于L[pivot]。其中L[pivot]称为这一趟分割中的主元(也称为枢轴、支点)。解决:通过递归调用快速排序,对子序列L[m..pivot-1]和L[pivot 1..r]排序。合并:由于两个子序列是就地排序的,所以对它们的合并不需要操作,整个序列L[m..n]已排好序。
性质/快速排序
内部排序快速排序是一种。也就是说快速排序的排序对象是读入内存的数据。比较排序快速排序确定元素位置的方法基于元素之间关键字大小的比较。所有基于比较方法的排序方法的时间下界不会低于O(nlgn)。这个结论的具体证明,请参考有关算法的书籍,例如《》第8章。快速排序在理想情况下,能严格地达到O(nlgn)的下界。一般情况下,快速排序与随机化快速排序的平均情况性能都达到了O(nlgn)。不稳定性快速排序是一种不稳定的排序方法。简单地说,元素a1,a2的关键字有a1.key=a2.key,则不稳定的排序方法不能保证a1,a2在排序后维持原来的位置先后关系。在排序的具体操作过程中,除去程序运行实现的空间消费(例如递归栈),只需消耗确定数量的空间(即S(1),常数级空间)。这个性质的意义,在于在内存空间受到限制的系统(例如MCU)中,快速排序也能够很好地工作。
时空复杂度/快速排序
快速排序每次将待排序数组分为两个部分,在理想状况下,每一次都将待排序数组划分成等长两个部分,则需要logn次划分。而在最坏情况下,即数组已经有序或大致有序的情况下,每次划分只能减少一个元素,快速排序将不幸退化为冒泡排序,所以快速排序时间复杂度下界为O(nlogn),最坏情况为O(n^2)。在实际应用中,快速排序的平均时间复杂度为O(nlogn)。快速排序在对序列的操作过程中只需花费常数级的空间。空间复杂度S(1)。但需要注意递归栈上需要花费最少logn最多n的空间。
随机化算法/快速排序
快速排序的最坏情况基于每次划分对主元的选择。基本的快速排序选取第一个元素作为主元。这样在数组已经有序的情况下,每次划分将得到最坏的结果。一种比较常见的优化方法是随机化算法,即随机选取一个元素作为主元。这种情况下虽然最坏情况仍然是O(n^2),但最坏情况不再依赖于输入数据,而是由于随机函数取值不佳。实际上,随机化快速排序得到理论最坏情况的可能性仅为1/(2^n)。所以随机化快速排序可以对于绝大多数输入数据达到O(nlogn)的期望时间复杂度。一位前辈做出了一个精辟的总结:“随机化快速排序可以满足一个人一辈子的人品需求。”随机化快速排序的唯一缺点在于,一旦输入数据中有很多的相同数据,随机化的效果将直接减弱。对于极限情况,即对于n个相同的数排序,随机化快速排序的时间复杂度将毫无疑问的降低到O(n^2)。
减少递归栈使用的优化/快速排序
快速排序的实现需要消耗递归栈的空间,而大多数情况下都会通过使用系统递归栈来完成递归求解。在元素数量较大时,对系统栈的频繁存取会影响到排序的效率。一种常见的办法是设置一个阈值,在每次递归求解中,如果元素总数不足这个阈值,则放弃快速排序,调用一个简单的排序过程完成该子序列的排序。这样的方法减少了对系统递归栈的频繁存取,节省了时间的消费。一般的经验表明,阈值取一个较小的值,排序算法采用选择、插入等紧凑、简洁的排序。一个可以参考的具体方案:阈值T=10,排序算法用选择排序。阈值不要太大,否则省下的存取系统栈的时间,将会被简单排序算法较多的时间花费所抵消。另一个可以参考的方法,是自行建栈模拟递归过程。但实际经验表明,收效明显不如设置阈值。
C例程/快速排序
以下是C语言权威《TheCProgrammingLanguage》中的例程,在这个例程中,对于数组v的left到right号元素以递增顺序排序。//.cbyTydus.#include&stdio.h&intarr[] = {14,10,11,5,6,15,0,15,16,14,0,8,17,15,7,19,17,1,18,7};/*swap函数:交换v与v[j]的值*/inlinevoidswap(intv[],inti,){&&& int temp = 0;&&& temp =&&& v = v[j];&&& v[j] =}voidqsort(intv[],intleft,intright){&&& inti = 0&&& int last = 0;&&& voidswap(intv[],inti,intj);&&& if(left &= right)/*若数组包含的元素个数少于两个*/&&&&&&&/*则不执行任何操作*/&&& swap(v,left,(left right) / 2);/*将划分子集的元素*/&&& last =/*移动到v[0]*/&&& for(i = left 1; i &= i )/*划分子集*/&&& if(vswap(v, last,i);&&&&&&& swap(v,left,last);/*恢复划分的元素*/&&& qsort(v,left,last - 1);&&& qsort(v,last 1,right);}intmain(void){&&& qsort(arr,0,19);&&& inti = 0;&&& for(i = 0; i &= 19; printf("%d",arr[i ]));&&&&&&& scanf("\n");&&& return 0;}
使用C 标准库的快速排序函数/快速排序
C 的标准库stdlib.h中提供了快速排序函数。请在使用前加入对stdlib.h的引用:#include或#includeqsort(void*base,size_tnum,size_twidth,int(*)compare(constvoid*elem1,constvoid*elem2))参数表*base:待排序的元素(数组,下标0起)。num:元素的数量。width:每个元素的内存空间大小(以字节为单位)。可用sizeof()测得。int(*)compare:指向一个比较函数。*elem1*elem2:指向待比较的数据。比较函数的返回值返回值是int类型,确定elem1与elem2的相对位置。elem1在elem2右侧返回正数,elem1在elem2左侧返回负数。控制返回值可以确定升序/降序。一个升序排序的例程:intCompare(constvoid*elem1,constvoid*elem2){return*((int*)(elem1))-*((int*)(elem2));}intmain(){inta[100];qsort(a,100,sizeof(int),Compare);return0;}
算法基本思想/快速排序
快速排序的基本思想是基于的。对于输入的子序列L【p..r】,如果规模足够小则直接进行排序(比如用前述的冒泡、选择、插入排序均可),否则分三步处理:分解(Divide):将待排序列L【p..r】划分为两个非空子序列L【p..q】和L【q 1..r】,使L【p..q】中任一元素的值不大于L【q 1..r】中任一元素的值。具体可通过这样的途径实现:在L【p..r】中选择数据元素L【q】,经比较和移动后,L【q】将处于L【p..r】中间的适当位置,使得L【q】的值小于L【q 1..r】中任一元素的值。 递归求解(Conquer):通过递归调用快速排序算法,分别对L【p..q】和L【q 1..r】进行排序。 合并(Merge):由于对分解出的两个子序列的排序是就地进行的,所以在L【p..q】和L【q 1..r】都排好序后不需要执行任何计算L【p..r】就已排好序,即自然合并。 这个解决流程是符合分治法的基本步骤的。因此,是分治法的经典应用实例之一。
区别/快速排序
快速排序法是对的一种改进,也是基于交换排序的一种算法。因此,被称为"分区交换排序"。在待排序序列中按某种方法选取一个元素K,以它为分界点,用交换的方法将序列分为两个部分:比该值小的放在左边,否则在右边。形成"{左子序列}K{右子序列}"。再分别对左、右两部分实施上述分解过程,直到各子序列长度为1,即有序为止。分界点元素值K的选取方法不同,将构成不同的排序法,也将影响排序的效率:例如,可取左边第1个元素为分界点、取中点A【(left right)/2】为分界点、或选取最大和最小值的平均值为分界点等。
伪代码&/快速排序
QUICKSORT(A,p,r)
2 then&q&←PARTITION(A,p,r)
3 QUICKSORT(A,p,q-1)
4 QUICKSORT(A,q+1,r)
为排序一个完整的数组A,最初的调用是QUICKSORT(A,1,length[A])。
快速排序算法的关键是PARTITION过程,它对子数组A[p..r]进行就地重排:
PARTITION(A,p,r)
1 x←A[r]
3 for&j←p&to&r-1
4 do&if&A[j]≤x
5 then&i←i+1
6 exchange&A[i]←→A[j]
7 exchange&A[i+1]←→A[r]
8 return&i+1[2]&随机&
对PARTITION和QUICKSORT所作的改动比较小。在新的划分过程中,我们在真正进行划分之前实现交换:
(其中PARTITION过程同快速排序伪代码(非随机))
RANDOMIZED-PARTITION(A,p,r)
1 i←&RANDOM(p,r)
2 exchange&A[r]←→A[i]
3 return&PARTITION(A,p,r)
新的快速排序过程不再调用PARTITION,而是调用RANDOMIZED-PARTITION。
RANDOMIZED-QUICKSORT(A,p,r)
2 then&q←&RANDOMIZED-PARTITION(A,p,r)
3 RANDOMIZED-QUICKSORT(A,p,q-1)
4 RANDOMIZED-QUICKSORT(A,q+1,r)[2]&性能分析&
这里为方便起见,我们假设算法Quick_Sort的范围阈值为1(即一直将线性表分解到只剩一个元素),这对该算法复杂性的分析没有本质的影响。
我们先分析函数partition的性能,该函数对于确定的输入复杂性是确定的。观察该函数,我们发现,对于有n个元素的确定输入L[p..r],该函数运行时间显然为θ(n)。
无论适用哪一种方法来选择pivot,由于我们不知道各个元素间的相对大小关系(若知道就已经排好序了),所以我们无法确定pivot的选择对划分造成的影响。因此对各种pivot选择法而言,最坏情况和最好情况都是相同的。
我们从直觉上可以判断出最坏情况发生在每次划分过程产生的两个区间分别包含n-1个元素和1个元素的时候(设输入的表有n个元素)。下面我们暂时认为该猜测正确,在后文我们再详细证明该猜测。
对于有n个元素的表L[p..r],由于函数Partition的计算时间为θ(n),所以快速排序在序坏情况下的复杂性有递归式如下:
T(1)=θ(1),T(n)=T(n-1)+T(1)+θ(n)&(1)
用迭代法可以解出上式的解为T(n)=θ(n2)。
这个最坏情况运行时间与插入排序是一样的。
下面我们来证明这种每次划分过程产生的两个区间分别包含n-1个元素和1个元素的情况就是最坏情况。
设T(n)是过程Quick_Sort作用于规模为n的输入上的最坏情况的时间,则
T(n)=max(T(q)+T(n-q))+θ(n),其中1≤q≤n-1&(2)
我们假设对于任何k&n,总有T(k)≤ck,其中c为常数;显然当k=1时是成立的。
将归纳假设代入(2),得到:
T(n)≤max(cq2+c(n-q)2)+θ(n)=c*max(q2+(n-q)2)+θ(n)
因为在[1,n-1]上q2+(n-q)2关于q递减,所以当q=1时q2+(n-q)2有最大值n2-2(n-1)。于是有:
T(n)≤cn2-2c(n-1)+θ(n)≤cn2
只要c足够大,上面的第二个小于等于号就可以成立。于是对于所有的n都有T(n)≤cn。
这样,排序算法的最坏情况运行时间为θ(n2),且最坏情况发生在每次划分过程产生的两个区间分别包含n-1个元素和1个元素的时候。
时间复杂度为o(n2)。
如果每次划分过程产生的区间大小都为n/2,则快速排序法运行就快得多了。这时有:
T(n)=2T(n/2)+θ(n),T(1)=θ(1)&(3)
解得:T(n)=θ(nlogn)
快速排序法最佳情况下执行过程的递归树如下图所示,图中lgn表示以10为底的对数,而本文中用logn表示以2为底的对数.
由于快速排序法也是基于比较的排序法,其运行时间为Ω(nlogn),所以如果每次划分过程产生的区间大小都为n/2,则运行时间θ(nlogn)就是最好情况运行时间。
但是,是否一定要每次平均划分才能达到最好情况呢?要理解这一点就必须理解对称性是如何在描述运行时间的递归式中反映的。我们假设每次划分过程都产生9:1的划分,乍一看该划分很不对称。我们可以得到递归式:
T(n)=T(n/10)+T(9n/10)+θ(n),T(1)=θ(1)&(4)
请注意树的每一层都有代价n,直到在深度log10n=θ(logn)处达到边界条件,以后各层代价至多为n。递归于深度log10/9n=θ(logn)处结束。这样,快速排序的总时间代价为T(n)=θ(nlogn),从渐进意义上看就和划分是在中间进行的一样。事实上,即使是99:1的划分时间代价也为θ(nlogn)。其原因在于,任何一种按常数比例进行划分所产生的递归树的深度都为θ(nlogn),其中每一层的代价为O(n),因而不管常数比例是什么,总的运行时间都为θ(nlogn),只不过其中隐含的常数因子有所不同。(关于算法复杂性的渐进阶,请参阅算法的复杂性)平均情况
快速排序的平均运行时间为θ(nlogn)。
我们对平均情况下的性能作直觉上的分析。
要想对快速排序的平均情况有个较为清楚的概念,我们就要对遇到的各种输入作个假设。通常都假设输入数据的所有排列都是等可能的。后文中我们要讨论这个假设。
当我们对一个随机的输入数组应用快速排序时,要想在每一层上都有同样的划分是不太可能的。我们所能期望的是某些划分较对称,另一些则很不对称。事实上,我们可以证明,如果选择L[p..r]的第一个元素作为支点元素,Partition所产生的划分80%以上都比9:1更对称,而另20%则比9:1差,这里证明从略。
平均情况下,Partition产生的划分中既有“好的”,又有“差的”。这时,与Partition执行过程对应的递归树中,好、差划分是随机地分布在树的各层上的。为与我们的直觉相一致,假设好、差划分交替出现在树的各层上,且好的划分是最佳情况划分,而差的划分是最坏情况下的划分。在根节点处,划分的代价为n,划分出来的两个子表的大小为n-1和1,即最坏情况。在根的下一层,大小为n-1的子表按最佳情况划分成大小各为(n-1)/2的两个子表。这儿我们假设含1个元素的子表的边界条件代价为1。
在一个差的划分后接一个好的划分后,产生出三个子表,大小各为1,(n-1)/2和(n-1)/2,代价共为2n-1=θ(n)。一层划分就产生出大小为(n-1)/2+1和(n-1)/2的两个子表,代价为n=θ(n)。这种划分差不多是完全对称的,比9:1的划分要好。从直觉上看,差的划分的代价θ(n)可被吸收到好的划分的代价θ(n)中去,结果是一个好的划分。这样,当好、差划分交替分布划分都是好的一样:仍是θ(nlogn),但θ记号中隐含的常数因子要略大一些。关于平均情况的严格分析将在后文给出。
在前文从直觉上探讨快速排序的平均性态过程中,我们已假定输入数据的所有排列都是等可能的。如果输入的分布满足这个假设时,快速排序是对足够大的输入的理想选择。但在实际应用中,这个假设就不会总是成立。
解决的方法是,利用随机化策略,能够克服分布的等可能性假设所带来的问题。
一种随机化策略是:与对输入的分布作“假设”不同的是对输入的分布作“规定”。具体地说,在排序输入的线性表前,对其元素加以随机排列,以强制的方法使每种排列满足等可能性。事实上,我们可以找到一个能在O(n)时间内对含n个元素的数组加以随机排列的算法。这种修改不改变算法的最坏情况运行时间,但它却使得运行时间能够独立于输入数据已排序的情况。
另一种随机化策略是:利用前文介绍的选择支点元素pivot的第四种方法,即随机地在L[p..r]中选择一个元素作为支点元素pivot。实际应用中通常采用这种方法。
快速排序的随机化版本有一个和其他随机化算法一样的有趣性质:没有一个特别的输入会导致最坏情况性态。这种算法的最坏情况性态是由随机数产生器决定的。你即使有意给出一个坏的输入也没用,因为随机化排列会使得输入数据的次序对算法不产生影响。只有在随机数产生器给出了一个很不巧的排列时,随机化算法的最坏情况性态才会出现。事实上可以证明几乎所有的排列都可使快速排序接近平均情况性态,只有非常少的几个排列才会导致算法的近最坏情况性态。
一般来说,当一个算法可按多条路子做下去,但又很难决定哪一条保证是好的选择时,随机化策略是很有用的。如果大部分选择都是好的,则随机地选一个就行了。通常,一个算法在其执行过程中要做很多选择。如果一个好的选择的获益大于坏的选择的代价,那么随机地做一个选择就能得到一个很有效的算法。我们在前文已经了解到,对快速排序来说,一组好坏相杂的划分仍能产生很好的运行时间[2]&。因此我们可以认为该算法的随机化版本也能具有较好的性态。
显示方式: |
计算机科学
共有124个词条
万方数据期刊论文
计算机学报
万方数据期刊论文
电力系统自动化
万方数据期刊论文
电脑与信息技术
&|&相关影像
互动百科的词条(含所附图片)系由网友上传,如果涉嫌侵权,请与客服联系,我们将按照法律之相关规定及时进行处理。未经许可,禁止商业网站等复制、抓取本站内容;合理使用者,请注明来源于www.baike.com。
登录后使用互动百科的服务,将会得到个性化的提示和帮助,还有机会和专业认证智愿者沟通。
此词条还可添加&
编辑次数:14次
参与编辑人数:12位
最近更新时间: 16:15:43
贡献光荣榜
扫码下载APP赞助商链接
当前位置: >>
第8讲 排序 (1)
8.1 8.2 8.3 8.4 8.5 8.6排序的基本概念 插入排序 交换排序 归并排序 基数排序 各种排序算法的性能比较 本章主要知识点:●● ● ●●● ●排序的基本概念和衡量排序算法优劣的标准, 其中衡量标准有算法的时间复杂度、空间复杂 度和稳定性 直接插入排序,希尔排序 直接选择排序,堆排序 冒泡排序,快速排序 归并排序 基数排序 各种排序算法的性能比较 8.1 排序的基本概念 排序是对数据元素序列建立某种有序排 列的过程。 关键字是要排序的数据元素集合中的一 个域,排序是以关键字为基准进行的。 关键字分主关键字和次关键字两种。对 要排序的数据元素集合来说,如果关键字 满足数据元素值不同时该关键字的值也一 定不同,这样的关键字称为主关键字。 不满足主关键字定义的关键字称为次关 键字。 学生成绩表序号 0 1 2 3...学号 12 1008...姓名 Wang Yun Zhang Pen Li Cheng Chen Hong...数学 84.0 75.0 90.0 80.0...语文 70.0 88.0 84.0 95.0...物理 78.0 92.0 66.0 77.0...英语 77.0 85.0 80.0 84.3...n-11022Chu San90.095.088.0100.0 要排序的数据可能是整数、浮点数、字符或者对象 ?为了简单起见,本章假设:?? ? ?要排序是数据是整数 数据以升序排列 数据存储在数组中5 比较两个关键字大小 将记录从一个位置移动到另一个位置 排序分内部排序和外部排序两种。内部排序 是把待排数据元素全部调入内存中进行的排序。 如果数据元素的数量太大,需要分批导入内存, 分批导入内存的数据元素排好序后再分批导出到 磁盘和磁带外存介质上的排序方法称作外部排序。 排序算法的比较标准: 1. 空间复杂度 2. 时间复杂度 3. 稳定性 基本思想:每步将一个待排序的记录,按其 关键字值的大小插入到前面已经排序的文件 中适当的位置上,直到全部插完为止。 8.2.1 直插入排序 直接插入排序的基本思想是:顺序地把待排 序的数据元素按其值的大小插入到已排序数据元 素子集合的适当位置。子集合的数据元素个数从 只有一个数据元素开始逐次增大。当子集合大小 最终和集合大小相同时排序完毕。 插入排序――直接插入排序例i=1(49 38 65 97 76 13 27 )比较次数 移动次数 2 1 1 0i=2 38 (38 49) 65 97 76 13 27 i=3 65 (38 49 65) 97 76 13 27 i=4 97 (38 49 65 97) 76 13 27 i=5 76 (38 49 65 76 97) 13 27 i=6 13 (13 38 49 65 76 97) 27 i=7 27 (13 27 49 65 65 76 97 38 38 49 76 97) 2712 601. 565j j j j j j 排序结果:(13 27 38 49 65 76 97) 直接插入排序算法分析按平均比较次数计算,将n个记录进行直接插入排序所 需的平均比较次数为:直接插入排序的时间复杂度为O(n2 )。 空间复杂度为O(1)直接插入排序是一种稳定的排序方法。 8.2.2 希尔排序希尔排序的基本思想是:把待排序的数据元素分成若干个小组,对同一小组内的数据元素用直接插入法排序;小组的个数逐次缩小; 当完成了所有数据元素都在一个组内的排序后 排序过程结束。希尔排序又称作缩小增量排序。 一个希尔排序的排序过程65 34 25 87 12 38 56 46 14 77 92 23结果序列56 34 14 77 12 23 65 46 25 87 92 38 (a)56 34 14 77 12 23 65 46 25 87 92 38结果序列56 12 14 65 34 23 77 46 25 87 92 38 (b)56 12 14 65 34 23 77 46 25 87 92 38结果序列12 14 23 25 34 38 46 56 65 77 87 92 (c) 希尔排序算法分析主要特点是每一趟以不同的增量进行插入 排序。当d较大时,被移动的记录是跳跃 式进行的。到最后一趟排序时(d=1),许 多记录已经有序,不需要多少移动,所以 能提高了排序的速度。 希尔排序是不稳定的排序方法。 8.3 选择排序选择排序的基本思想是:每次从待排序的 数据元素集合中选取最小(或最大)的数据元 素放到数据元素集合的最前(或最后),数据 元素集合不断缩小,当数据元素集合为空时排 序过程结束。常用的选择排序有直接选择排序 和堆排序两种。堆排序是一种基于完全二叉树 的排序。 8.3.1 直接选择排序 直接选择排序的基本思想是:从待排序的数 据元素集合中选取最小的数据元素并将它与原始 数据元素集合中的第一个数据元素交换位置;然 后从不包括第一个位置上数据元素的集合中选取 最小的数据元素并将它与原始数据元素集合中的 第二个数据元素交换位置;如此重复,直到数据 元素集合中只剩一个数据元素为止。 k 例 i=1 初始: [ 49 13kk38 jk65 j97 j76 j13 49 j27 ] jki=2 一趟: 13[38 65 27 j97 j 97 [9776 j 76 7649 38 ] 27 j 49 49 j 38 ] 65 ]二趟: 13 三趟: 1327 27[65 38四趟: 13五趟: 13 六趟: 13 排序结束: 132727 27 273838 38 384949 49 49[7665 65 6597[97 76 7665 ]76 ] [97 ] 97 简单选择排序算法分析简单选择排序所需要的总的比较次 数为O(n2 )。当初始文件是有序时,最 小移动记录次数等于0,而当初始文件 是逆序时,每次都要交换记录 。 直接选择排序是不稳定的. 选择排序――堆排序的引入堆排序是简单选择排序的改进。用直接 选择排序从n个记录中选出关键字值最小的 记录要做n-1次比较,然后从其余n-1个记录 中选出最小者要作n-2次比较。显然,相邻 两趟中某些比较是重复的。为了避免重复比 较,可以采用树形选择排序比较。 3113 3601149607149118249360(a)31149 6060114960714911824960(b)(a)求出最小关键字3 (b) 求出次小关键字11 图 树形选择排序8 选择排序――堆排序的引入树形选择排序总的比较次数为O(nlog2 n), 与直接选择排序比较,减少了比较次数, 但需要增加额外的存储空间存放中间比较 结果和排序结果。 堆的定义n个元素的序列(k1,k2,……kn),当且仅当满足下列 关系时,称之为堆ki?k2i ki?k2i+1 或 ki?k2i ki?k2i+1 (i=1,2,…...?n/2?) 例 (13,38,27,50,76,65,49,97) 13 38 27 50 76 65 49例 (96,83,27,38,11,9)9683273811997可将堆序列看成完全二叉树,则堆顶 元素(完全二叉树的根)必为序列中 n个元素的最小值或最大值 对于位置i处的结点,它的左孩子在位置2i+1处,它的右 孩子在位置 2i+2处,而它的双亲结点在 (i-1)/2处。 比如,元素39的结点在位置4处,因此,它的左孩子 (元素14)在9处 (2*4+1),它的右孩子 (元素 33) 在10 处 (2*4+2),而它的双亲 (元素42)在 1 ((4-1)/2)处[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10][11][12][13]62 42 32 22 29 14 39 33 44 30 17 9 59 13[10][11] 62 42 59 32 39 44 13 22 29 14 33 30 17 9parent leftright23 堆排序的基本思路堆排序的基本思路:对一组待排序的记 录序列,先将其关键字按堆的定义排列-个 序列(称初建堆),找到了最小(最大)关 键字,将其取出。用剩余的n-1个元素再重建 堆,便可得到次小(次大)值。如此反复执 行,直到全部关键字排好序为止。 例 38 50 97 7613 27 65 49 13 3897 27 38 50 7627 49 65 9750766549 13输出:13输出:1397 38 50 13 输出:13 27 76 65 49 27 13 9738 5076 65 49 27 13 9765 5076 38 49 27输出:13 27输出:13 27 38 49 50 97 13 输出:13 27 38 76 38 65 27 13 5076 65507697 13 49 3865 2797493827输出:13 27 38 49输出:13 27 38 499765 65 76 50 49 38 97 27 13 输出:13 27 38 49 50 50 76 4997 6538 277650 13 49 382713 输出:13 27 38 49 50输出:13 27 38 49 50 65 76 97 50 49 38 65 27 13 输出:13 27 38 49 50 65 97 5097 7649 38652713输出:13 27 38 49 50 65 767650 13 49 3865 27输出:13 27 38 49 50 65 76 97 堆排序需解决的两个问题: ? 如何由一个无序序列建成一个堆??如何在输出堆顶元素之后,调整剩余元 素,使之成为一个新的堆? 假设初始化为空的堆,依次加入 3, 5, 1, 19, 113 3 (a) After adding 35 35 1(b) After adding 5(c) After adding 119 5 3 (d) After adding 19 1 11 3 519 1 3 11 522 19 1(e) After adding 1129(f) After adding 22 向堆中加入 8822 11 3 5 1 19 88 3 11 522 88 1 19 3 11 588 22 1 19(a) Add 88 to a heap(b) After swapping 88 with 19(b) After swapping 88 with 2230 删除根节点 6262 42 32 22 29 14 39 33 30 44 17 9 59 1331 把最后结点 9 移到根处9 42 32 22 29 14 39 33 30 44 17 59 1332 交换9 和5959 42 32 22 29 14 39 33 30 44 17 9 1333 交换 9 和 4459 42 32 22 29 14 39 33 30 9 17 44 1334 交换9 和 3059 42 32 22 29 14 39 33 9 30 17 44 1335 Heap&E&-list: java.util.ArrayList&E& +Heap() +Heap(objects: E[]) +add(newObject: E): void +remove(): E +getSize(): int Creates a default empty heap. Creates a heap with the specified objects. Adds a new object to the heap. Removes the root from the heap and returns it. Returns the size of the heap.HeapTestHeap36Run HeapSortRun37 设 h 表示包含 n 个元素的堆的高度。由于堆 是完全二叉树,第一层有1个结点,第二层有2 个结点,第 k 层有 2(k-1) 个结点,第 (h-1) 层有 2(h-2) 结点,而第 h 层最少有一个结点,最多 有2(h-1) 个结点。因此:1 ? 2 ? ... ? 2h?2 ? n ? 1 ? 2 ? ... ? 2h?2 ? 2h?12h ?1?1 ? n ? 2 ?1h2h?1 ? n ? 1 ? 2h log 2h ?1 ? log(n ? 1) ? log 2hh ? 1 ? log(n ? 1) ? hlog(n ? 1) ? h ? log(n ? 1) ? 138 堆排序的算法及分析堆排序只需要一个记录大小的辅助空间。 堆排序算法的时间复杂度为O(nlogn)。 堆排序是一种不稳定的排序方法。 在优先队列中,元素被赋予优先级。当访问元素时,具有最高 优先级的元素最先被删除。 优先队列具有最高先出( largest-in, first-out )的行为特征。比如, 医院的急救室为病人赋予优先级,具有最高优先级的病人最先 得到治疗MyPriorityQueue&E&-heap: Heap&E& +enqueue(element: E): void +dequeue(): E +getSize(): int Adds an element to this queue. Removes an element from this queue. Returns the number of elements from this queue.MyPriorityQueue TestPriorityQueue40Run 8.3交换排序交换排序是通过两两比较待排序记录的 关键值,交换不满足顺序的那些偶对,直到 全部满足为止。 8.3.1 冒泡排序冒泡排序的基本思想是:设数组a中存放了n个数据元素,循 环进行n-1趟如下的排序过程:第1趟时,依次比较相临两个数据 元素a[i]和a[i+1](i = 0,1,2,…,n-2),若为逆序,即a[i]&a[i+1],则交 换两个数据元素,否则不交换,这样数值最大的数据元素将被放 置在a[n-1]中。第2趟时,循环次数减1,即数据元素个数为n-1, 操作方法和第1趟的类似,这样整个n个数据元素集合中数值次大 的数据元素将被放置在a[n-2]中。当第n-1趟结束时,整个n个数据 元素集合中次小的数据元素将被放置在a[1]中,a[0]中放置了最小 的数据元素。 交换排序――冒泡排序例 38 4938 49 65 97 76 76 13 97 13 97 27 38 49 65 76 13 38 49 65 13 38 49 13 13 49 2713 3813 27 3813 27 30 3813 27 3038 27 3030 38 4927 65 1327 30 65 30 65 7649 30 27 49 306527 76 13 30 76 27 76 309727 30 9797 30 初 始 关 键 字第 一 趟第 二 趟第 三 趟第 四 趟第 五 趟第 六 趟 冒泡排序算法分析由上述算法可见,当初始序列中记录已按关 键字次序排好序,则只需要进行一趟排序, 在排序过程中只需要进行n-1次比较,记录移 动次数为0;反之,若初始序列中记录按逆序 排列,若待排序的序列有n个记录,最多进行 n-1趟排序,最大比较次数为n?n ? 1? n 2 ? ?n ? i ? ? 2 ? 2 i ?1n ?1交换记录时移动记录的次数也约为3n2 /2次,故总 的时间复杂度为O(n2 )。冒泡排序是稳定的。 基本思想:通过一趟排序,将待排序记录分割成 独立的两部分,其中一部分记录的关键字均比另 一部分记录的关键字小,则可分别对这两部分记 录进行排序,以达到整个序列有序 8.3.2快速排序 快速排序是一种二叉树结构的交换排序方法。 快速排序算法的基本思想是:设数组a中存放了n个数 据元素,low为数组的低端下标,high为数组的高端下 标,从数组a中任取一个元素(通常取a[low])做为标 准元素,以该标准元素调整数组a中其他各个元素的位 置,使排在标准元素前面的元素均小于标准元素,排 在标准元素后面的均大于或等于标准元素。这样一次 排序过程结束后,一方面将标准元素放在了未来排好 序的数组中该标准元素应位于的位置上,另一方面将 数组中的元素以标准元素为中心分成了两个子数组, 位于标准元素左边子数组中的元素均小于标准元素, 位于标准元素右边子数组中的元素均大于等于或标准 元素。对这两个子数组中的元素分别再进行方法类同 的递归快速排序。算法的递归出口条件是low≥high。 快速排序的排序过程QuickSortx 例 初始关键字: 27 49 38 i 38 13 49 65 i 13) 49 97 iij 76 97 49 13 j 97 65 49 27 j 65 50 j 50)Runi完成一趟排序: ( 27j49 (76分别进行快速排序: ( 13) 27(38) 49 (5065)76(97)快速排序结束:1327384950657697 快速排序的排序算法分析快速排序平均时间复杂度为O(nlog2 n)。最坏情况下时间复杂度为O(n2),快速排序所 需的比较次数反而最多。 快速排序法不稳定。 快速排序需要一个栈空间来实现递归。栈的 最大深度为 ?log2 n」 +1,所需栈空间为 O(log2 n)。最坏情况下,递归深度为n,所需 栈空间为O(n)。 在最差情况下,每次标准元素会将数字划分成 一个大的子数组和一个空数组。这个大的子数 组的规模是上次划分的子数组的规模减1。该 O(n 2 ) 算法需要的时间为:(n ? 1) ?(n ? 2) ? ... ? 2 ? 1 ? O(n )249 在最佳情况下,每次标准元素将数组划分为规 模大致相等的两部分。设 T(n) 表示使用快排 对数组排序所需的时间,则n n T (n) ? T ( ) ? T ( ) ?n ? O(n log n) 2 250 在平均情况下,每次标准元素不会将数组分为 规模相等的两部分或是一个空的部分。 从统 计上说,两部分的规模会非常接近,所以,平 均时间为O(nlogn)51 8.4 归并排序归并排序:把两个或多个有序表进行合 并,得到一个新的有序表。将两个有序子文 件合并成一个有序文件,称为二路归并。 归并排序主要是二路归并排序。二路归并排 序的基本思想是:设数组a中存放了n个数据元素, 初始时我们把它们看成是n个长度为1的有序子数 组,然后从第一个子数组开始,把相临的子数组 两两合并,得到n/2个(若n/2为小数则上取整) 长度为2的新的有序子数组(当n为奇数时最后一 个新的有序子数组的长度为1);对这些新的有 序子数组再两两归并;如此重复,直到得到一个 长度为n的有序数组为止。多于二路的归并排序 方法和二路归并排序方法类同。 2 9 5 4 8 1 67 split 2 9 5 4 split 2 9 split 2 merge 2 9 merge 2 4 5 9 merge 1 2 4 5 6 7 89548 1 6 7 divide5 4 9 5 4 5 4 88 1 1 1 8 66 7 7 6 7conquer1 6 7 8MergeSort Run current1current2current1current2current1current22 4 5 91 6 7 82 4 5 91 6 7 82 4 5 91 6 7 811 2 4 5 6 7 81 2 4 5 6 7 8 9current3 (a) After moving 1 to tempcurrent3 (b) After moving all the elements in list2 to temp to tempcurrent3 (c) After moving 9 to temp55 假设 T(n) 代表使用归并排序对由n个元素构成 的数组进行排序所需的时间。不失一般性,假 设n是2的幂。归并排序将数组分成两个子数组, 使用同样的算法对子数组递归排序,然后将子 数组进行归并。则n n T (n) ? T ( ) ? T ( ) ? mergetime 2 256 第一项T(n/2) 是对数组前半部分排序所需的时 间,而第二项T(n/2) 是对后半部分排序所需时 间。要归并两个子数组,最多需要n-1次比较 来比较两个子数组中的元素,以及n次移动将 元素移到临时数组。因此,总时间为 2n-1。从 而,n n n n T ( n ) ? 2T ( ) ? 2n ? 1 ? 2( 2T ( ) ? 2 ? 1) ? 2n ? 1 ? 2 2 T ( 2 ) ? 2n ? 2 ? 2n ? 1 2 4 2 2 n ? 2k T ( k ) ? 2n ? 2k ?1 ? ... ? 2n ? 2 ? 2n ? 1 2 n ? 2log n T ( log n ) ? 2n ? 2log n ?1 ? ... ? 2n ? 2 ? 2n ? 1 2 ? n ? 2n log n ? 2log n ? 1 ? 2n log n ? 1 ? O ( n log n )57 归并排序算法分析归并排序的总的时间复杂度为O(nlog2 n)。 归并排序需要的附加存储空间为O(n),所需 辅助空间较大。 二路归并排序是稳定的。 *8.5基数排序基数排序是和前面所述的各种排序方法完 全不同的一种排序方法。前面介绍的几种排序 方法,都是根据关键字之间的比较和移动记录 来实现的,基数排序不需要进行记录关键字间 的比较,而是根据组成关键字的各位值,即借 助于多关键字排序的思想,用“分配”和“收 集”的方法进行排序。 假设有n个记录的序列 { R1, R2, …,Rn} 每个记录Ri中含有d个关键字(Ki0, Ki1, …,Kid-1),则称上述记录序列对关键字 (Ki0, Ki1, …,Kid-1)有序是指:对于序列中 任意两个记录Ri和Rj(1≤i&j≤n)都满足下 列(词典)有序关系: (Ki0, Ki1, …,Kid-1)& (Kj0, Kj1, …,Kjd-1) 其中K0被称为“最主”位关键字,Kd-1被称为 “最次”位关键字。 最高位优先MSD法:先对K0进行排序,并按 K0的不同值将记录序列分成若干子序列之 后,分别对K1进行排序,…,依次类推, 直至最后对最次位关键字排序完成为止。 最低位优先LSD法:先对Kd-1进行排序,然 后对Kd-2进行排序,依次类推,直至对最 主位关键字K0排序完成为止。排序过程中 不需要根据“前一个”关键字的排序结果, 将记录序列分割成若干个(“前一个”关键 字不同的)子序列。 例如:学生记录含三个关键字:系别、班号和班 内的序列号,其中以系别为最主位关键字。 LSD的排序过程如下: 无序序列3,2,30 1,2,15 3,1,20 2,3,18 2,1,20 对K2排序1,2,15 2,3,18 3,1,20 2,1,20 3,2,30 对K1排序3,1,20 2,1,20 1,2,15 3,2,30 2,3,18 对K0排序1,2,15 2,1,20 2,3,18 3,1,20 3,2,30 MSD法和LSD法的比较比较MSD法和LSD法,一般来讲,LSD 法要比MSD法来得简单,因为LSD 法是从 头到尾进行若干次分配和收集,执行的 次数取决于构成关键字值的成分为多少; 而MSD 法则要处理各序列与子序列的独 立排序问题,就可能复杂一些。 基数排序算法的基本思想是:设待排序的数据元 素是m位d进制整数(不足m位的在高位补0),设置 d个桶,令其编号分别为0,1,2,…,d-1。首先按最低位 (即个位)的数值依次把各数据元素放到相应的桶中, 然后按照桶号从小到大和进入桶中数据元素的先后次 序收集分配在各桶中的数据元素,这样就形成了数据 元素集合的一个新的排列,我们称这样的一次排序过 程为一次基数排序;再对一次基数排序得到的数据元 素序列按次低位(即十位)的数值依次把各数据元素 放到相应的桶中,然后按照桶号从小到大和进入桶中 数据元素的先后次序收集分配在各桶中的数据元素; 这样的过程重复进行,当完成了第m次基数排序后, 就得到了排好序的数据元素序列。 基数排序算法的排序过程放置 710 0 841 1 710 342 2 841 264 134 4 134 (a) 264 045 5 045 006 686 6 686 068 8 068 429 429 93 3427 006收集后的新序列:放置006 0710 1 006429 2 710134 3 429045 342 841 4 134 (b) 8415 342068 264 6 0457 264686 8 068 6869收集后的新序列:放置068 045 006134 006264 045342 068429 134 (c) 264 342686 429710 686841 710 841收集后的新序列: 链式队列的基数排序算法存储结构myQueue rear front 0 1 2 ...∧...d-1...∧ 排序方法最好时间平均时间最坏时间辅助空间稳定性直接插入排序 希尔排序 直接选择排序 堆排序 冒泡排序 快速排序O(n)O(n2) O(n1.3)O(n2)O(1) O(1)稳定 不稳定 稳定 不稳定 稳定 不稳定O(n2)O(n2)O(n2)O(1)O(nlog2n) O(nlog2n) O(nlog2n) O(1) O(n) O(n2) O(n2) O(1) O(log2n)O(nlog2n) O(nlog2n) O(n2)归并排序 基数排序O(nlog2n) O(nlog2n) O(nlog2n) O(n) O(mn) O(mn) O(mn) O(n)稳定 稳定 各种内部排序方法性能比较1)从平均时间而言:快速排序最佳。但在最坏情况下时间性 能不如堆排序和归并排序。 2)从算法简单性看:由于直接选择排序、直接插入排序和冒 泡排序的算法比较简单,将其认为是简单算法,都包含在 上图中的“简单排序”中。对于希尔排序、堆排序、快速 排序和归并排序算法,其算法比较复杂,认为是复杂排序。 3)从稳定性看:直接插入排序、冒泡排序和归并排序是稳定 的;而希尔排序、直接选择排序、快速排序和堆排序是不 稳定排序。 4)从待排序的记录数n的大小看,n较小时,宜采用简单排序; 而n较大时宜采用改进排序。 选择排序的方法(1)当待排序记录数n 较大时,若要求排序稳定, 则采用归并排序。 (2)当待排序记录数n 较大,关键字分布随机,而 且不要求稳定时,可采用快速排序; (3)当待排序记录数n 较大,关键字会出现正、逆 序情形,可采用堆排序(或归并排序)。 (4)当待排序记录数n 较小,记录已接近有序或随 机分布时,又要求排序稳定,可采用直接插入排序。 (5)当待排序记录数n 较小,且对稳定性不作要求 时,可采用直接选择排序。 前面讨论的所有算法,都假定要排序的所有数据在内 存中同时可用,如数组。要对存储在外部文件中的数 据排序,首先要将数据送入内存,然后对它们进行内 部排序。然而,如果文件太大,那么文件中的所有数 据不能同时放入内容CreateLargeFileProgram Array Temporary file …… S1 S270Original fileRun SortLargeFileSkRun 重复将数据从文件读入数组,并使用内部排序 算法对数组排序,然后将数据从数组输出到一 个临时文件。Program Array Temporary file …… S1 S2 Sk Original file71 归并每对有序分段 (比如, S1 和 S2, S3 和 S4, ..., 等等) 到一个大一些的有序分段中,并将新分段 存储到新的临时文件中。继续同样的过程直到 得到一个有序分段。S1 Sk S1, S2 merged S3, S4 merged S5, S6 merged S7, S8 merged Merge S1, S2, S3, S4 merged S5, S6 , S7, S8 merged Merge S1, S2, S3, S4 , S5, S6 , S7, S8 merged72S2S3S4S5S6S7S8 Merge 每步归并都将两个有序分段归并成一个新段。新段的元 素数目是原来的两倍,因此,每次归并后分段的个数减 少一半。如果一个分段太大,它将不能放入内存的数组 中。为了实现归并,要将文件 f1.dat 中一半数目的分段 复制到临时文件 f2.dat中。然后将 f1.dat 中剩下的首个分 段与 f2.dat 中的首个分段归并到名为 f3.dat的临时文件中73 S1 SkS2S3S4S5S6S7S8f1.datCopy to f2.datS1 S1, S5 merged S2, S6 mergedS2S3S4f2.datS3, S7 mergedS4, S8 mergedf3.dat74 ? 排序的概念和有关知识;? 插入排序、交换排序、选择排序、归并排序和基 数排序五类内部排序方法的基本思想、排序过程、 实现的算法、算法的效率分析及排序的特点 。 ?各种内部排序方法的优缺点及不同的应用场合选 择合适的方法进行排序 。
更多搜索:
赞助商链接
All rights reserved Powered by
文档资料库内容来自网络,如有侵犯请联系客服。

我要回帖

更多关于 js 数组长度 的文章

 

随机推荐