冒泡排序
- 冒泡排序(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.csdn.net/guoweimelon/article/details/50902597
https://zh.wikipedia.org/zh/%E5%86%92%E6%B3%A1%E6%8E%92%E5%BA%8F