冒泡排序算法分析(冒泡排序法和快速排序比较的算法)

:暂无数据 2026-10-08 00:00:02 :0

冒泡排序算法分析(冒泡排序法和快速排序比较的算法)

各位老铁们,大家好,今天由我来为大家分享冒泡排序算法分析,以及冒泡排序法和快速排序比较的算法的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!

本文目录

冒泡排序法和快速排序比较的算法

打你屁股,这么简单的问题都不认真研究一下。

冒泡排序是最慢的排序,时间复杂度是 O(n^2)。

快速排序是最快的排序。关于快速排序,我推荐你看看《代码之美》第二章:我编写过的最漂亮的代码。作者所说的最漂亮,就是指效率最高的。

--------------------------------摘自《代码之美》---------------

当我撰写关于分治(divide-and-conquer)算法的论文时,我发现C.A.R. Hoare的Quicksort算法(“Quicksort”,Computer Journal 5)无疑是各种Quicksort算法的鼻祖。这是一种解决基本问题的漂亮算法,可以用优雅的代码实现。我很喜欢这个算法,但我总是无法弄明白算法中最内层的循环。我曾经花两天的时间来调试一个使用了这个循环的复杂程序,并且几年以来,当我需要完成类似的任务时,我会很小心地复制这段代码。虽然这段代码能够解决我所遇到的问题,但我却并没有真正地理解它。
我后来从Nico Lomuto那里学到了一种优雅的划分(partitioning)模式,并且最终编写出了我能够理解,甚至能够证明的Quicksort算法。William Strunk Jr.针对英语所提出的“良好的写作风格即为简练”这条经验同样适用于代码的编写,因此我遵循了他的建议,“省略不必要的字词”(来自《The Elements of Style》一书)。我最终将大约40行左右的代码缩减为十几行的代码。因此,如果要回答“你曾编写过的最漂亮代码是什么?”这个问题,那么我的答案就是:在我编写的《Programming Pearls, Second Edition》(Addison-Wesley)一书中给出的Quichsort算法。在示例2-1中给出了用C语言编写的Quicksort函数。我们在接下来的章节中将进一步地研究和改善这个函数。
【示例】 2-1 Quicksort函数
void quicksort(int l, int u)
{ int i, m;
if (l 》= u) return; 10
swap(l, randint(l, u));
m = l;
for (i = l+1; i 《= u; i++)
if (x[i] 《 x[l])
swap(++m, i);
swap(l, m);
quicksort(l, m-1);
quicksort(m+1, u);
}
如果函数的调用形式是quicksort(0, n-1),那么这段代码将对一个全局数组x[n]进行排序。函数的两个参数分别是将要进行排序的子数组的下标:l是较低的下标,而u是较高的下标。函数调用swap(i,j)将会交换x[i]与x[j]这两个元素。第一次交换操作将会按照均匀分布的方式在l和u之间随机地选择一个划分元素。
在《Programming Pearls》一书中包含了对Quicksort算法的详细推导以及正确性证明。在本章的剩余内容中,我将假设读者熟悉在《Programming Pearls》中所给出的Quicksort算法以及在大多数初级算法教科书中所给出的Quicksort算法。
如果你把问题改为“在你编写那些广为应用的代码中,哪一段代码是最漂亮的?”我的答案还是Quicksort算法。在我和M. D. McIlroy一起编写的一篇文章(“Engineering a sort function,“ Software-Practice and Experience, Vol. 23, No. 11)中指出了在原来Unix qsort函数中的一个严重的性能问题。随后,我们开始用C语言编写一个新排序函数库,并且考虑了许多不同的算法,包括合并排序(Merge Sort)和堆排序(Heap Sort)等算法。在比较了Quicksort的几种实现方案后,我们着手创建自己的Quicksort算法。在这篇文章中描述了我们如何设计出一个比这个算法的其他实现要更为清晰,速度更快以及更为健壮的新函数——部分原因是由于这个函数的代码更为短小。Gordon Bell的名言被证明是正确的:“在计算机系统中,那些最廉价,速度最快以及最为可靠的组件是不存在的。”现在,这个函数已经被使用了10多年的时间,并且没有出现任何故障。
考虑到通过缩减代码量所得到的好处,我最后以第三种方式来问自己在本章之初提出的问题。“你没有编写过的最漂亮代码是什么?”。我如何使用非常少的代码来实现大量的功能?答案还是和Quicksort有关,特别是对这个算法的性能分析。我将在下一节给出详细介绍。
2.2 事倍功半
Quicksort是一种优雅的算法,这一点有助于对这个算法进行细致的分析。大约在1980年左右,我与Tony Hoare曾经讨论过Quicksort算法的历史。他告诉我,当他最初开发出Quicksort时,他认为这种算法太简单了,不值得发表,而且直到能够分析出这种算法的预期运行时间之后,他才写出了经典的“Quicksoft”论文。
我们很容易看出,在最坏的情况下,Quicksort可能需要n2的时间来对数组元素进行排序。而在最优的情况下,它将选择中值作为划分元素,因此只需nlgn次的比较就可以完成对数组的排序。那么,对于n个不同值的随机数组来说,这个算法平均将进行多少次比较?
Hoare对于这个问题的分析非常漂亮,但不幸的是,其中所使用的数学知识超出了大多数程序员的理解范围。当我为本科生讲授Quicksort算法时,许多学生即使在费了很大的努力之后,还是无法理解其中的证明过程,这令我非常沮丧。下面,我们将从Hoare的程序开
11
始讨论,并且最后将给出一个与他的证明很接近的分析。
我们的任务是对示例2-1中的Quicksort代码进行修改,以分析在对元素值均不相同的数组进行排序时平均需要进行多少次比较。我们还将努力通过最短的代码、最短运行时间以及最小存储空间来得到最深的理解。
为了确定平均比较的次数,我们首先对程序进行修改以统计次数。因此,在内部循环进行比较之前,我们将增加变量comps的值(参见示例2-2)。
【示例2-2】 修改Quicksort的内部循环以统计比较次数。
for (i = l+1; i 《= u; i++) {
comps++;
if (x[i] 《 x[l])
swap(++m, i);
}
如果用一个值n来运行程序,我们将会看到在程序的运行过程中总共进行了多少次比较。如果重复用n来运行程序,并且用统计的方法来分析结果,我们将得到Quicksort在对n个元素进行排序时平均使用了1.4 nlgn次的比较。
在理解程序的行为上,这是一种不错的方法。通过十三行的代码和一些实验可以反应出许多问题。这里,我们引用作家Blaise Pascal和T. S. Eliot的话,“如果我有更多的时间,那么我给你写的信就会更短。”现在,我们有充足的时间,因此就让我们来对代码进行修改,并且努力编写出更短(同时更好)的程序。
我们要做的事情就是提高这个算法的速度,并且尽量增加统计的精确度以及对程序的理解。由于内部循环总是会执行u-l次比较,因此我们可以通过在循环外部增加一个简单的操作来统计比较次数,这就可以使程序运行得更快一些。在示例2-3的Quicksort算法中给出了这个修改。
【示例2-3】 Quicksort的内部循环,将递增操作移到循环的外部
comps += u-l;
for (i = l+1; i 《= u; i++)
if (x[i] 《 x[l])
swap(++m, i);
这个程序会对一个数组进行排序,同时统计比较的次数。不过,如果我们的目标只是统计比较的次数,那么就不需要对数组进行实际地排序。在示例2-4中去掉了对元素进行排序的“实际操作”,而只是保留了程序中各种函数调用的“框架”。
【示例2-4】将Quicksort算法的框架缩减为只进行统计
void quickcount(int l, int u)
{ int m;
if (l 》= u) return;
m = randint(l, u);
comps += u-l;
quickcount(l, m-1);
quickcount(m+1, u);
}
12
这个程序能够实现我们的需求,因为Quichsort在选择划分元素时采用的是“随机”方式,并且我们假设所有的元素都是不相等的。现在,这个新程序的运行时间与n成正比,并且相对于示例2-3需要的存储空间与n成正比来说,现在所需的存储空间缩减为递归堆栈的大小,即存储空间的平均大小与lgn成正比。
虽然在实际的程序中,数组的下标(l和u)是非常重要的,但在这个框架版本中并不重要。因此,我们可以用一个表示子数组大小的整数(n)来替代这两个下标(参见示例2-5)
【示例2-5】 在Quicksort代码框架中使用一个表示子数组大小的参数
void qc(int n)
{ int m;
if (n 《= 1) return;
m = randint(1, n);
comps += n-1;
qc(m-1);
qc(n-m);
}
现在,我们可以很自然地把这个过程整理为一个统计比较次数的函数,这个函数将返回在随机Quicksort算法中的比较次数。在示例2-6中给出了这个函数。
【示例2-6】 将Quicksort框架实现为一个函数
int cc(int n)
{ int m;
if (n 《= 1) return 0;
m = randint(1, n);
return n-1 + cc(m-1) + cc(n-m);
}
在示例2-4、示例2-5和示例2-6中解决的都是相同的基本问题,并且所需的都是相同的运行时间和存储空间。在后面的每个示例都对这些函数的形式进行了改进,从而比这些函数更为清晰和简洁。
在定义发明家的矛盾(inventor’s paradox)(How To Solve It, Princeton University Press)时,George Póllya指出“计划越宏大,成功的可能性就越大。”现在,我们就来研究在分析Quicksort时的矛盾。到目前为止,我们遇到的问题是,“当Quicksort对大小为n的数组进行一次排序时,需要进行多少次比较?”我们现在将对这个问题进行扩展,“对于大小为n的随机数组来说,Quichsort算法平均需要进行多少次的比较?”我们通过对示例2-6进行扩展以引出示例2-7。
【示例2-7】 伪码:Quicksort的平均比较次数
float c(int n)
if (n 《= 1) return 0
sum = 0
for (m = 1; m 《= n; m++)
sum += n-1 + c(m-1) + c(n-m)
return sum/n
如果在输入的数组中最多只有一个元素,那么Quichsort将不会进行比较,如示例2-6
13
中所示。对于更大的n,这段代码将考虑每个划分值m(从第一个元素到最后一个,每个都是等可能的)并且确定在这个元素的位置上进行划分的运行开销。然后,这段代码将统计这些开销的总和(这样就递归地解决了一个大小为m-1的问题和一个大小为n-m的问题),然后将总和除以n得到平均值并返回这个结果。
如果我们能够计算这个数值,那么将使我们实验的功能更加强大。我们现在无需对一个n值运行多次来估计平均值,而只需一个简单的实验便可以得到真实的平均值。不幸的是,实现这个功能是要付出代价的:这个程序的运行时间正比于3n(如果是自行参考(self-referential)的,那么用本章中给出的技术来分析运行时间将是一个很有趣的练习)。
示例2-7中的代码需要一定的时间开销,因为它重复计算了中间结果。当在程序中出现这种情况时,我们通常会使用动态编程来存储中间结果,从而避免重复计算。因此,我们将定义一个表t[N+1],其中在t[n]中存储c[n],并且按照升序来计算它的值。我们将用N来表示n的最大值,也就是进行排序的数组的大小。在示例2-8中给出了修改后的代码。
【示例2-8】 在Quicksort中使用动态编程来计算
t = 0
for (n = 1; n 《= N; n++)
sum = 0
for (i = 1; i 《= n; i++)
sum += n-1 + t[i-1] + t[n-i]
t[n] = sum/n
这个程序只对示例2-7进行了细微的修改,即用t[n]来替换c(n)。它的运行时间将正比于N2,并且所需的存储空间正比于N。这个程序的优点之一就是:在程序执行结束时,数组t中将包含数组中从元素0到元素N的真实平均值(而不是样本均值的估计)。我们可以对这些值进行分析,从而生成在Quichsort算法中统计比较次数的计算公式。
我们现在来对程序做进一步的简化。第一步就是把n-1移到循环的外面,如示例2-9所示。
【示例2-9】 在Quicksort中把代码移到循环外面来计算
t = 0
for (n = 1; n 《= N; n++)
sum = 0
for (i = 1; i 《= n; i++)
sum += t[i-1] + t[n-i]
t[n] = n-1 + sum/n
现在将利用对称性来对循环做进一步的调整。例如,当n为4时,内部循环计算总和为:
t+t + t+t + t+t + t+t
在上面这些组对中,第一个元素增加而第二个元素减少。因此,我们可以把总和改写为:
2 * (t + t + t + t)
我们可以利用这种对称性来得到示例2-10中的Quicksort。
【示例2-10】 在Quichsort中利用了对称性来计算
t = 0
14
for (n = 1; n 《= N; n++)
sum = 0
for (i = 0; i 《 n; i++)
sum += 2 * t[i]
t[n] = n-1 + sum/n
然而,在这段代码的运行时间中同样存在着浪费,因为它重复地计算了相同的总和。此时,我们不是把前面所有的元素加在一起,而是在循环外部初始化总和并且加上下一个元素,如示例2-11所示。
【示例2-11】 在Quicksort中删除了内部循环来计算
sum = 0; t = 0
for (n = 1; n 《= N; n++)
sum += 2*t[n-1]
t[n] = n-1 + sum/n
这个小程序确实很有用。程序的运行时间与N成正比,对于每个从1到N的整数,程序将生成一张Quicksort的估计运行时间表。
我们可以很容易地把示例2-11用表格来实现,其中的值可以立即用于进一步的分析。在2-1给出了最初的结果行。
表2-1 示例2-11中实现的表格输出
N Sum t[n]
0 0 0
1 0 0
2 0 1
3 2 2.667
4 7.333 4.833
5 17 7.4
6 31.8 10.3
7 52.4 13.486
8 79.371 16.921
这张表中的第一行数字是用代码中的三个常量来进行初始化的。下一行(输出的第三行)的数值是通过以下公式来计算的:
A3 = A2+1 B3 = B2 + 2*C2 C3 = A2-1 + B3/A3
把这些(相应的)公式记录下来就使得这张表格变得完整了。这张表格是“我曾经编写的最漂亮代码”的很好的证据,即使用少量的代码完成大量的工作。
但是,如果我们不需要所有的值,那么情况将会是什么样?如果我们更希望通过这种来方式分析一部分数值(例如,在20到232之间所有2的指数值)呢?虽然在示例2-11中构建了完整的表格t,但它只需要使用表格中的最新值。因此,我们可以用变量t的定长空间来替代table t的线性空间,如示例2-12所示。
【示例2-12】 Quicksoft 计算——最终版本
sum = 0; t = 0
15
for (n = 1; n 《= N; n++)
sum += 2*t
t = n-1 + sum/n
然后,我们可以插入一行代码来测试n的适应性,并且在必要时输出这些结果。
这个程序是我们漫长学习旅途的终点。通过本章所采用的方式,我们可以证明Alan Perlis的经验是正确的:“简单性并不是在复杂性之前,而是在复杂性之后” (“Epigrams on Programming,“ Sigplan Notices, Vol. 17, Issue 9)。

