排序小結之插入排序及其升級版

1、直接插入排序

比較次數最好n-1,最壞n(n-1)/2,平均比較複雜度爲O(n^2),平均移動複雜度也爲O(n^2),穩定的排序方法,在大部分元素有序的情況下,表現優良。不適合數據量較大的排序,小於千的數量級,是不錯選擇(文末有測試數據)。STL的sort算法和stdlib的qsort算法中,都將插入排序作爲快速排序的補充,用於少量元素的排序(通常爲8個或以下)

void insert_sort(int a[], int len)  
{  
    int i, j, temp;  
    for(i = 1; i < len; i++)  
    {  
        temp = a[i];  
        for( j = i -1; j >= 0 && a[j] >= temp; a[j + 1] = a[j], j--);  
        a[j + 1] = temp;  
    }  
} 

可在上述程序中去掉地7行中a[j] >= temp表達式中的等號,優化相等情況的性能


2.二分插入排序

也是穩定的排序方法,和直接插入比較,減少了比較次數,數據規模大時,比直接插入稍微好些,但改觀不大,平均移動複雜度也爲O(n^2)

int binary_search(int elm, int start_pos, int end_pos)
{
	if (start_pos == end_pos)
		return start_pos; 
	else
	{
		int tmp_pos = (start_pos + end_pos) / 2;
		if (tmp_pos == start_pos)
			return start_pos;
		if (elm > a[tmp_pos])
			binary_search(elm, tmp_pos, end_pos);
		else if (elm < a[tmp_pos])
			binary_search(elm, start_pos, tmp_pos);
		else
			return tmp_pos;
	}
}

void isort_binary(int a[], int len)
{
	int i, j, temp, pos;
	for (i = 1; i < len ; i++)
	{
		temp = a[i];
		pos = binary_search(temp, 0, i - 1);
		for (j = i - 1; j > pos; a[j + 1] = a[j], j--);
		a[pos+1] = temp;
	}
}


3. 希爾排序 wiki

是插入排序的一種更高效的改進版本,非穩定排序算法,把直接插入每次移動的一次改爲一定的步長,並按照一定規律遞減,最終爲1.

舉個例子,以步長20開始,折半遞減

void shell_sort(int a[], int len)//#define INITSTEP 20
{
	int step, i, j, temp;
	for (step = INITSTEP; step >= 1; step /= 2)
	{
		for (i = 1; i < len; i++)
		{
			temp = a[i];
			for (j = i - step; j >= 0 && a[j] > temp; a[j + step] = a[j], j -= step);
			a[j + step] = temp;
		}
	}
}
希爾排序的時間複雜度與增量序列的選取有關,比較在希爾排序中是最主要的操作,而不是交換
好的增量序列的共同特徵:
① 最後一個增量必須爲1;

② 應該儘量避免序列中的值(尤其是相鄰的值)互爲倍數的情況。

參考一下維基百科裏的各種步長效率:


已知的最好步長串行是由Sedgewick提出的 (1, 5, 19, 41, 109,...),該串行的項來自 9*4^i-9*2^i+1 和 4^i-3*2^i+1 這兩個算式
總的說來,它比O(N^2)複雜度的算法快得多,並且容易實現,此外,希爾算法在最壞的情況下和平均情況下執行效率相差不是很多


博主純手工肉測了一組數據,小做參考

測試程序和數據打包到這裏:http://download.csdn.net/detail/simon_uestc/6858561


可以看出希爾的效率着實喜人,再馬克一個測試截圖以做紀念



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章