在我的博文《「主宰世界」的10種演算法短評》中給出的首個演算法就是高效的排序演算法。本文將對排序演算法做乙個全面的梳理,從最簡單的「冒泡」到高效的堆排序等。
排序:將一組雜亂無章的資料按一定的規律順次排列起來。
資料表( data list): 它是待排序資料物件的有限集合。排序碼(key):通常資料物件有多個屬性域,即多個資料成員組成,其中有乙個屬性域可用來區分物件,作為排序依據。該域即為排序碼。每個資料表用哪個屬性域作為排序碼,要視具體的應用需要而定。分類
內排序:指在排序期間資料物件全部存放在記憶體的排序;外排序:指在排序期間全部物件個數太多,不能同時存放在記憶體,必須根據排序過程的要求,不斷在內、外存之間移動的排序。
如果在物件序列中有兩個物件r[i]和r[j] ,它們的排序碼k[i]==k[j] 。如果排序前後,物件r[i]和r[j] 的相對位置不變,則稱排序演算法是穩定的;否則排序演算法是不穩定的。
時間開銷
排序的時間開銷可用演算法執行中的資料比較次數與資料移動次數來衡量。 演算法執行時間代價的大略估算一般都按平均情況進行估算。對於那些受物件排序碼序列初始排列及物件個數影響較大的,需要按最好情況和最壞情況進行估算
空間開銷
演算法執行時所需的附加儲存。
交換排序的基本思想是:兩兩比較待排序記錄(資料表)的關鍵字(排序碼),發現兩個記錄的次序相反時即進行交換,直到沒有反序的記錄為止。主要包括氣泡排序和快速排序。
演算法思想及步驟
氣泡排序是第乙個接觸也最容易理解的排序演算法,因為就像泡泡一樣,最輕的率先「冒」出來佔據第一的位置,隨後是剩下的最輕的再冒出來,佔據第二的位置,就這樣一步步冒出來,也就完成了排序。
物件個數n。最多作最多作n-1趟, i= 0, 2, …, n-1 。 第i趟中從後向前j= n-1, n-2, ……, i,順次兩兩比較。 比較如果發生逆序,則交換v[j-1] 和v[j]。總之就是每一趟都是將剩餘中最大或最小的資料項排在前面已經「冒」出來的資料表後面,遍歷完畢也就實現了排序。
演算法分析
最好情況:正序排列,比較次數(kcn):n−1 ; 移動次數(rmn):為0。則對應的時間複雜度為o(n)。
完全正序排列的話,只需一趟就能判定是否有序,如果遍歷j之後發現沒有發生逆序就說明已經有序,所以,共比較了n−1次,移動0次。
最壞情況:逆序排序,比較次數(kcn):∑n−1i=1(n−i)=n(n−1)2;移動次數(rmn):3∑n−1i=1(n−i)=3n(n−1)2。
完全逆序排序的話,第i都要比較n−i次,而每次比較都要移動3次資料項來交換記錄位置。因此總的時間複雜度為o(n2)。
它需要乙個附加空間,是乙個穩定的排序演算法。
氣泡排序的c plus plus實現#include
using namespace std;
void bubblesort(int a, int size)
}for(k = 0; k < size; k++)
cout << a[k] << ;
cout << endl;
}int dummy = 1;
}int main()
; const size_t sz = sizeof(a)/sizeof(a[0]);
for(k = 0; k < sz; k++)
cout << a[k] << ;
cout << endl;
cout << ********************== << endl;
bubblesort(a,sz);
cout << ********************== << endl;
for(k = 0; k < sz; k++)
cout << a[k] << ;
cout << endl;
}這裡給出的bubblesort其實可以簡化,每趟排序都將最大的冒到了最後,所以最後已經排序的不必再進行比較了,從而可以節省一些比較的次數。改進如下:
void bubblesort(int a, int size)
}for(k = 0; k < size; k++)
cout << a[k] << ;
cout << endl;
}int dummy = 1;
}輸出結果如下:
5 7 1 3 4 9 2 6 8 0
//********************==
5 1 3 4 7 2 6 8 0 9
1 3 4 5 2 6 7 0 8 9
1 3 4 2 5 6 0 7 8 9
1 3 2 4 5 0 6 7 8 9
1 2 3 4 0 5 6 7 8 9
1 2 3 0 4 5 6 7 8 9
1 2 0 3 4 5 6 7 8 9
1 0 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
//********************==
0 1 2 3 4 5 6 7 8 9
注意到,如果此實現中如果給定的資料已經有序,則並不能實現最好情況中所分析的比較次數,因為並沒有設定檢測每趟是否發生過資料項的交換,如果沒有發生資料交換則說明資料表已經有序,則不必進行下一趟的排序了。因此,可以修改**為:
void bubblesort(int a, int size)
}for(k = 0; k < size; k++)
cout << a[k] << ;
cout << endl;
if(isreplaced==0) break;
}int dummy = 1;
}通過測試資料int a = ;進行對比:
未新增資料項交換檢查標誌的資料輸出:
0 1 5 4 3 2 6 7 8 9
********************==
0 1 4 3 2 5 6 7 8 9
0 1 3 2 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
********************==
0 1 2 3 4 5 6 7 8 9
請按任意鍵繼續. . .新增資料相交換檢查標誌的資料輸出:
0 1 5 4 3 2 6 7 8 9
********************==
0 1 4 3 2 5 6 7 8 9
0 1 3 2 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
********************==
0 1 2 3 4 5 6 7 8 9
請按任意鍵繼續. . .從對比中可以看出,通過判斷之後能夠提前終止一輪一輪的交換排序,減少不必要的比較過程。
排序演算法 C 四)交換排序之氣泡排序
前三篇都是插入排序,隨後的氣泡排序和快速排序是交換排序 氣泡排序有兩種,1 每次把最大數放到末尾 2 每次把最小的放在行首。其實都是一樣的。本文是每次找最大值,放在末尾。找最大值,往末尾放,則必須從行首開始遍歷,先拿第乙個數跟第二個比較,a 1 a 2 兩者交換,然後a 2 和a 3 比較,a 2 ...
排序演算法 交換排序之冒泡
一 主要思想 顧名思義,交換排序的主要操作是交換,其主要思想是在待排序列中選兩個記錄,將它們的關鍵碼相比較,如果反序 即排列順序與排序後的次序正好相反 則交換它們的儲存位置。二 需要解決的關鍵問題 1 在一趟起泡排序中,若有多個紀錄位於最終位,應如何記載 解決方法 設定變數 exchange 記載記...
排序 交換排序之氣泡排序
在排序演算法中還有一大類是交換類排序,其中最為常見,最好理解的便是氣泡排序了。氣泡排序的演算法思想 通過無序區中相鄰記錄關鍵字的比較和位置的交換,使得關鍵字最小 最大 的記錄如冒泡一般上浮,至水面 有序區 整個演算法從最下面的記錄開始,對每兩個相鄰的記錄的值進行比較,使關鍵字較小的交換至較大的記錄之...