1. 程式人生 > >跟著《演算法導論》學習——插入排序與歸併排序

跟著《演算法導論》學習——插入排序與歸併排序

讀前宣告:本人所寫帖子主要為了記錄本人學習的一個過程,無他想法,由於內容比較膚淺,如有雷同,非常正常!!!

本文內容:

本文主要是參考《演算法導論》這本書,完成部分演算法編寫,可能程式設計習慣或者風格比較差,還請多多批評。

1、插入排序(Insertion Sort)

插入排序是對少量元素進行排序的有效演算法,其機理與很多人打牌時,整理手中牌時的做法差不多。開始摸牌時,我們的左手是空的,牌面朝下放在桌上,接著,一次從桌上摸起一張牌,並將它插入到左手一把牌中的正確位置上。為了找到這張牌的正確位置,要將它與手中已有的每一張牌從右到左的比較。

其程式碼如下:

void InsertionSort(int a[],int n)
{
	for(int j=1;j<n;j++)
	{
		int key = a[j];
		int i = j-1;
		while (i>=0&&a[i]>key)
		{
			a[i+1] = a[i];
			i--;
		}
		a[i+1] = key;
}
2、歸併排序(Merge sort)

歸併排序是分治法(Divide-and-Conquer)的一個應用。分治法的的策略如下:將原問題劃分為n個規模較小而結構與原問題相似的子問題;遞迴地解決這些子問題,然後再合併其結果,就得到原問題的解。分治模式在每一層遞迴都有三個步驟:

分解(Divide):將原問題分解成一系列子問題;

解決(Conquer):遞迴地求解各子問題,若子問題足夠小,則直接求解;

合併(Combine):將子問題的結果合併成原問題的解

歸併排序完全按照上述模式,直觀的操作如下:

分解:將n個元素分成各含n/2個元素的子序列;

解決:用合併排序法對兩個子序列遞迴地排序;

合併:合併兩個已排序的子序列以得到排序結果。

在對子序列排序時,其長度為1時遞迴結束,單個元素被視為已排序的。

合併排序的關鍵步驟在於合併步驟中的合併兩個已排序子序列。為做排序,引入一個輔助過程Merge,其過程是將兩個子序列經過比較,合併成一個大的排好序的陣列。

Merge子函式如下:

void Merge(int a[],int b[],int left,int middle,int right)
{
	for (int i=left;i<=right;i++)
	{
		b[i] = a[i];
	}
	int s1 = left;
	int s2 = middle+1;
	int t = left;
	while (s1<=middle&&s2<=right)
	{
		if (b[s1]<=b[s2])
		{
			a[t++] = b[s1++];
		} 
		else
		{
			a[t++] = b[s2++];
		}
	}
	if (s1==middle+1)
	{
		while (s2<=right)
		{
			a[t++] = b[s2++];
		}
	}
	if (s2==right+1)
	{
		while (s1<=middle)
		{
			a[t++] = b[s1++];
		}
	}
}

歸併排序演算法過程:
void MergeSort(int a[],int b[],int left,int right)
{
	if(left>=right) return;
	int middle = (left+right)/2;
	MergeSort(a,b,left,middle);
	MergeSort(a,b,middle+1,right);
	Merge(a,b,left,middle,right);
}