冒泡排序是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序为止
稳定性:冒泡排序是稳定排序
时间复杂度: 最好:O(n) 最差:O(n^2) 平均:O(n^2)
辅助空间:O(1)
以下的所有代码都要用到的swap函数在此给出
/*实现swap功能*/ void swap(int *a, int *b){ *a ^= *b; *b ^= *a; *a ^= *b; }
下面先看一段最简单的排序代码,从严格意义上说,它不算是标准的冒泡排序算法,因为它不满足 “两两比较相邻记录” 的冒泡排序思想,它更应该是最简单的交换排序而已。
交换排序的数组版本:
/* 对顺序表作交换排序(冒泡排序初级版) --- 数组版*/ void BubbleSort11(int *L, int n){ //注意下标从0开始 for (int i = 0; i < n - 1; ++i){ for (int j = i + 1; j < n; ++j){ if (L[j] < L[i]){ //其实是简单选择排序的记录位置改成了直接交换,因此此版本的冒泡排序是不稳定排序 swap(L + i, L + j); } }//for(j) }//for(i) }
交换排序的指针版本:
/* 对顺序表作交换排序(冒泡排序初级版) --- 指针版*/ /* [head,tail)为左闭又开区间*/ void BubbleSort12(int *head, int *tail){ for (int* p = head; p < tail - 1; ++p){ for (int* q = p + 1; q < tail; ++q){ if (*q < *p){ swap(p, q); } }//for(q) }//for(p) }
接下来便是正宗的冒泡排序算法,由于冒泡排序既可以从前往后冒泡,又可以从后往前冒泡,于是实现了从前往后冒泡和从后往前冒泡的数组、指针共4种版本。
/* 冒泡排序算法 --- 数组版(采用从后往前冒泡)*/ void BubbleSort21(int *L, int n){ for (int i = 0; i < n - 1; ++i){ for (int j = n - 1; j > i; --j){ if (L[j] < L[j - 1]) //若后者小于前者,前移 swap(L + j, L + j - 1); }//for(j) }//for(i) }
/* 冒泡排序算法 --- 数组版(采用从前往后冒泡)*/ void BubbleSort22(int *L, int n){ for (int i = n - 1; i > 0; --i){ for (int j = 0; j < i; ++j){ if (L[j] > L[j + 1]){ //若前者大于后者 swap(L + j, L + j + 1); } }//for(j) }//for(i) }
/* 冒泡排序算法 --- 指针版(采用从后往前冒泡)*/ /* 同理,[head, tail)为左闭右开区间 */ void BubbleSort23(int* head, int* tail){ for (int *p = head; p < tail - 1; ++p){ for (int *q = tail - 1; q > p; --q){ if (*q < *(q - 1)){ //后者小于前者,小的往前冒泡 swap(q, q - 1); } }//for(q) }//for(p) }
/* 冒泡排序算法 --- 指针版(采用从前往前后冒泡)*/ /* [head, tail)为左闭右开区间 */ void BubbleSort24(int* head, int* tail){ for (int* p = tail - 1; p > head; --p){ for (int* q = head; q < p; ++q){ if (*q > *(q + 1)){ //若前者大于后者,大的往后冒泡 swap(q, q + 1); } }//for(q) }//for(p) }
其实,以上的冒泡排序是可以优化的,如序列{2,1,3,4,5,6,7,8,9}只需交换第一、第二的关键字,别的都已经是正常的顺序。 因此第一次交换后,数据已经有序,此后的大量比较是多余的,那如何优化呢? 我们可以增加一个标记变量flag,用于标记序列是否已经有序,详见代码。
改进冒泡排序算法之数组版,从后往前冒泡
/* 改进的冒泡排序算法 --- 数组版(从后往前冒泡) */ void BubbleSort31(int* L, int n){ bool flag = true; //最开始是为了进入循环 for (int i = 0; i < n - 1 && flag; ++i){ flag = false; //初始化为false,若下面的循环未做更改,则数列已经有序,退出循环 for (int j = n - 1; j > i; --j){ if (L[j] < L[j - 1]){ //若后者小于前者,小的往前冒泡 swap(L + j, L + j - 1); flag = true; //更好做标记 } }//for(j) }//for(i) }
改进的冒泡排序算法之指针版,从前往后冒泡
/* 改进冒泡排序 --- 指针版(从前往后冒泡)*/ void BubbleSort32(int* head, int* tail){ bool flag = true; for (int* p = tail - 1; p > head && flag; --p){ flag = false; //若下面的循环没有交换,则已经是有序序列,退出循环 for (int* q = head; q < p; ++q){ if (*q > *(q + 1)){ //若前者大于后者,从后往前冒泡 swap(q, q + 1); flag = true; } }//for(q) }//for(p) }