1. 程式人生 > >【資料結構】八大排序之歸併排序

【資料結構】八大排序之歸併排序

一.歸併排序的基本思想

          歸併排序(MERGE-SORT)是利用歸併的思想實現的排序方法,該演算法採用經典的分治(divide-and-conquer)策略(分治法將問題分(divide)成一些小的問題然後遞迴求解,而治(conquer)的階段則將分的階段得到的各答案"修補"在一起,即分而治之)。

如下圖:

1.我們看到在分治的方法中其中重要的一步就是合併兩個有序陣列,接下來我們先看一下如何將兩個有序數組合並在一起:

思路:開闢一段輔助空間(空間大小是兩個有序陣列的大小之和)然後一次比較兩個有序陣列中的數,哪個陣列中的數比較小,就將該陣列中的數放到開闢的輔助空間中。

程式碼如下:

int add(int arr1[], int sz1, int arr2[], int sz2, int arr3[])
{
	int i = 0;
	int j = 0;
	int n = 0;
	while (i < sz1 && j < sz2)
	{
		if (arr1[i] < arr2[j])
		{
			arr3[n++] = arr1[i++];
\
		}
		else
		{
			arr3[n++] = arr2[j++];
		}
	}
		while (i < sz1 )
		{
			arr3[n++] = arr1[i++];
		}
		while (j < sz2)
		{
			arr3[n++] = arr1[j++];
		}
	
}

              可以看出合併兩個陣列的效率是非常高的,為O(n)

2.解決了合併的問題,接下來我們只要將陣列中分為兩個有序陣列(A陣列,B陣列),那麼一切都會解決,這裡我們用遞迴的方法,將原陣列從中間分為兩個陣列,然後將分開的兩個數進行排序。

排序的思路:

可以將A,B組各自再分成二組。依次類推,當分出來的小組只有一個數據時,可以認為這個小組組內已經達到了有序,然後再合併相鄰的二個小組就可以了。這樣通過先遞迴的分解數列,再合併數列就完成了歸併排序。

程式碼如下:

void mergesort(int arr[], int left, int right, int arr1[])
{
	int mid = (left + right) >> 1;
	if (left < right)
	{
		//左邊有序
		mergesort(arr, left, mid, arr1);
		//右邊有序
		mergesort(arr, mid + 1, right, arr1);
		//合併
		mergearray(arr, left, right, mid, arr1);
	}


}


//合併兩個有序陣列
void mergearray(int arr[], int left, int mid, int right, int arr1[])
{
	int first = left;
	int last = right;
	int first1 = mid + 1;
	int i = 0;
	while (first < mid && first1 < right)
	{
		if (arr[first] < arr[first1])
			arr1[i++] = arr[first++];
		else
			arr1[i++] = arr1[first1++];
	}
	while (first1 < right)
		arr1[i++] = arr[first1++];
	while (first < mid)
		arr1[i++] = arr[first++];

	for (int i = 0; i < right; i++)
		arr[i] = arr1[i];

}

//將陣列分為兩個有序陣列
void MergeSort(int arr[], int sz)
{
	int* arr1 = (int)malloc(sizeof(int)*sz);
	if (arr == NULL)
		return NULL;
	mergesort(arr, 0, sz - 1, arr1);
	free(arr1);
}

歸併排序的效率是比較高的,設數列長為N,將數列分開成小數列一共要logN步,每步都是一個合併有序數列的過程,時間複雜度可以記為O(N),故一共為O(N*logN)。因為歸併排序每次都是在相鄰的資料中進行操作,所以歸併排序在O(N*logN)的幾種排序方法(快速排序,歸併排序,希爾排序,堆排序)也是效率比較高的。 

總結:

歸併排序是穩定排序,它也是一種十分高效的排序,能利用完全二叉樹特性的排序一般效能都不會太差。java中Arrays.sort()採用了一種名為TimSort的排序演算法,就是歸併排序的優化版本。從上文的圖中可看出,每次合併操作的平均時間複雜度為O(n),而完全二叉樹的深度為|log2n|。總的平均時間複雜度為O(nlogn)。而且,歸併排序的最好,最壞,平均時間複雜度均為O(nlogn)。(面試會問到)

相關推薦

資料結構八大排序歸併排序

