冒泡排序(Bubble Sort)是一种极其简单的排序算法。
它重复地走访过要排序的数列,依次比较相邻两个元素,如果他们的顺序错误就把他们调换过来,直到没有元素再需要交换,排序完成。
这个算法的名字由来是因为越小(或越大)的元素会经由交换慢慢“浮”到数列的顶端。
冒泡排序算法的运作如下:

  • 比较相邻的元素,如果前一个比后一个大,就把它们两个调换位置。
  • 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
  • 针对所有的元素重复以上的步骤,除了最后一个。
  • 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
152717655941622846076bd?from=pc.jpg
冒泡排序算法思路

冒泡排序的C语言代码如下:
  1. void vBubbleSort(int a[], int n){
  2. int i, j, temp;
  3. for (j = 0; j < n - 1; j++){ //每次最大元素就像气泡一样"浮"到数组的最后
  4. for (i = 0; i < n - 1 - j; i++){ //依次比较相邻的两个元素,使较大的那个向后移
  5. if(a[i] > a[i + 1]){
  6. temp = a[i];
  7. a[i] = a[i + 1];
  8. a[i + 1] = temp;
  9. }
  10. }
  11. }
15271730031497ea700167f?from=pc.jpg
冒泡排序算法

放几张图直观的了解下
152715375860977b4675db0?from=pc.jpg
对序列{ 6, 5, 3, 1, 8, 7, 2, 4 }进行冒泡排序

152717214672024e897b81d?from=pc.jpg

从上面的算法可以看出,没趟都要遍历比较,即使数据已经是排序好的,上面的第7趟完全可以不用排序的,因为第6趟的时候已经没有数据做交换了,对代码改进如下:
  1. void vBubbleSortChange(int a[], int n){
  2. int i,j,temp;
  3. int swapped = 1;
  4. for (j = 0; j < n - 1; j++){ //每次最大元素就像气泡一样"浮"到数组的最后
  5. swapped = 0;
  6. for (i = 0; i < n - 1 - j; i++){ //依次比较相邻的两个元素,使较大的那个向后移
  7. if(a[i] > a[i + 1]){ //交换两个数
  8. temp = a[i];
  9. a[i] = a[i + 1];
  10. a[i + 1] = temp;
  11. swapped = 1;
  12. }
  13. }
  14. if( swapped == 0) {j = n-1;}//如果没有元素交换,说明序列是顺序的,退出循环
  15. }
  16. }
1527176459929c4437e2b39?from=pc.jpg
冒泡排序算法改进

放一张直观些的图片,注意观察最后的几趟没有做遍历判断
152717728852295ec16a94e?from=pc.jpg
冒泡排序改进


冒泡排序还有一种更好的改进排序的方法,叫鸡尾酒排序。
鸡尾酒排序也就是定向冒泡排序, 鸡尾酒搅拌排序, 搅拌排序 (也可以视作选择排序的一种变形), 涟漪排序, 来回排序 or 快乐小时排序, 是冒泡排序的一种变形。
此演算法与冒泡排序的不同处在于排序时是以双向在序列中进行排序。
C语言代码如下:
  1. void vCockTailSort(int arr[],int len){
  2. int tmp,i,left=0,right = len-1;
  3. while(left < right){
  4. for(i=left;i<right;i++){//正向冒泡,确定最大值
  5. if(arr[i]>arr[i+1]){
  6. tmp = arr[i];
  7. arr[i] = arr[i+1];
  8. arr[i+1] = tmp;
  9. }
  10. }
  11. right--;
  12. for(i=right;i>left;i--){//反向冒泡,确定最小值
  13. if(arr[i]<arr[i-1]){
  14. tmp = arr[i];
  15. arr[i] = arr[i-1];
  16. arr[i-1] = tmp;
  17. }
  18. }
  19. left++;
  20. }
  21. }
15271767590722601003e3c?from=pc.jpg
鸡尾酒排序


上面的代码比较直观的展现了鸡尾酒排序的过程,但是也可以做些优化,就是在正反向遍历的时候记录最后一次交换元素的位置作为左右限制的边界,改进代码如下:
  1. void vCockTailSortChange(int arr[],int len){
  2. int tmp,i,left=0,right = len-1;
  3. int swapped = 1;
  4. bound = 0;//记录某趟遍历的最后一次交换元素的位置,优化减少循环次数
  5. while(swapped){//如果没有元素交换,说明序列是顺序的
  6. swapped = 0;
  7. for(i=left;i<right;i++){//正向冒泡,确定最大值
  8. if(arr[i]>arr[i+1]){
  9. tmp = arr[i];
  10. arr[i] = arr[i+1];
  11. arr[i+1] = tmp;
  12. swapped = 1;
  13. bound = i;
  14. }
  15. }
  16. right=bound;//缩小遍历边界
  17. for(i=right;i>left;i--){//反向冒泡,确定最小值
  18. if(arr[i]<arr[i-1]){
  19. tmp = arr[i];
  20. arr[i] = arr[i-1];
  21. arr[i-1] = tmp;
  22. swapped = 1;
  23. bound = i;
  24. }
  25. }
  26. left=bound;//缩小遍历边界
  27. }
  28. }
1527176946325fe9c28124d?from=pc.jpg
鸡尾酒排序算法改进边界

放一张更加直观的图片,注意图片中边界的优化
15271770320945395d582ad?from=pc.jpg
鸡尾酒排序优化边界