1.基本冒泡排序
冒泡排序的基本思想:假设被排序的记录数组d[1...N]垂直竖立,将每个记录d[i]看作是一个气泡,那么重的气泡就会向下下沉,轻的气泡就会向上升。每次都是相邻的两个气泡d[i]和d[i+1]进行比较。如果d[i]>d[i+1],那么就交换两个气泡,然后在比较d[i+1]和d[i+2],以此类推,知道所有的气泡都有序排列。假设排序20,37,11,42,29。
第1次冒泡:20。37,11,42,29 d[0]和d[1]比较 第2次冒泡:20,11,37,42,29 d[1]和d[2]比较 第3次冒泡:20,11,37,42,29 d[2]和d[3]比较 第4次冒泡:20,11,37,29,42 d[3]和d[4]比较
那么就找到了最重的气泡42,接下来按同样的方法找出第二重、第三重……的气泡,直到完成排序。根据以上分析可知需要双层循环。第一层循环控制次数,第二层循环控制要排序的数据范围。如下所示
第0次比较第0个到第n-1个,下标控制0~n-2 第1次比较第0个到第n-2个,下标控制0~n-3 . . 第i次比较第0到第n-i+1个,下标控制0到n-i-2 . . 第n-2次比较第0到第1个,下标控制0到0
冒泡排序算法的代码如下
int main(void) { int i, j, tmp; int N = 5; int a[N] = {20,37,11,42,29}; for( i=0; i<N; i++ ){ for( j=0; j<N-i-1; j++ ){ if( a[j]>a[j+1] ){ tmp = a[j]; a[j] = a[j+1]; a[j+1] = tmp; } } } for(i=0; i<N; i++) printf("%d\n", a[i]); return 0; }
冒泡排序的最好、最坏、平均情况下的时间复杂度都是O(n^2)。但是若在某趟排序中未发现气泡位置的交换,则说明排序的无序区中所有的气泡均满足轻者在上,重者在下的原则,即为正序,则冒泡排序过程可在此次扫描后就终止。基于这种考虑,提出第一种改进算法
2.冒泡排序算法优化一:不做每次扫描都判断是否已经排序完成
如果在某趟循环中没有任何数据交换发生,则表明数据已经排序完成。那么剩余的循环就不需要再执行了。改进后的算法代码如下
int main(void) { int i, j, tmp; int N = 5; int isSorted = 0; int a[5] = {20,37,11,42,29}; for( i=0; i<N&&(!isSorted); i++ ){ //只有在没有排序的情况下(!isSorted)才进行继续循环 isSorted = 1; //设定排序标志 for( j=0; j<N-i-1; j++ ){ if( a[j]>a[j+1] ){ isSorted = 0; //如果没有排序,就重新设定标志 tmp = a[j]; a[j] = a[j+1]; a[j+1] = tmp; } } } for(i=0; i<N; i++) printf("%d\n", a[i]); return 0; }
这种排序方法,如果数据初始状态就是正序,那么扫描一趟就可以完成。所需要的比较和数据移动的次数分别时最小值n-1和0,也就是算法最好的时间复杂度是O(n);若初始数据反序,则需要进行n-1趟排序,每趟排序进行n-i次关键字的比较,且每次比较都必须移动数据三次来达到交换数据位置,这种情况下比较次数达到最大值n(n-1)/2,移动次数也达到最大值3n(n-1)/2,所以最坏的时间复杂度还是O(n^2)。平均的时间复杂度仍为O(n^2)
3.冒泡排序算法优化二:
借鉴 http://blog.chinaunix.net/uid-22744029-id-1770037.html