冒泡排序以及优化
最近需要用到冒泡排序,所以翻出来研究一下。冒泡排序的基础其实就是元素交换,是一种极其简单的排序算法。
话不多说,直接上代码:
1 #include <stdio.h> 2 void bubble_sort(int arr[], int len) 3 { 4 int i, j, temp; 5 for(i = 0; i < len - 1; i++) 6 { 7 for(j = 0; j < len - 1; j++) 8 { 9 if(arr[j] > arr[j + 1]) 10 { 11 temp = arr[j]; 12 arr[j] = arr[j + 1]; 13 arr[j + 1] = temp; 14 } 15 } 16 } 17 } 18 19 int main () 20 { 21 int arr[] = {22, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70}; 22 int len = (int)sizeof(arr)/sizeof(arr[0]); 23 int i; 24 bubble_sort(arr, len); 25 for(i = 0; i < len; i++) 26 { 27 printf("%d ",arr[i]); 28 } 29 return 0; 30 }
以上是基础版,下面来讲一下原理。
首先初始化一个数组 arr[] = {22, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70} 我们需要从小到大对数组元素进行排序,运用最简单的元素交换步骤,比较相邻两个元素的大小,比较后,数值较大的往后移动。由此,两两比较多次后(这是一趟排序),数值最大的元素移动到数组尾部。经过多趟排序之后,数组元素将从小到大排列。
但是这样的排序并不是最优选择。因为按照以上的算法,即使后面的数据已经排序完成,还是每一趟都要遍历。以下是优化的算法:
1 #include <stdio.h> 2 void bubble_sort(int arr[], int len) 3 { 4 int i, j, temp; 5 int swapped = 1; //设置交换的标志位 6 for(i = 0; i < len - 1; i++) 7 { 8 swapped = 0; 9 for(j = 0; j < len - 1 - i; j++) //减少了需要遍历的次数 10 { 11 if(arr[j] > arr[j + 1]) 12 { 13 temp = arr[j]; 14 arr[j] = arr[j + 1]; 15 arr[j + 1] = temp; 16 swapped = 1; //如果有数据交换,表示序列还没有完成排序,继续进行循环 17 } 18 } 19 if(swapped == 0) //如果没有元素交换,表示序列是顺序状态,退出循环 20 { 21 j = len - 1; 22 } 23 } 24 } 25 int main () 26 { 27 int arr[] = {22, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70}; 28 int len = (int)sizeof(arr)/sizeof(*arr); 29 int i; 30 bubble_sort(arr, len); 31 for(i = 0; i < len; i++) 32 { 33 printf("%d ",arr[i]); 34 } 35 return 0; 36 }
当然,冒泡排序还有更优化的方法:鸡尾酒排序,这种方法特点是在排序的过程中是双向进行的。程序如下:
1 #include <stdio.h> 2 3 void CockTailSort(int arr[], int len); 4 void swap(int *a, int *b); 5 6 int main () 7 { 8 int arr[] = {22, 34, 3, 32, 82, 55, 89, 50, 37, 5, 64, 35, 9, 70}; 9 int len = (int)sizeof(arr)/sizeof(*arr); 10 int i; 11 CockTailSort(arr, len); 12 for(i = 0; i < len - 1; i++) 13 { 14 printf("%d ",arr[i]); 15 } 16 return 0; 17 } 18 19 void swap(int *a, int *b) //交换两元素的值 20 { 21 int t; 22 t=*a; 23 *a=*b; 24 *b=t; 25 } 26 27 void CockTailSort(int arr[], int len) 28 { 29 int i, left = 0, right = len - 1; 30 int swapped = 1; 31 while(swapped) 32 { 33 swapped = 0; 34 for(i = left; i < right; i++) //向右排序,确认最大元素 35 { 36 if(arr[i] > arr[i+1]) 37 { 38 swap(&arr[i], &arr[i+1]); 39 swapped = 1; 40 } 41 } 42 right--; 43 for(i = right; i > left; i--) //向左排序,确认最小元素 44 { 45 if(arr[i] < arr[i-1]) 46 { 47 swap(&arr[i], &arr[i-1]); 48 swapped = 1; 49 } 50 } 51 left++; 52 } 53 }
下图是排序的模式,更直观一点:
冒泡排序,最好的情况是序列已经是正序,时间复杂度为O(n),最坏的当然是逆序,时间复杂度为O(n^2),另外冒泡排序需要一个空间作为数据交换的临时存储单元,因此空间复杂度为O(1)。