歸併排序

zhengbiyu發表於2024-06-23
/*
 * mergeSort.cpp(歸併排序)
 *
 *  Created on: 2012-4-20
 *      Author: jiyiqin
 *
 *  歸併排序:
 *  分治法:
	 *  分治法思想,不斷將待排序陣列劃分成兩個部分。
	 *  直到問題最小(兩個元素)。
	 *  然後將兩個部分(各自有序)歸併到一起。
 *
 *	代價:
	 *  歸併的時間複雜度為o(n),整個排序演算法:
	 *  時間複雜度:o(n log n)
	 *  空間複雜度:o(n),需要兩個額外的陣列,但是總大小至多為n
 *
 *  穩定性:
 *		穩定
 *
 */
#include <iostream>
#include <math.h>
using namespace std;

#define MAXINT 65535
class MergeSort{
public:

	/**
	 * 將a[low..m]和a[m+1..high]歸併到a[low...high]中
	 * 歸併前各自有序。
	 *
	 *	哨兵思想:
	 * 將兩個陣列歸併在一起的時候採用“哨兵”
	 * 即用無窮大放在兩個陣列各自的末尾
	 * 每次取兩個陣列中最小的放入a陣列,最先被
	 * 取完的陣列會遇到"哨兵",它總是大於另一個
	 * 沒有取完的陣列的元素,所以不需要判斷邊界條件
	 *
	 * 否則我們還要判斷,如果某個陣列提早結束,
	 * 還需要將另外一個沒有結束的陣列一次拷貝到a中
	 * 無疑增加了很多程式碼量
	 * 3,4,6,3,7,8,3,2,6,11,5
	 * */
	/**
	 * 將陣列a的low->m部分和m+1->high部分歸併到low->high
	 * 呼叫此函式之前陣列a的兩邊已經各自有序
	 * */
	void merge(int a[], int low, int m, int high){
		int size1 = m-low+2;		//low ~ m,額外申請一個存放哨兵
		int size2 = high-m+1;		//m+1 ~ high,額外申請一個存放哨兵
		int *b1 = new int[size1];
		int *b2 = new int[size2];

		//拷貝a[low~m]到b1[0~size1-2]
		for(int i=0;i<size1-1;i++)
			b1[i] = a[i+low];
		b1[i] = MAXINT;

		//拷貝a[m+1~high]到b2[0~size-2]
		for(int j=0;j<size2-1;j++)
			b2[j] = a[j+m+1];
		b2[j] = MAXINT;


		/**
		 * merge b1 and b2:
		 * if b1 shorter than b2
		 * b1[size1-1](MAX) will greater than all b2[j]
		 *
		 * So MAX is great sentinel(哨兵)
		 * */
		i = 0;
		j = 0;
		for(int k=low;k<=high;k++){
			if(b1[i] <= b2[j]){
				a[k] = b1[i++];
			}
			else{
				a[k] = b2[j++];
			}
		}
	}

	/**
	 * 對陣列a進行分治法的歸併排序
	 * */
	void mergeSort(int a[], int low, int high){
		int m;

		//歸併和氣泡排序的是<,二分查詢是<=
		if(low < high)
		{
			m=(low+high)/2;				//partition point
			mergeSort(a, low, m);			
			mergeSort(a, m+1, high);
			merge(a, low, m, high);		
		}
	}
};

int main(){
	MergeSort msort;
	int a[11] = {12,2,16,30,8,128,4,10,20,6,18};

	//sort
	msort.mergeSort(a,0,10);
	for(int i=0;i<11;i++){
		cout<<a[i]<<" ";
	}
	cout<<endl;
	return 0;
}

相關文章