基礎的排序算法

基本概念
穩定性:對於序列中相等的元素a , b,且a在b的前面,若排序之後,a依然在b的前面,則該排序算法是穩定的,否則算法是不穩定的。
時間複雜度:直白的說就是算法才做的次數。
空間複雜度:指執行算法所需要的輔助空間(存儲空間)。若存儲空間的大小與數據的個數無關,則空間複雜度爲O(1)。
說明
爲方便講清楚代碼,先定義一個用於排序的順序結構和一個交換函數。
注意:這裏數字的起始位置的下標設置爲1

#define MAXSIZE 10 /* 要排序數組的元素個數,可根據需要改變 */
typedef struct
{
	int r [MAXSIZE +1] /* 用於存儲排序數組,r[0]用作哨兵或臨時變量 */
	int length;
}SqList;

// 也可以使用vector替代
#include<vector> 
vector<int> r(MAXSIZE+1, 0);
viod swap(SqList *L, int i , int j)
{
	int temp = L->r[i];
	L->r[i] = L->r[j];
	L->r[j] = temp;
}

冒泡排序
冒泡算法的基本思想是:兩兩比較相鄰記錄的關鍵字,如果反序則交換,直到沒有反序的記錄爲止。時間複雜度爲O(n^2)

void BubbleSort(SqList* L)
{
	int i, j;
	flag = True;
	for(i = 1; i< L->length && flag; i++)
	{
		flag = False;
		for(j = L->length -1; j >= i; j--)
		{
			if(L->r[j] > L->r[j+1])
			{
				swap(L, j, j+1);
				flag = True;
			}
		}
	}
}

選擇排序
選擇排序就是通過n-i次關鍵字間的比較,從n-i+1個記錄中選出關鍵字最小的記錄,並和第i(1<= i <=n)個記錄交換。
時間複雜度爲O(n^2)。儘管選擇排序與冒泡排序的時間複雜度一樣,但是在性能上還是優於冒泡排序的。

void SelectSort(SqList* L)
{
	int i,j, min;
	for(i = 1;i< L->length;i++)
	{
		min = i;
		for(j = i + 1;j <= L->length;i++)
		{
			if(L->r[min] > L->r[j])
				min = j;
		}
		if(i != min)
			swap(L, i, min);
	}
}

插入排序
插入排序是將一個記錄插入到已經排好順序的有序表中,從而得到一個新的、記錄數增加1的有序表。
時間複雜度同樣爲O(n^2), 但是優於選擇排序和冒泡排序。

void InsertSort(SqList* L)
{
	int i,j;
	for(i = 2; i <= L->length; i++)
	{
		if(L->r[i] < L->r[i-1])
		{
			L->r[0] = L->r[i];  /* 設置哨兵  */
			for( j = i -1;L->r[j] > L->r[0]; j--)  /*  找出在已排序的序列中的位置  */
				L->r[j+1] = L->r[j];
			L->r[j+1] = L->r[0];
		}
	}
}

希爾排序
希爾排序是對插入排序的優化,基本思想是:將序列分割成若干個子序列,然後對這些子序列分別進行直接插入排序,當整個序列都基本有序時,注意只是基本有序時,再對全體記錄進行一次直接插入排序。
所謂基本有序就是小的關鍵字基本在前面,大的基本在後面,不大不小的在中間。

void ShellSort(SqList* L)
{
	int i, j;
	int increment = L->length;
	do
	{
		increment = increment/3 + 1;
		for(i = increment+1; i< L->length;i++)
		{
			if(L->r[i] < L->r[i- increment])
			{
				L->r[0] = L->r[i];
				for(j = i-increment; j>0 && L->r[0] < L->r[j]; j-= increment)
					L->r[j+increment] = L->r[j];
				L->r[j+increment] = L->r[0];
			}
		}
	}
	while(increment > 1);
}

