算法导论上对归并排序的算法描述如下
基本思想是将序列分成两部分 L R,然后合并,L R 是有序的
算法的合并过程:
Pseudocode:
MERGE(A, p, q, r )
n1 ← q − p + 1
n2 ←r − q
create arrays L[1 . . n1 + 1] and R[1 . . n2 + 1]
for i ← 1 to n1
do L[i ] ← A[p + i − 1]
for j ← 1 to n2
do R[ j ] ← A[q + j ]
L[n1 + 1]←∞
R[n2 + 1]←∞
i ← 1
j ← 1
for k ← p to r
do if L[i ] ≤ R[ j ]
then A[k] ← L[i ]
i ←i + 1
else A[k] ← R[ j ]
j ← j + 1
归并排序:
MERGE-SORT(A, p, r )
if p < r Check for base case
then q ← (p + r)/2
Divide
MERGE-SORT(A, p, q) // Conquer
MERGE-SORT(A, q + 1, r ) // Conquer
MERGE(A, p, q, r ) //combine
c 语言的实现过程 数组下标从1(算法导论上的描述数组下标均从1开始)开始,0位置为0
#include"stdio.h" #define Type int #define MAX 1000 #define false 0 #define true 1 //0--1--2--3--4--5--6--7--8--9--10--11--12--13--14--15--16--17--18--19 int a1[20] = {0, 4, 6, 9, 0, 3, 4, 8, 16,2, 4, 5, 7, 1, 2, 3, 6, 20, 31, 9 }; void merge(int a[],int p,int q,int r) { int n1 = q - p + 1; int n2 = r - q; int L[n1 + 2]; int R[n2 + 2]; L[0] = 0; R[0] = 0; int i,j,k; for(i = 1; i <= n1; i++) { L[i] = a[i+p-1]; } for(j = 1; j <= n2;j++) { R[j] = a[q+j]; } L[n1 + 1] = MAX; R[n2 + 1] = MAX; for(i = 0;i<n1+2;i++) { printf("L[%d]:%d--",i,L[i]); } for(j = 0; j < n2+2;j++) { printf("R[%d]:%d--",j,R[j]); } printf("\n"); i = 1; j = 1; for(k = p; k <= r;k++) { if(L[i] <= R[j]) { a[k] = L[i]; i++; } else { a[k] = R[j]; j++; } printf("a[%d]:%d\n",k,a[k]); } } int merge_sort(int *a,int p,int r) { int q; if(p < r) { q = (p+r)/2; merge_sort(a,p,q); merge_sort(a,q+1,r); merge(a,p,q,r); } else return 0; } void main() { int i; printf("\n"); for(i = 0; i < 19; i++)printf("%d:%d,",i,a1[i]); printf("\n"); merge(a1,9,12,16); for(i = 0; i < 19; i++)printf("%d:%d,",i,a1[i]); }
归并排序的应用: 计算逆序数int a2[6] = {0,5,3,2,1,7}; int merge_inversions(int a[],int p,int q,int r) { int n1 = q - p + 1; int n2 = r - q; int inversions,counted; int L[n1 + 2]; int R[n2 + 2]; L[0] = 0; R[0] = 0; int i,j,k; for(i = 1; i <= n1; i++) { L[i] = a[i+p-1]; } for(j = 1; j <= n2;j++) { R[j] = a[q+j]; } L[n1 + 1] = MAX; R[n2 + 1] = MAX; i = 1; j = 1; inversions = 0; counted = false; for(k = p; k <= r;k++) { if(counted == false && R[j] < L[i]) { inversions = inversions + n1 - i + 1; counted = true; } if(L[i] <= R[j]) { a[k] = L[i]; i++; } else { a[k] = R[j]; j++; counted = false; } //printf("a[%d]:%d\n",k,a[k]); } return inversions; }
计算逆序数的个数
int count_inversions(int *a,int p,int r) { int inversions = 0; int q; if(p < r) { q = (p+r)/2; inversions = inversions + count_inversions(a,p,q); inversions = inversions + count_inversions(a,q+1,r); inversions = inversions + merge_inversions(a,p,q,r); } return inversions; } void main() { int m = count_inversions(a2,1,5); printf("inversions:%d",m); }
归并排序的另一种写法,用一个temp数组存储归并的结果,最后将temp里的值赋给a数组
#include <iostream> using namespace std; void merge(int a[],int left,int mid,int right,int temp[]) { int l_n = left; int l_end = mid; int r_n = mid+1; int r_end = right; int k = 0; while (l_n <= l_end && r_n <= r_end) { if (a[l_n] <= a[r_n]) { temp[k++] = a[l_n++]; } else { temp[k++] = a[r_n++]; } } while(l_n <= l_end)temp[k++] = a[l_n++]; while(r_n <= r_end)temp[k++] = a[r_n++]; for (int i = 0; i < k; i++) { a[left+i] = temp[i]; cout<<"["<<left+i<<"]:"<<a[left+i]; } cout<<endl; } void mergesort(int a[],int l,int r) { if(l < r){ int mid = (l + r)/2; mergesort(a,l,mid); mergesort(a,mid+1,r); int *temp = new int[r-l+1]; merge(a,l,mid,r,temp); } else return; } int a1[20] = {0, 4, 10, 9, 32, 3, 14, 8, 16,2, 19, 5, 7, 1, 37, 17, 6, 20, 31, 9 }; int main() { mergesort(a1,0,19); for (int i = 0; i < 20; i++) { cout<<"-"<<a1[i]; } system("pause"); return 0; }