算法导论 归并排序解决逆序数

算法导论上对归并排序的算法描述如下

基本思想是将序列分成两部分 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;
}



posted @ 2011-07-06 01:24  foreverlearn  阅读(186)  评论(0编辑  收藏  举报