堆排序
堆排序就是將待排序的序列構成一個大頂堆。此時整個序列的最大值就是堆頂的根節點。將它與堆數組的末尾元素交換,此時末尾元素就是最大值,然後將剩餘的n-1個序列重新構造成一個堆,這樣就會得到n個元素的次小值。如此反覆執行,就可以得到一個有序序列。
實現堆排序需要解決兩個問題:
1.如何由一個無序序列構建一個最大堆?
2.如果在輸出對頂元素後,調整剩餘元素成爲一新的堆?
時間複雜度O(nlogn)

/* 對順序表L 進行堆排序 */
void HeapSort(Sqort* L)
{
	int i ;
	for(i = L->length/2;i > 0 ;i++)   	/*將待排序的序列構建成一個大頂堆*/
	{
		HeapAdjust(L, i, L->length);
	}
	for(i = L->length;i>1; i--)  /* 逐步將每個最大堆的根節點與末尾元素交換,並且在調整其成爲大頂堆。 */
	{
	 	swap(L, l,i);
	 	HeapAdjust(L,1,i-1);
	 }
}


void HeapAdjust( SqList* L, int s, int m)
{
	int temp, j;
	temp = L->r[s];
	for(j = 2*s; j <= m; j*=2)
	{
		if(j < m &&L->r[j] < L->r[j+1])
			j++;
		if(temp >= L->r[j])
			break;
		L->r[s] = L->r[j];
		s = j;
	}
	L->r[s] = temp;
}

歸併排序
歸併排序的原理是:假設初始序列含有n個記錄,則可以看成是n個有序的子序列,每個子序列的長度爲1,然後兩兩歸併,得到[n/2]個長度爲1或者2 的有序子序列;再兩兩歸併,如此重複,直至得到長度爲n的有序序列爲止。
時間複雜度O(nlogn),空間複雜度爲O(n + logn)

void MergeSort(SqList* L)
{
	MSort(L->r, L->r, 1, L->length);
}

void MSort( int SR[], int TR1[], int s, int t)
{
	int m;
	int TR2[MAXSIZE + 1];
	if(s == t)
		TR1[s] = SR[s];
	else
	{
		m = (s+t) /2;  /*將SR[s .. t]平分爲SR[s..m] 和SR[m+1 .. t] */
		MSort(SR,TR2, s, m);   /* 遞歸將SR[s..m] 歸併爲有序的TR2[s..m] */
		MSort(SR, TR2, m+1, t);  /* 遞歸將SR[m+1 .. t] 歸併爲有序的TR2[m+1 .. t] */
		Merge((TR2, TR1,s, m, t); /*將TR2[s..m]和TR2[m+1 .. t]歸併到TR1[s..t] */
	}
}

void Merge(int SR[], int TR[], int i, int m, int n)
{
	int j,k,x;
	for(j = m+1, k = i; i <= m && j <=n;k++)
	{
		if(SR[i] < SR[j])
			TR[k] = SR[i++];
		else
			TR[k] = SR[j++];
	}
	if(i <= m)
	{
		for( x = 0; x<= m-i; x++)
			TR[k+x] = SR{i+x];
	}
	if(j <= n)
	{
		for(x = 0; x<=n-j;n++)
			TR[k+x] = SR[j+x];
	}
}

快速排序
快速排序的基本思想是:通過一趟排序將待排序分割成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分記錄的關鍵字小, 則可分別對這兩部分記錄繼續進行排序,已達到整個序列有序的目的。
時間複雜度O(nlogn)

void QuickSort(SqList *L)
{
	 QSort(L, 1,L->length);
}

void QSort(SqList* L, int low, int high)
{
	int pivot;
	if(low < high)
	{
		pivot = Partition(L,low,high);

		QSort(L,low,pivot-1);
		QSort(L,pivot+1,high);
	}
}

int Partition(SqList* L, int low, int high)
{
	int pivotkey;
	pivotkey = L-> r[low];
	while(low<high)
	{
		while(low < high&&L->r[high} >= pivotkey)
			high--;
		swap(L,low,high);
		while(low<high && L->r[low]<=pivotkey)
			low++;
		swap(L,low, high);
	}
	return low;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章