冒泡排序
- 冒泡排序(Bubble Sort),一种交换排序,两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为止。
基本思想
- 基本思想:从无序序列头部开始,进行两两比较,根据大小交换位置,直到最后将最大(小)的数据元素交换到了无序队列的队尾,从而成为有序序列的一部分;下一次继续这个过程,直到所有数据元素都排好序。
- 算法核心:每次通过两两比较交换位置,选出剩余无序序列里最大(小)的数据元素放到队尾。
- 运行过程:
- 比较相邻元元素,第一个比第二个大(小),交换。
- 从序列头到尾做同样的工作,这样序列中最大(小)的元素被交换到最后一位。
- 除去已经选出的元素,对剩下的元素重复以上的步骤。
- 持续对每次越来越少的元素(无序)重复上面的步骤,直到没有任何一对数字需要比较,则序列最终有序。
- 示例
算法实现(核心代码)
代码部分使用了Utils类,定义在这篇文章中有说明。
核心代码:
//C++实现
void bubbleSort(int* A, int n){
if(A==NULL || n==0){
return;
}
for(int i=n-1; i>=0; i--){
for(int j=0; j<i; j++){
if(A[j]>A[j+1]){
Utils::swap(A, j, j+1);
}
}
}
}
算法优化和变种
- 设置交换标志变量flag
试想一下,如果待排序的序列是[1,2,3,4,5,6,7,9,8],也就是倒数第一和倒数第二个关键字需要交换,别的都已经是正常顺序,当i=1时,交换了8和9,序列已经有序,但是算法仍然将i=2~9以及每个循环中的j循环都执行一遍,虽然没有交换数据,但这种大量的比较也是多余的,优化的方法是当一趟冒泡中并没有发生交换时,说明序列已经时有序的了,这时候便可以停止运行,所以改进代码,增加一个flag变量用来标记是否有交换的发生。C++实现如下:
void bubbleSort(int* A, int n){
if(A==NULL || n==0){
return;
}
bool flag = true; //定义标志变量flag
for(int i=n-1; i>=0 && flag; i--){
flag = false; //循环开始置为false
for(int j=0; j<i; j++){
if(A[j]>A[j+1]){
Utils::swap(A, j, j+1);
flag = true; //发生交换置为true
}
}
}
}
- 鸡尾酒排序
鸡尾酒排序又叫定向冒泡排序,搅拌排序、来回排序等,是冒泡排序的一种变形。此算法与冒泡排序的不同处在于排序时是以双向在序列中进行排序。
鸡尾酒排序在于排序过程是先从低到高,然后从高到低;而冒泡排序则仅从低到高去比较序列里的每个元素。它可以得到比冒泡排序稍微好一点的效能,原因是冒泡排序只从一个方向进行比对(由低到高),每次循环只移动一个项目。
以序列(2,3,4,5,1)为例,鸡尾酒排序只需要从低到高,然后从高到低就可以完成排序,但如果使用冒泡排序则需要四次。
但是在乱数序列的状态下,鸡尾酒排序与冒泡排序的效率都很差劲。
//C++实现
void cocktailSort(int* A, int n){
int j, left = 0, right = n-1;
while(left<right){
for(j=left; j<right; j++){
if(A[j]>A[j+1]){
Utils::swap(A, j, j+1);
}
}
right--;
for(j=right; j>left; j--){
if(A[j-1]>A[j]){
Utils::swap(A, j-1, j);
}
}
left++;
}
}
性能分析
-
时间复杂度
在设置标志变量之后:
当原始序列“正序”排列时,冒泡排序总的比较次数为n-1,移动次数为0,也就是说冒泡排序在最好情况下的时间复杂度为O(n);
当原始序列“逆序”排序时,冒泡排序总的比较次数为n(n-1)/2,移动次数为3n(n-1)/2次,所以冒泡排序在最坏情况下的时间复杂度为O(n^2);
当原始序列杂乱无序时,冒泡排序的平均时间复杂度为O(n^2)。
-
空间复杂度
冒泡排序排序过程中需要一个临时变量进行两两交换,所需要的额外空间为1,因此空间复杂度为O(1)。
-
稳定性
冒泡排序在排序过程中,元素两两交换时,相同元素的前后顺序并没有改变,所以冒泡排序是一种稳定排序算法。
附:完整实现和测试
#include <iostream>
#include "Utils.h"
using namespace std;
class BubbleSort{
public:
void bubbleSort(int* A, int n){
if(A==NULL || n==0){
return;
}
bool flag = true;
for(int i=n-1; i>=0 && flag; i--){
flag = false;
for(int j=0; j<i; j++){
if(A[j]>A[j+1]){
Utils::swap(A, j, j+1);
flag = true;
}
}
}
}
void cocktailSort(int* A, int n){
int j, left = 0, right = n-1;
while(left<right){
for(j=left; j<right; j++){
if(A[j]>A[j+1]){
Utils::swap(A, j, j+1);
}
}
right--;
for(j=right; j>left; j--){
if(A[j-1]>A[j]){
Utils::swap(A, j-1, j);
}
}
left++;
}
}
};
int main(int argc, char const *argv[])
{
int n = 10;
int range = 100;
int *arr = Utils::generateArray(n,range);
Utils::printArray(arr, n);
BubbleSort bubble = BubbleSort();
// bubble.bubbleSort(arr, n);
bubble.cocktailSort(arr, n);
Utils::printArray(arr, n);
return 0;
}
参考链接:
https://blog.youkuaiyun.com/guoweimelon/article/details/50902597
https://zh.wikipedia.org/zh/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F