歸併排序採用的是一種分而治之的策略。首先將待排序數組劃分爲若干有序數組,然後再兩兩合併爲有序的數組,到最後合併爲一個有序數組。
歸併排序主要看怎麼把待排序數組劃分爲有序數組和怎麼將兩個有序的數組合併爲一個有序數組。
劃分好說,我們可以一分爲二 的劃分數組,直到劃分的子數組只有一個元素爲止,只有一個元素時,它自然是有序的。
劃分和歸併我們可以用下面的圖簡單演示一下:
關於歸併我們演示一下{5,9}和{0,1,2}的合併過程:
假設a【2】={5,9},b【3】={0,1,2},還要一個臨時數組存放合併後的數組,假設爲c【5】
(1):比較a【0】=5 >b【0】=0;所以c【0】=b【0】=0;
(2):比較a【0】=5>b【1】=1;所以c【1】=b【1】=1;
(3):比較a【0】=5>b【2】=2;所以c【2】 =b【2】=2;
(4):此時b【】中的數組元素已經全部拷貝到臨時數組c【】中,
(5):但是,a【】中還有數組元素,此時,將a【】中的元素全部拷貝到c【】就可以了
(6):合併結束
下面是一段測試代碼:
1 #include<stdio.h>
2 #include<stdlib.h>
3 void merge(int A[],int begin,int mid,int end);//合併函數
4 void mergesort(int A[],int begin,int end);//歸併排序函數
5 void PRINT(int A[],int n);//數組大於函數
6
7 int main()
8 {
9 int a[5] = {9,3,2,0,1};
10
11 PRINT(a,5);
12 mergesort(a,0,5);
13 PRINT(a,5);
14
15 return 0;
16 }
17
18 void PRINT(int A[],int n)//數組大於函數
19 {
20 int i;
21 for(i=0;i<n;i++)
22 {
23 printf("%d--",A[i]);
24
25 }
26
27 printf("\n");
28 }
29
30 void merge(int A[],int begin,int mid,int end)//合併函數實現
31 {
32 int i = begin;//數組左端有序起始
33 int j= mid+1;//數組右端有序起始
34 int k = begin;//臨時數組下標起始
35
36 int *T = (int *)malloc((end - begin+1)*sizeof(int)); //申請臨時數組空間
37 while(i<=mid && j<=end)//只要左半部分和右半部分還有元素就循環
38 {
39 if(A[i]<A[j])//如果左端元素小於右端元素
40 T[k++] = A[i++];//把左端元素放入臨時數組
41 if(A[i]>A[j])//如果左端元素大於右端元素
42 T[k++] = A[j++];//右端元素放入臨時數組
43
44 }
45
46 while(i<=mid)//如果左端還有元素
47 T[k++] = A[i++];//拷貝到臨時數組
48 while(j<= end)//如果右端還有元素
49 T[k++] = A[j++];//拷貝到臨時數組
50
51 for(i=begin,k=begin;k<end-begin+1;i++,k++)
52 {
53 A[i]=T[k];//把臨時數組元素拷貝回原數組
54 }
55
56 free(T);//釋放申請的臨時空間
57 }
58
59
60 void mergesort(int A[],int begin,int end)
61 {
62
63 if(begin < end)//只要數組中元素超過一個
64 {
65 int mid = (begin+end)/2;//從中間開始劃分
66 mergesort(A,begin,mid);//左端有序
67 mergesort(A,mid+1,end);//右端有序
68
69 merge(A,begin,mid,end);//歸併
70 }
71 }