1. 程式人生 > >C++排序演算法——歸併排序

C++排序演算法——歸併排序

歸併排序C++

歸併排序從小到大排序:首先讓陣列中的每一個數單獨成為長度為1的區間, 然後兩兩一組有序合併,得到長度為2的有序區間,依次進行,直到合成整個區間。


#include <iostream>
using namespace std;

//4 歸併排序
/*
歸併排序從小到大排序:首先讓陣列中的每一個數單獨成為長度為1的區間,
然後兩兩一組有序合併,得到長度為2的有序區間,依次進行,直到合成整個區間。
*/
//4.3 核心程式碼(函式)
//1 遞迴實現
//函式宣告
void MergeSort(int array[]);
void MSort(int array[], int Result[], int start, int end);
void Merge(int array[], int Ans[], int start, int midd, int endd);   //將兩個排序序列排序   從小到大排序

//函式實現
void MergeSort(int array[])
{
	MSort(array, array, 0, 9);
}

void Merge(int array[],int Ans[], int start, int midd, int endd)   //將兩個排序序列排序   從小到大排序
{
	int i = start;     //記錄前半段的下標
	int j ;            //記錄後半段的下標
	int k;             //記錄結果Ans的下標
	for ( j = midd + 1, k = i; i <= midd && j <= endd; k++)
	{
		if (array[i] > array[j])
		{
			Ans[k] = array[j];
			j++;
		}
		else
		{
			Ans[k] = array[i];
			i++;
		}

	}

	if (i <= midd)   //
	{
		for (; i <= midd; i++,k++)
		{
			Ans[k] = array[i];
		}
	}

	if (j <= endd)   //
	{
		for (; j <= endd; j++, k++)
		{
			Ans[k] = array[j];
		}
	}
}
void MSort(int array[], int Result[], int start, int end)
{
	int Tmp[1000];
	if (start == end)
		Result[start] = array[start];
	else 
	{
		int mid = (start+end) / 2;        //中間點的位置,從中間點將陣列分成兩部分
		MSort(array, Tmp, start, mid);    //左半部分排序
		MSort(array, Tmp, mid + 1, end);   //右半部分排序
		Merge(Tmp, Result,start, mid, end);   //合併
	}
}


//2:迭代實現
void MergeSortIter(int k[], int n)
{
	int i, next, left_min, left_max, right_min, right_max;
	//動態申請一個與原來陣列一樣大小的空間用來儲存
	int *temp = (int *)malloc(n * sizeof(int));
	//逐級上升,第一次比較2個,第二次比較4個,第三次比較8個。。。  
	for (i = 1; i<n; i *= 2)
	{
		//每次都從0開始,陣列的頭元素開始  
		for (left_min = 0; left_min<n - i; left_min = right_max)
		{
			right_min = left_max = left_min + i;
			right_max = left_max + i;
			//右邊的下標最大值只能為n  
			if (right_max>n)
			{
				right_max = n;
			}
			//next是用來標誌temp陣列下標的,由於每次資料都有返回到K,  
			//故每次開始得重新置零  
			next = 0;
			//如果左邊的資料還沒達到分割線且右邊的陣列沒到達分割線,開始迴圈  
			while (left_min<left_max&&right_min<right_max)
			{
				if (k[left_min] < k[right_min])
				{
					temp[next++] = k[left_min++];
				}
				else
				{
					temp[next++] = k[right_min++];
				}
			}
			//上面迴圈結束的條件有兩個,如果是左邊的遊標尚未到達,那麼需要把  
			//陣列接回去,可能會有疑問,那如果右邊的沒到達呢,其實模擬一下就可以  
			//知道,如果右邊沒到達,那麼說明右邊的資料比較大,這時也就不用移動位置了  

			while (left_min < left_max)
			{
				//如果left_min小於left_max,說明現在左邊的資料比較大  
				//直接把它們接到陣列的min之前就行  
				k[--right_min] = k[--left_max];
			}
			while (next>0)
			{
				//把排好序的那部分陣列返回該k  
				k[--right_min] = temp[--next];
			}
		}
	}
}
//非遞迴的方法,避免了遞迴時深度為log2N的棧空間,
//空間只是用到歸併臨時申請的跟原來陣列一樣大小的空間,並且在時間效能上也有一定的提升,
//因此,使用歸併排序是,儘量考慮用非遞迴的方法。


int main(  )
{
	int array[10] = { 3,5,4,6,9,8,7,1,2,0};
	
	int len = sizeof(array) / sizeof(int);

	for (int i = 0; i < len; i++)
		cout << array[i] << " ";
	cout << endl;
	cout << "*************************"<< endl;

	
	//insertSort(array,len);  //插入排序

	MergeSort(array);      //歸併排序

	//adjust_quicksort(array,10);  //快速排序


	for (int i = 0; i < len; i++)
		cout << array[i] << " ";
	cout << endl;
	system("pause");
	return 0;
}