排序算法之歸併排序

#include <iostream>

using namespace std;

//歸併算法

/**
一句箴言:將待排序數據一分爲二,二分爲四,四分爲八,遞歸下去,直至每份爲1個元素,這一個元素自身必定爲有序的,而後再將分了的兩兩合併爲有序數組,最終變成一個有序數組。

方法:遞歸拆分並兩兩合併爲有序數組。其中合併時候須要將待合併的兩組數據拷貝出來,指定左待歸併數據索引i,右待歸併數據索引j, k爲原數組需從新指定值得索引

**/


void _merge(int arr[], int l, int mid, int r) {

	//歸併前判斷是否分割的兩數組已經左邊小右邊大了
	if (arr[mid+1] > arr[mid]) {
		return;
	}

	//首先須要拷貝出待歸併區間的數據 區間爲索引l到 r
	int aux[r - l + 1];
	for (int i = l ; i <= r; i++) {
		aux[i - l] = arr[i];
	}

	/**
		// 註釋的是去除掉偏移量l後的數組 求解法
		int max = r -l;
		int newMid = (max - min) / 2;
		int i = 0,j = newMid + 1;
		//遍歷原數組l到 r 這個區間,走待歸併的兩個區間裏選擇最小的去填充覆蓋
		for (int k = l; k <= r; k++) {
			//當左邊的都已經賦值完,索引已經越過中間點,則只剩下右邊的了
			if (i > newMid ) {
				arr[k] = aux[j];
				j++;
			} else if (j > max) {
				arr[k] = aux[i];
				i++;
			} else if(aux[i] < aux[j]) {
				arr[k] = aux[i];
				i++;
			} else {
				arr[k] = aux[j];
				j++;
			}
		}
		**/

	int i = l,j = mid + 1;
	//遍歷原數組l到 r 這個區間,走待歸併的兩個區間裏選擇最小的去填充覆蓋
	for (int k = l; k <= r; k++) {
		//當左邊的都已經賦值完,索引已經越過中間點,則只剩下右邊的了
		if (i > mid ) {
			arr[k] = aux[j-l];
			j++;
		} else if (j > r) {
			arr[k] = aux[i-l];
			i++;
		} else if(aux[i-l] < aux[j-l]) {
			arr[k] = aux[i-l];
			i++;
		} else {
			arr[k] = aux[j-l];
			j++;
		}
	}

}

void mergeSort(int arr[], int l, int r) {

	//遞歸則首先要找到跳出條件
	if (l >= r) {
		return ;
	}

	//一分爲二,遞歸調用本身排序
	int mid = (r + l) / 2;
	mergeSort(arr, l, mid);
	mergeSort(arr, mid+1, r);

	//歸併
	_merge(arr, l, mid, r);

}


int main() {

	int arr[10] = {10,9,8,7,6,5,4,3,2,1};

	mergeSort(arr, 0,  9);

	for(int i =0; i< 10; i++) {
		cout << arr[i] << "  ";
	}

	return 0;
}
相關文章
相關標籤/搜索