簡介
以下總結幾個基礎的排序算法,包括選擇排序、插入排序、冒泡排序、希爾排序,這幾個排序算法是比較簡單的幾個。以下給出算法的分析和代碼示例。
時間複雜度
選擇排序、插入排序、冒泡排序、希爾排序四個排序算法的時間複雜度都是O(n^2)。
算法分析
選擇排序
選擇排序取第一個元素以此與後續的元素進行比較,保存最小的元素的下標,最終把最小的元素與第一個元素進行交換,第二次遍歷取第二個元素,在剩餘元素中選擇最小的元素與第二個元素交換,依次類推。。。。,最終實現把所有元素按照從小到大進行排序。
以下爲代碼示例
template<typename T>
void selectionSort(T arr[], int n){
for(int i = 0 ; i < n ; i ++){
int minIndex = i;
for( int j = i + 1 ; j < n ; j ++ )
if( arr[j] < arr[minIndex] )
minIndex = j;
swap( arr[i] , arr[minIndex] );
}
}
選擇排序是基礎的排序算法,但需要重點理解,以後複雜的算法也都會以此爲基礎進行衍生。
插入排序
插入排序分爲兩種,第一種是直接插入排序,第二種是折半插入排序,以下分別描述兩種排序的基本思想:
直接插入排序的基本思想:當插入第i(i>1)個元素時,前面的data[0],data[1]……data[i-1]已經排好序。這時用data[i]的排序碼與data[i-1],data[i-2],……的排序碼順序進行比較,找到插入位置即將data[i]插入,原來位置上的元素向後順序移動。
折半插入排序的基本思想:設元素序列data[0],data[1],……data[n-1]。其中data[0],data[1],……data[i-1]是已經排好序的元素。在插入data[i]時,利用折半搜索法尋找data[i]的插入位置。
因爲插入排序每次循環比較可能提前退出,所以比選擇排序在性能上更優,特別是對於一些近乎有序的數據,插入排序的性能更優,插入排序對小數據量排序性能更好。
以下代碼爲直接插入排序的示例:
template<typename T>
void insertionSort(T arr[], int n)
{
for(int i = 1; i < n; i++)
{
T tmp = arr[i];
int j;
for(j = i; j > 0 && arr[j - 1] > tmp; j --)
arr[j] = arr[j - 1];
arr[j] = tmp;
}
}
冒泡排序
冒泡排序是進行兩兩比較,通過遍歷一遍所有的數據把最大的元素放到最後,然後繼續兩兩比較剩餘的數據,依次類推,直到所有的數據都有序。冒泡排序與插入排序類似,對於幾乎有序的數據,性能會更高。代碼如下:
template<typename T>
void bubbleSort(T arr[], int n)
{
int newn;
do
{
newn = 0;
for(int i = 1; i < n; i++)
if(arr[i - 1] > arr[i])
{
swap(arr[i - 1], arr[i]);
//記錄最後一次交換的位置,在此之後的元素在下一輪比較中均不考慮
newn = i;
}
n = newn;
}while(newn > 0);
}
希爾排序
希爾排序的基本思想:
(1)希爾排序(shell sort)這個排序方法又稱爲縮小增量排序,是1959年D·L·Shell提出來的。該方法的基本思想是:設待排序元素序列有n個元素,首先取一個整數increment(小於n)作爲間隔將全部元素分爲increment個子序列,所有距離爲increment的元素放在同一個子序列中,在每一個子序列中分別實行直接插入排序。然後縮小間隔increment,重複上述子序列劃分和排序工作。直到最後取increment=1,將所有元素放在同一個子序列中排序爲止。
(2)由於開始時,increment的取值較大,每個子序列中的元素較少,排序速度較快,到排序後期increment取值逐漸變小,子序列中元素個數逐漸增多,但由於前面工作的基礎,大多數元素已經基本有序,所以排序速度仍然很快。
希爾排序的複雜度和增量序列是有關的
{1,2,4,8,...}這種序列並不是很好的增量序列,使用這個增量序列的時間複雜度(最壞情形)是O(n^2)
Hibbard提出了另一個增量序列{1,3,7,...,2^k-1},這種序列的時間複雜度(最壞情形)爲O(n^1.5)
Sedgewick提出了幾種增量序列,其最壞情形運行時間爲O(n^1.3),其中最好的一個序列是{1,5,19,41,109,...}
示例代碼如下:
template<typename T>
void InsertSort(T arr[], int h, int i)
{
T tmp = arr[i];
int j;
for(j = i; j >= h && arr[j - h] > tmp; j -= h)
arr[j] = arr[j - h];
arr[j] = tmp;
}
template<typename T>
void shellSort(T arr[], int n)
{
int h = 1;
// 計算 increment sequence: 1, 4, 13, 40, 121, 364, 1093...
while(h < n/3)
h = 3 * h + 1;
while(h >= 1)
{
//arr[h], arr[h+1], arr[h+2]....開始排序
for(int i = h; i < n; i++)
{
//對arr[i], arr[i-h],...進行插入排序
InsertSort(arr, h, i);
}
h /= 3;
}
}