1. 程式人生 > >希爾排序和歸併排序

希爾排序和歸併排序

1.首先說一下為什麼要搞這些東西。當然是資料結構考試啦,再來複習一下資料結構以及一些常用的演算法,平時都是用的

是sort真的自己敲了一下發現還是不容易一次敲對的。

2.首先是希爾排序,ShellSort,沒錯這個排序方法就是希爾發明的,作為第一個打破排序時間複雜度O(n^2)的方法。首先我們需要知道什麼是交換排序,其實交換排序就是很簡單的一個思想,假設第一個元素已經是OK的,那麼後邊的元素一次找到自己的位置,這個排序方法是很暴力的。Shell看到這個十分暴力的方法之後,找到了一種優化的方法,但是這種優化也讓這種基於插入排序的方法失去了插入排序的一些特性。所以說任何事情都是要付出代價的。

3.希爾排序的原理:希爾排序又叫做縮小增量排序,這個增量的引入使得排序的速度加快。我們看一組資料。

這組資料的長度為8,我們首先選取8/2=4的長度為間隔,然後怎麼做呢?其實很簡單,我們把下標相差4的元素作比較,也就是1和5,3和6,7和4,9和8.假設我們現在正在按照從小到大排序,那麼如果前邊的比後邊的小就交換,否則不交換,這樣我們逐漸的縮小間隔,一種類似於夾逼的思想就會把間隔縮的越來越小,這樣就完成了排序。那麼分析時間複雜度是nlogn的。這比n^2要好很多,但是由於多次插入,導致希爾排序不再是穩定的排序。下邊給出實現的程式碼:

void ShellSort(int a[], int n)
{
	int j, gap = n / 2, i, x;
	for (gap; gap > 0; gap /= 2)//列舉間隔
	{
		for (i = gap; i < n; i++)//列舉每一段子序列
		{
			x=a[i];
			for (j = i - gap; j >= 0&&x < a[j]; j -= gap)
			{
				a[j + gap] = a[j];
			}
			a[j + gap] = x;
		}
	}
}

希爾排序間隔的選取是很重要的,一般都是一種基於二分的思想,但是很多情況表明二分不是最好的方法,有的是基與gap=gap/3+1來做的,還有研究表明,使用素數效率更高。當然,原理都是一樣的。

3.歸併排序原理。歸併排序其實有一種快速排序的思想,二者都是基與分而治之的思想來做的。但是,也有很大的區別。快排是出了名的不穩定排序,但是歸併排序是穩定的。我們首先看一下歸併排序的思想:分而治之。

歸併的圖解

這是一種基與二叉樹的思想,首先把序列分散到葉子結點,然後在回溯的時候合併整個序列,這樣就可以完成排序。這當然是一種基於遞迴的演算法了,下面給出具體的程式碼實現。

void merge(int a[], int start, int mid, int end)
{
	int *tmp = (int *)malloc((end - start + 1) * sizeof(int));   
	int i = start;           
	int j = mid + 1;       
	int k = 0;               

	while (i <= mid && j <= end)
	{
		if (a[i] <= a[j])
			tmp[k++] = a[i++];
		else
			tmp[k++] = a[j++];
	}

	while (i <= mid)
		tmp[k++] = a[i++];

	while (j <= end)
		tmp[k++] = a[j++];
	for (i = 0; i < k; i++)
		a[start + i] = tmp[i];

	free(tmp);
}
void merge_sort(int a[], int start, int end)
{
	if (a == NULL || start >= end)
		return;
	int mid = (end + start) / 2;
	merge_sort(a, start, mid); 
	merge_sort(a, mid + 1, end);
	merge(a, start, mid, end);
}

好了,基本上就是這樣了。當然還有很多排序演算法,這裡就不再一一討論了。反正大多數sort是可以搞定的。感興趣的可以看一下sort的實現。