写在前面
看了b站上清华老师邓俊辉邓老师的视频,把代码写下来自己记录记录,方便记忆和理解。
起泡排序算法
bubbleSort.1
这是个很简单也很容易理解的起泡排序算法。
算法开始逐行扫描,每次能找到最大者然后放在最后。因此需要的扫描的次数逐行递减,最后排序完成。
代码如下
void bubblesort ( int A[], int n ) { //起泡排序算法(版本0):0 <= n
while ( n-- ) { //在尚未确认已全局排序之前,逐趟进行扫描交换
for ( int i = 0; i < n; i++ ) { //自左向右逐对检查当前范围A[0, n)内的各相邻元素
if ( A[i] > A[i+1] ) { //一旦A[i]与A[i+1]逆序,则
swap ( A[i], A[i+1] ); //交换之,并
}
}
}
} //蛮力算法,不能及时提前退出,总是必须做n-1趟扫描交换
算法的正确性:
1.经过k趟扫描交换后,最大的k个元素必然就位。
2.经过k趟扫描后,问题规模缩减至n-k。
3.至多经过n-1趟,算法必然终止,且给出正确答案。
4.时间效率在最好最坏情况下都是O(n^2)
显然,我们有更好的策略改进这个算法。
可能出现这种情况,当机器经过某次扫描后可能剩下的都是有序的,这个时候我们就想可不可以提前终止这个算法,显然,是可以的。
bubbleSort.2
while版本
void bubblesort1A ( int A[], int n ) { //起泡排序算法(版本1A):0 <= n
bool sorted = false; //整体排序标志,首先假定尚未排序
while ( !sorted ) { //在尚未确认已全局排序之前,逐趟进行扫描交换
sorted = true; //假定已经排序
for ( int i = 1; i < n; i++ ) { //自左向右逐对检查当前范围A[0, n)内的各相邻元素
if ( A[i - 1] > A[i] ) { //一旦A[i - 1]与A[i]逆序,则
swap ( A[i - 1], A[i] ); //交换之,并
sorted = false; //因整体排序不能保证,需要清除排序标志
}
}
n--; //至此末元素必然就位,故可以缩短待排序序列的有效长度
}
} //
for循环版本
void bubbleSort(int A[],int n){
for(bool sorted=false;sorted=!sorted;n--){
for(int i=0;i<n-1;i++){
if(A[i]>A[i+1]){
swap(A[i],A[i+1]);
sorted=false;
}
}
}
}
注意while和for版本的区别,在while版本中,我们的i起始位置是1,for版本起始位置是0;
我们可能经常是让i从0开始(例如上面的bubbleSort.1),所以要注意两者之间的区别。
当i从0开始时,我们需要在i<n-1时跳出内层循环,不然可能会造成A[n-1]和A[n]比较并交换数据,造成结果错误;当i从1时,我们则需进行A[i-1]和A[i]的比较,在i<n时跳出内层循环。
在bubbleSort.2中我们借助布尔型标志位sorted,可及时提前退出,而不致总是蛮力地做n - 1趟扫描交换。不过,如果我们在完成某次扫描就位后,可能会发现这种情况:
在这里发现hi前面的一段元素是就位好了的,我们就发现可以让遍历次数大幅度的减小,让n=last,
这样就可以减少我们扫描时比较的次数。于是,有了下面的版本。
bubbleSort.3
void bubbleSort(int A[],int n){
for(int m;1<n;n=m){//在尚未确认已全局排序之前,逐趟进行扫描交换
for(int i=m=0;i<n-1;i++){ //自左向右逐对检查当前范围A[0, m)内的各相邻元素
if(A[i]>A[i+1]){//一旦A[i-1]与A[i]逆序,则
swap(A[i],A[i+1]);//交换之,并
m=i+1;//更新待排序区间的长度
}
}
}
}
我们让m=i+1,也就是此趟扫描最后交换元素的秩,直接让n=m,就能跳过Last到hi之间排序正确的元素,省略了在bubbleSort.2版本中下一趟需要比较的次数。
特点:
**1.对尾部有序(或接近有序)的输入,算法收敛的速度大大提高
2.元素交换的次数仅取决于输入序列
分析:
该算法在输入数据都是顺序时时间效率最好,为O(n),即为算遍历比较一遍然后退出。
输入数据是逆序排列时时间效率最坏,为O(n^2),即为每次都就位最大的元素,重复n-1次。
同时,该算法也是稳定的。**如下图所示:
在上图中,有三个值相同但下标有序的数,当我们排序为7a,7b,7c时,我们认为它是稳定的。
显然,bubbleSort算法的三个版本都是稳定的,因为只有前一个元素严格大于后一个元素(A[i]>A[i+1])时,我们才执行swap语句。
写在后面
排序算法有很多种,选择排序、归并排序以及还可能学习的堆排序、快速排序。
不过,起泡排序就值得我们多多练习,多多思考。