冒泡排序法代码解析

private int aaa(int ii,int a) // 定义私有方法 aaa ,返回类型为 整数型数组,该方法两个参数,整数型数组 ii 与整数型 a
{
if(a==0)return ii; //如果 参数 a 为零时,直接返回参数ii
if(ii[a-1]《ii[a])return ii; //如果 参数 ii[a-1] 成员值小于 ii[a] 成员值 返回参数ii
else{ //否则
int b=ii[a-1]; //临时变量 b ,暂时存放 ii[a-1] 的成员值
ii[a-1]=ii[a]; //将ii[a] 成员值 存入 ii[a-1]
ii[a]=b; //将之前暂存的值,存入ii[a]
//以上几条综述,就是 如果 ii[a-1] 成员大于ii[a] 则交换彼此的成员值

return aaa(ii,a-1); //返回
}
}
//这些已经是最最简单的了。。如果这些都不能解理并搞定它们,,趁早放弃最好,不要为难自己

冒泡排序算法

冒泡排序(BubbleSort)的基本概念是:依次比较相邻的两个数,将小数放在前面,大数放在后面。即首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。重复以上过程,仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到最大数前的一对相邻数,将小数放前,大数放后,第二趟结束,在倒数第二个数中得到一个新的最大数。如此下去,直至最终完成排序。
由于在排序过程中总是小数往前放,大数往后放,相当于气泡往上升,所以称作冒泡排序。
用二重循环实现,外循环变量设为i,内循环变量设为j。外循环重复9次,内循环依次重复 9,8,...,1次。每次进行比较的两个元素都是与内循环j有关的,它们可以分别用a[j]和a[j+1]标识,i的值依次为1,2,...,9,对于每一个i, j的值依次为1,2,...10-i。
产生
在许多程序设计中,我们需要将一个数列进行排序,以方便统计,而冒泡排序一直由于其简洁的思想方法而倍受青睐。
排序过程
设想被排序的数组R〔1..N〕垂直竖立,将每个数据元素看作有重量的气泡,根据轻气泡不能在重气泡之下的原则,从下往上扫描数组R,凡扫描到违反本原则的轻气泡,就使其向上“漂浮“,如此反复进行,直至最后任何两个气泡都是轻者在上,重者在下为止。
算法示例
49 13 13 13 13 13 13 13
38 49 27 27 27 27 27 27
65 38 49 38 38 38 38 38
97 65 38 49 49 49 49 49
76 97 65 49 49 49 49 49
13 76 97 65 65 65 65 65
27 27 76 97 76 76 76 76
49 49 49 76 97 97 97 97
Procedure BubbleSort(Var R : FileType) //从下往上扫描的起泡排序//
Begin
For I := 1 To N-1 Do //做N-1趟排序//
begin
NoSwap := True; //置未排序的标志//
For J := N - 1 DownTo 1 Do //从底部往上扫描//
begin
If R[J+1]《 R[J] Then //交换元素//
begin
Temp := R[J+1]; R[J+1 := R[J]; R[J] := Temp;
NoSwap := False
end;
end;
If NoSwap Then Return//本趟排序中未发生交换,则终止算法//
end
End; //BubbleSort//
该算法的时间复杂性为O(n^2),算法为稳定的排序方
本段
冒泡排序代码
AAuto
bubble_sort = function(array){
var temp;
for( i=1;#array ){
//i前面的已经是最小的数,并排序好了
for(j=#array;i+1;-1){
//挨个比较
if(array[j]《array[j-1]){
//小的总是往前排
bubble = array[j]
array[j] = array[j-1];
array[j-1] = bubble;
}
}
}
}
io.print(“----------------“)
io.print(“冒泡排序( 交换类换排序 )“)
io.print(“----------------“)
array ={2;46;5;17;1;2;3;99;12;56;66;21};
bubble_sort(array,1,#array)
//输出结果
for(i=1;#array;1){
io.print( array[i] )
}
C
void bubble_sort(int *x, int n)
{
int j, k, h, t;
for (h=n-1; h》0; h=k) /*循环到没有比较范围*/
{
for (j=0, k=0; j《h; j++) /*每次预置k=0,循环扫描后更新k*/
{
if (*(x+j) 》 *(x+j+1)) /*大的放在后面,小的放到前面*/
{
t = *(x+j);
*(x+j) = *(x+j+1);
*(x+j+1) = t; /*完成交换*/
k = j; /*保存最后下沉的位置。这样k后面的都是排序排好了的。*/
}
}
}
}
C++
#include 《iostream》
#define LEN 9
using namespace std;
int main()
{
int nArray[LEN];
for(int i=0;i《LEN;i++)nArray[i]=LEN-i;
cout《《“原始数据为:“《《endl;
for(int i=0;i《LEN;i++)cout《《nArray[i]《《“ “;
cout《《endl;
//开始冒泡
{
int temp;
for(int i=LEN-1;i》0;i--)
for(int j=0;j《i;j++)
{
if(nArray[j]》nArray[j+1])
{
temp=nArray[j];
nArray[j]=nArray[j+1];
nArray[j+1]=temp;
}
}
}
//结束冒泡
cout《《“排序结果:“《《endl;
for(int i=0;i《LEN;i++)cout《《nArray[i]《《“ “;
return 0;
}

关于本次冒泡排序算法分析和冒泡排序法和快速排序比较的算法的问题分享到这里就结束了,如果解决了您的问题,我们非常高兴。

冒泡排序算法分析(冒泡排序法和快速排序比较的算法)

本文编辑:admin

更多文章:


turtles歌曲(哪位大神有turtles(乌龟组合)的<谢谢>的歌词中文翻译 感激不尽)

turtles歌曲(哪位大神有turtles(乌龟组合)的<谢谢>的歌词中文翻译 感激不尽)

“turtles歌曲”相关信息最新大全有哪些,这是大家都非常关心的,接下来就一起看看turtles歌曲(哪位大神有turtles(乌龟组合)的的歌词中文翻译 感激不尽)!

2026年10月11日 10:00

java转义字符(java中的转义字符的作用是什么)

java转义字符(java中的转义字符的作用是什么)

其实java转义字符的问题并不复杂,但是又很多的朋友都不太了解java中的转义字符的作用是什么,因此呢,今天小编就来为大家分享java转义字符的一些知识,希望可以帮助到大家,下面我们一起来看看这个问题的分析吧!

2026年10月11日 09:40

金山铁路22号线(请问现在轨道交通22号线金山铁路是个什么情况据说9月28日就开通了啊~~~)

金山铁路22号线(请问现在轨道交通22号线金山铁路是个什么情况据说9月28日就开通了啊~~~)

“金山铁路22号线”相关信息最新大全有哪些,这是大家都非常关心的,接下来就一起看看金山铁路22号线(请问现在轨道交通22号线金山铁路是个什么情况据说9月28日就开通了啊~~~)!

2026年10月11日 09:10

repercussions(都是余波,repercussions和aftermath有什么区别啊)

repercussions(都是余波,repercussions和aftermath有什么区别啊)

今天给各位分享都是余波,repercussions和aftermath有什么区别啊的知识,其中也会对都是余波,repercussions和aftermath有什么区别啊进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!

2026年10月11日 09:00

dropdownlist 绑定(DropDownList 绑定所有项 并 显示指定项)

dropdownlist 绑定(DropDownList 绑定所有项 并 显示指定项)

本篇文章给大家谈谈dropdownlist 绑定,以及DropDownList 绑定所有项 并 显示指定项对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

2026年10月11日 08:50

协方差计算公式(协方差的计算公式)

协方差计算公式(协方差的计算公式)

这篇文章给大家聊聊关于协方差计算公式,以及协方差的计算公式对应的知识点,希望对各位有所帮助,不要忘了收藏本站哦。

2026年10月11日 08:10

易语言网页api接口怎么调用(易语言,怎么读取网页json的api)

易语言网页api接口怎么调用(易语言,怎么读取网页json的api)

本篇文章给大家谈谈易语言网页api接口怎么调用,以及易语言,怎么读取网页json的api对应的知识点,文章可能有点长,但是希望大家可以阅读完,增长自己的知识,最重要的是希望对各位有所帮助,可以解决了您的问题,不要忘了收藏本站喔。

2026年10月11日 08:00

majority of(the majority of 和 a majority of的区别以及用法例句)

majority of(the majority of 和 a majority of的区别以及用法例句)

这篇文章给大家聊聊关于majority of,以及the majority of 和 a majority of的区别以及用法例句对应的知识点,希望对各位有所帮助,不要忘了收藏本站哦。

2026年10月11日 07:40

汉字机内码查询表(1个汉字的机内码是几位谢谢)

汉字机内码查询表(1个汉字的机内码是几位谢谢)

大家好,关于汉字机内码查询表很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于1个汉字的机内码是几位谢谢的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!

2026年10月11日 07:20

promote翻译(英语翻译倡导怎么说)

promote翻译(英语翻译倡导怎么说)

其实promote翻译的问题并不复杂,但是又很多的朋友都不太了解英语翻译倡导怎么说,因此呢,今天小编就来为大家分享promote翻译的一些知识,希望可以帮助到大家,下面我们一起来看看这个问题的分析吧!

2026年10月11日 06:30

最近更新

热门文章

标签列表