一.歸併排序的基本思想           歸併排序(MERGE-SORT)是利用歸併的思想實現的排序方法,該演算法採用經典的分治(divide-and-conquer)策略(分治法將問題分(divide)成一些小的問題然後遞迴求解,而治(conquer)的階段則將分的階段

資料結構八大排序氣泡排序

氣泡排序:(升序為例)          利用兩個for迴圈每次比較相鄰的兩個元素,如果前一個元素比後一個元素大則交換兩個數。外層的for迴圈控制排序的總趟數,內層的for迴圈控制每一趟的相鄰兩個數的比較的次數 我們很輕易的看出:       氣泡排序的時間複雜度最

資料結構八大排序快速排序(遞迴和非遞迴方法)

上一博文我們講了氣泡排序,但是由於他的時間複雜度過高為O(n*n),於是在氣泡排序的基礎上今天要說的是快速排序。 本文講述兩個內容: 1.快速排序的三種方法。 2.快速排序的優化 一.什麼是快速排序???      通過一趟排序將要排序的資料分割成獨立的兩部

C/C++資料結構八大排序

//array是待調整的堆陣列,i是待調整的陣列元素的位置,nlength是陣列的長度 //本函式功能是:根據陣列array構建大根堆 void HeapAdjust(int array[],int i,int nLength) { int nChild; int nTemp; f

資料結構與演算法C++歸併排序(續)

上一篇部落格中實現的是自上以下的歸併排序,自上而下需要先不斷將陣列進行對半拆分(遞迴實現),然後再合併排序 其實也可以自下而上實現歸併排序,這樣使用for迴圈就可以實現,省掉了遞迴的操作 首先對陣列的每一個元素進行兩兩歸併(相鄰的兩個元素合併成一個有序陣列),然後將合併好的兩個元素的有序

資料結構與演算法C++歸併排序

上兩篇部落格使用的選擇排序和插入排序的演算法複雜度都是O(n2),這在陣列元素比較多的時候和一些演算法複雜度為O(nlogn)的快速排序演算法相比,差距還是很明顯的,如下圖 當有10萬個元素的時候,快速排序演算法比普通的選擇排序演算法要快了6000倍, 本篇部落格介紹的是快速排序演算法

資料結構BST:二叉排序樹演算法

建立二叉排序樹,實現樹的插入、刪除,前、中、後序遍歷(遞迴方式)等操作。 /***************************************** Copyright (c) 2015 Jingshuang Hu @filename:dem

資料結構Java實現各類經典排序演算法——插入排序、希爾排序

一、插入排序    顧名思義,插入排序從左往右掃描陣列,每趟排序把一個元素“插入”到已排序部分陣列的合適位置中。既然是“插入”,則不必兩兩交換元素來進行排序,從邏輯上把當前元素放到合適位置,並把該位置右側部分元素往右移動一格就可以了。這樣做和氣泡排序的交換相鄰元素比,好處在於

資料結構歸併排序-python實現

【資料結構】歸併排序--python 實現時間複雜度程式碼實現執行示例 歸併排序介紹 快速排序是典型的使用分治的思想來解決問題的演算法。分治策略會將原問題劃分為n個規模較小而結構與原問題相似的子問題。遞迴地解決這些子問題,然後再合併其結果,就得到原問題的解。

資料結構歸併排序

歸併排序的基本思想是:將兩個(或以上)的有序表組成新的有序表。 更實際的意義:可以把一個長度為n的無序序列看成是n個長度為1的有序子序列,首先做兩兩歸併,得到個長度為2的子序列;再做兩兩歸併,...,如此重複,直到最後得到一個長度為n的有序序列。 例:關鍵字序列T=(21

資料結構8種排序的比較

  直接插入排序 ①所給元素越接近有序,直接插入排序的時間效率越高 ②時間複雜度: O(N^2) ③空間複雜度: O(1) ④穩定性: 穩定 希爾排序 ①希爾排序是對直接插入排序的優化  ②當gap >

資料結構希爾排序(ShellSort)

  概念: 希爾排序法,又稱縮小增量法。希爾排序法的基本思想是:先選定一個整數, 把待排序檔案中所有資料分成幾個組,所有距離為gap的資料分在同一組內,並對每一組內的資料進行排序。 然後,去重複上述分組和排序的工作。當到達gap=1時,所有資料在一組內

資料結構直接插入排序

概念:       直接插入排序是一種簡單的插入排序法,其基本思想是:把待排序的記錄按其關鍵碼值的大小逐個插入到一個已經排好序的有序序列中,直到所有的記錄插入完為止,得到一一個新的有序序列。 核心思想:     &nb

資料結構計數排序

概念: 計數排序,又稱為鴿巢原理,是對雜湊定址法的變形應用。 核心思想是: 具體程式碼如下: void CountSort(int* a, int n)//計數排序 { int max = a[0]; int min = a[0]; for (in

資料結構選擇排序

概念: 每次從待排序的陣列元素中,選出最小或最大的,存放在序列的起始位置,直到全部待排序的陣列元素排完。 核心思想: 如果有n個元素需要排序,首先從n個元素中找到最小的那個元素,並與第0個位置上的元素交換,最大的那個元素與最後一個位置上的數交換(說明一點,如果沒有比第

資料結構排序選擇排序(直接選擇排序、堆排序)

【資料結構】【排序】選擇排序 ①簡單選擇排序 每次從序列中找出最大/最小元素,插入已排列部分的最後。 過程: 1、設一個變數min,先放在第一個元素的位置,設i,j,i=0,j=i+1。 2、在未排序陣列中找到最小的賦給min,與i比較,開始交換 3、i++  j+

資料結構順序表應用1:多餘元素刪除移位演算法

Problem Description 一個長度不超過10000資料的順序表,可能存在著一些值相同的“多餘”資料元素(型別為整型),編寫一個程式將“多餘”的資料元素從順序表中刪除,使該表由一個“非純表

資料結構十一種排序演算法C++實現

   練習了十一種排序演算法的C++實現:以下依次為,冒泡、選擇、希爾、插入、二路歸併、快排、堆排序、計數排序、基數排序、桶排序,可建立sort.h和main.cpp將程式碼放入即可執行。如有錯誤,請指出更正,謝謝交流。 // sort.h # include <

資料結構直接插入排序、詳細解釋希爾排序、直接選擇排序、選擇排序

一、直接插入排序 將一個數組進行直接插入排序,每次取陣列中一個數A儲存起來,和此數下標之前已經排好的陣列進行比較(第一次因為前面沒有數,直接取陣列第二個數),假設需要升序數列,如果A數小於要比較的數,就繼續往陣列中更小下標的數比較(在這個過程中因為A數已經儲存起

資料結構排序比較

排序 時間複雜度 穩定程度 (基本有序)時間複雜度 插入 直接插入 O(n^2) 穩定 O(n) 交換