排序(二):歸併排序

目錄

1.什麼是歸併排序?

2. 和選擇排序,冒泡排序等的暴力排序的區別在哪裏,爲什麼快?

3.  代碼實現歸併排序


瞭解其他常用算法點這裏 >> https://blog.csdn.net/GD_ONE/article/details/104061907


歸併排序是分治法思想的實例,學習完歸併排序後會更加理解分治法思想和遞歸思想。

  1. 什麼是歸併排序?
  2. 和選擇排序,冒泡排序的區別在哪裏,爲什麼它要比以上兩種排序快呢?
  3. 我們要怎麼實現歸併排序?

本文將主要解決以上三個問題。

1.什麼是歸併排序?

歸併排序的主要思想是:

    1). 歸0    

      將無序的數列分爲兩個部分,對於每個部分,在繼續劃分爲更小的兩部分,直到每個部分都有序,即分解爲單個數據,因爲僅有一個數一定是有序的。

    2). 合併

      把每次分開的兩部分再合併到一起。合併是歸併排序的核心。

2. 和選擇排序,冒泡排序等的暴力排序的區別在哪裏,爲什麼快?

    選擇排序和冒泡排序直接對原數列進行遍歷比較,要比較n+(n-1)+(n-2)...+1次,時間複雜度爲o(n^2)

    歸併排序採用了分治法思想,將待排序的數列分解爲兩個更小的數列,分解數列的時間複雜度爲o(log2n),每一次分解都需要將兩個有序的數列合併在一起,合併兩個有序數列的時間複雜度是o(n)所以總的時間複雜度是 o(nlog2n)。

3.  代碼實現歸併排序

先看下圖, 圖來自https://www.cnblogs.com/onepixel/p/7674659.html

動態圖

 
 

   首先解決分的問題,需要將數列分爲兩個部分, 在將每個部分再次分爲兩個部分,直到不可再分。

   我們可以使用遞歸的方式來實現歸併排序,其實分治法的思想幾乎就是遞歸的過程。

對於每一個序列,每次都按左右兩部分劃分,所以 int  mid = l+r>>1;

然後對 (l, mid) 和 (mid + 1, r) 兩部分再次遞歸劃分。當l == r  時不再繼續劃分。

( 另: l+r >>1 是位運算, 相當於 (l+r)/ 2

代碼:   

int mergesort(int a[], int l, int r){
    if(l==r) return;
    int mid = l+r>>1;
    mergesort(a, l, mid);
    mergesort(a, mid+1, r);
}

  分完之後就剩下合併了

  上面說到  將兩個有序的序列合併爲一個, 那麼怎麼合併呢, 首先我們當然需要一個額外的數組去存儲這個合併後的序列

  然後比較將兩個有序的序列的每一個數據,按照大小關係將數據存入額外數組。

  如 1 3 5  和 2 4 6

  先比較1 2       1 < 2   將1存入, 然後比較2  3   2 < 3 將2存入 以此類推。

   完整代碼:

void mergesort(int a[], int l, int r){
	if(l>=r) return;
	int mid = l+r>>1;
	mergesort(a, l, mid);
	mergesort(a, mid+1, r);
	int i,j,k = l;
	for(i = l, j = mid + 1; i <= mid&&j <= r;){
		if(a[i] > a[j]){
			b[k++] = a[j];
			j++;
		}
		else b[k++] = a[i], i++;
	} 
	while(i <= mid) b[k++] = a[i++];
	while(j <= r) b[k++] = a[j++]; 
	for(int ii = l; ii <= r; ii++){
		a[ii] = b[ii];
	}
}

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章