冒泡排序(Bubble Sort)是基本的交換排序算法之一
-
定義:通過相鄰之間的元素比較大小,進行交換。
-
基本思想:若前一個比後一個大,則交換,第一趟會把最大的放到最後。
-
時間複雜度:O(n^2)
-
穩定性:穩定(若元素相同,穩定即表示通過排序之後獲得的數組中,相同元素的位置不會發生改變)
1. 實現(下面分別用C語言,Java,和JavaScript 實現)
(1)C語言
#include<stdio.h>
int main()
{
int i,j;
int a[10] = {34,65,2,43,54,64,23,49,78,89};
for(i=0;i<10-1;i++){
for(j = 0;j<10-i-1;j++){
if(a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
for(i=0;i<10;i++)
{
printf("%5d",a[i]);
}
printf("\n");
return 0;
}
運行結果如下
(2)Java
public class Bubble_Sort {
public static void main(String[] args){
int i,j;
int [] a = {34,65,2,43,54,64,23,49,78,89};
for(i=0;i<10-1;i++){
for(j = 0;j<10-i-1;j++){
if(a[j]>a[j+1]){
int temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
for(i=0;i<10;i++)
{
System.out.print(a[i]+" ");
}
}
}
運行結果如下
(3)JavaScript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
var i,j;
var a = [34,65,2,43,54,64,23,49,78,89];
for(i=0;i<a.length-1;i++){
for(j = 0;j<a.length-i-1;j++){
if(a[j]>a[j+1]){
var temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
}
console.log(a);
</script>
</body>
</html>
運行結果如下:
2. 優化(3種優化,JavaScript實現)
(1)設置標誌位(適用於連片有序,但整體無序數據)
在排序過程中,如果有一趟沒有進行交換,則表示已完成排序,即不必繼續比較後面的元素,所以我們在交換處設置flag標誌位,若flag值沒有發生變化,則說明排序完成,跳出循環。
上面的js代碼若每一趟輸出數組a,則結果如下:
進行了9次排序。
優化代碼如下(js)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
var i,j,flag = 0;
var a = [34,65,2,43,54,64,23,49,78,89];
for(i=0;i<a.length-1;i++){
flag = 0;
for(j = 0;j<a.length-i-1;j++){
if(a[j]>a[j+1]){
flag = 1;
var temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
if(flag == 0){//表示這一趟沒有進行交換,即排序完成
break;
}
console.log(a);
}
</script>
</body>
</html>
優化之後進行了5次排序,運行結果如下:
(2)每次交換記錄最後一次的位置(適用於前面無序,但是後面有序)
記錄每趟交換的最後位置作爲下趟比較的結束位置,到0時停止。因爲沒有交換,說明後面的數據已經有序,所以不做無效比較,下次直接比較到上次交換的最後位置即可。
一般的冒泡排序比較次數都是逐次少1,如圖:
數字爲每趟的比較次數,數組a爲每次的排序結果
但是優化會減少它的比較次數(代碼及結果如下)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
var i,j,end,t,c = 0;
var a = [34,65,2,43,54,64,23,49,78,89];
end = a.length-1;
for(i=0;i<a.length-1;i++){
t = 0;
c = 0;//記錄比較次數,看是否優化
for(j = 0;j<end;j++){
c++;
if(a[j]>a[j+1]){
t = j;//記錄比較的位置
var temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
}
}
console.log(c);
end = t;//把比較的最後位置作爲下次比較的結束位置
console.log(a);
if(t == 0){
break;
}
}
</script>
</body>
</html>
(3)雙向冒泡排序
每次既從左往右找最大值,又從右往左找最小值,把最大值放最後,最小值放前面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script>
var a = [34,65,2,43,54,64,23,49,78,89];
var i,j,end,t,c = 0,flag;
var left = 0;//左邊界的初始值
var right = a.length-1;//右邊界的初始值
var before = 0,after = 0;//記錄左右邊界的最後一次位置
for(i=0;i<a.length-1;i++){
flag = 0;c = 0;
//正向尋找最大值
for(j = left;j<right;j++){
if(a[j]>a[j+1]){
c++;
after = j;//記錄比較的位置
var temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
flag = 1;
}
}
//反向尋找最小值
for(j = right;j>left;j--){
if(a[j]<a[j+1]){
c++;
before = j;//記錄比較的位置
var temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
flag = 1;
}
}
if(flag == 0){
break;
}
left = before;
right = after;
console.log(c);
console.log(a);
}
</script>
</body>
</html>
運行結果如下:(數字表示比較次數,數組爲每趟比較結果)
最後說一下穩定性。
一般來說,冒泡排序是穩定的,但是一個排序的穩定性主要還是由具體算法決定,不穩定的算法在某種條件下可以變爲穩定的算法,而穩定的算法在某種條件下也可以變爲不穩定的算法。比如今天所分享的冒泡排序,將元素交換的條件改成a[j]>=a[j+1],則兩個相等的元素就會交換位置,即不穩定。