冒泡排序(交换排序)-八大排序汇总(3)
基本思想
两两相邻元素之间的比较,如果前者大于后者,则交换;
设数组长度为N。
1.比较相邻的前后二个数据,如果前面数据大于后面的数据,就将二个数据交换。
2.这样对数组的第0个数据到N-1个数据进行一次遍历后,最大的一个数据就“沉”到数组第N-1个位置。
3.N=N-1,如果N不为0就重复前面二步,否则排序完成。
稳定性
冒泡排序是一种稳定的排序算法
时间复杂度
若文件的初始状态是正序的,一趟扫描即可完成排序。所需的关键字比较次数 和记录移动次数 均达到最小值: , 。所以,冒泡排序最好的时间复杂度为 。
若初始文件是反序的,需要进行 趟排序。每趟排序要进行 次关键字的比较(1≤i≤n-1),且每次比较都必须移动记录三次来达到交换记录位置(swap函数)。在这种情况下,比较和移动次数均达到最大值:
原始待排序数组| 6 | 2 | 4 | 1 | 5 | 9 |
第一趟排序(外循环)
第一次两两比较6 > 2交换(内循环)
交换前状态| 6 | 2 | 4 | 1 | 5 | 9 | 交换后状态| 2 | 6 | 4 | 1 | 5 | 9 |
第二次两两比较,6 > 4交换
交换前状态| 2 | 6 | 4 | 1 | 5 | 9 | 交换后状态| 2 | 4 | 6 | 1 | 5 | 9 |
第三次两两比较,6 > 1交换
交换前状态| 2 | 4 | 6 | 1 | 5 | 9 | 交换后状态| 2 | 4 | 1 | 6 | 5 | 9 |
第四次两两比较,6 > 5交换
交换前状态| 2 | 4 | 1 | 6 | 5 | 9 | 交换后状态| 2 | 4 | 1 | 5 | 6 | 9 |
第五次两两比较,6 < 9不交换
交换前状态| 2 | 4 | 1 | 5 | 6 | 9 | 交换后状态| 2 | 4 | 1 | 5 | 6 | 9 |
第二趟排序(外循环)
第一次两两比较2 < 4不交换
交换前状态| 2 | 4 | 1 | 5 | 6 | 9 | 交换后状态| 2 | 4 | 1 | 5 | 6 | 9 |
第二次两两比较,4 > 1交换
交换前状态| 2 | 4 | 1 | 5 | 6 | 9 | 交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |
第三次两两比较,4 < 5不交换
交换前状态| 2 | 1 | 4 | 5 | 6 | 9 | 交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |
第四次两两比较,5 < 6不交换
交换前状态| 2 | 1 | 4 | 5 | 6 | 9 | 交换后状态| 2 | 1 | 4 | 5 | 6 | 9 |
第三趟排序(外循环)
第一次两两比较2 > 1交换
交换后状态| 2 | 1 | 4 | 5 | 6 | 9 | 交换后状态| 1 | 2 | 4 | 5 | 6 | 9 |
第二次两两比较,2 < 4不交换
交换后状态| 1 | 2 | 4 | 5 | 6 | 9 | 交换后状态| 1 | 2 | 4 | 5 | 6 | 9 |
第三次两两比较,4 < 5不交换
交换后状态| 1 | 2 | 4 | 5 | 6 | 9 | 交换后状态| 1 | 2 | 4 | 5 | 6 | 9 |
第四趟排序(外循环)无交换
第五趟排序(外循环)无交换
1 #include "stdafx.h" 2 #include <iostream> 3 using namespace std; 4 5 void print(int a[], int n ,int i) 6 { 7 cout<<"第"<<i+1 <<"趟 : "; 8 for(int j= 0; j<n; j++) 9 { 10 cout<<a[j] <<" "; 11 } 12 cout<<endl; 13 } 14 15 void bubbleSort(int a[], int n) 16 { 17 for(int i =0 ; i< n-1; ++i) 18 { 19 for(int j = 0; j < n-1-i; ++j) //for(int j = n-1; j > i; j--) 20 { 21 if(a[j] > a[j+1]) 22 { 23 int tmp = a[j] ; 24 a[j] = a[j+1] ; 25 a[j+1] = tmp; 26 } 27 } 28 print(a,n,i); 29 } 30 } 31 32 int main(int argc, char* argv[]) 33 { 34 int a[6] = {6,2,4,1,5,9}; 35 36 bubbleSort(a, 6); 37 return 0; 38 }
可以看到,从第三次交换后就已经排好序了,之后的比较是多余的,所以可以加一个标志,如果一次循环中没有交换过元素,则说明已经排好序。
1 void print(int a[], int n ,int i) 2 { 3 cout<<"第"<<i+1 <<"趟 : "; 4 for(int j= 0; j<n; j++) 5 { 6 cout<<a[j] <<" "; 7 } 8 cout<<endl; 9 } 10 11 void bubbleSort(int a[], int n) 12 { 13 bool isChanged = false; 14 for(int i =0 ; i< n-1; ++i) 15 { 16 isChanged = false; 17 for(int j = 0; j < n-1-i; ++j) //for(int j = n-1; j > i; j--) 18 { 19 if(a[j] > a[j+1]) 20 { 21 int tmp = a[j] ; 22 a[j] = a[j+1] ; 23 a[j+1] = tmp; 24 25 isChanged = true; 26 } 27 } 28 print(a,n,i); 29 if(isChanged == false) 30 break; 31 } 32 } 33 34 int main(int argc, char* argv[]) 35 { 36 int a[6] = {6,2,4,1,5,9}; 37 38 bubbleSort(a, 6); 39 return 0; 40 }
再做进一步的优化。如果有100个数的数组,仅前面10个无序,后面90个都已排好序且都大于前面10个数字,那么在第一趟遍历后,最后发生交换的位置必定小于10,且这个位置之后的数据必定已经有序了,记录下这位置,第二次只要从数组头部遍历到这个位置就可以了。
1 //冒泡排序3 2 void BubbleSort3(int a[], int n) 3 { 4 int j, k; 5 int flag; 6 7 flag = n; 8 while (flag > 0) 9 { 10 k = flag; 11 flag = 0; 12 for (j = 1; j < k; j++) 13 if (a[j - 1] > a[j]) 14 { 15 Swap(a[j - 1], a[j]); 16 flag = j; 17 } 18 } 19 }