算法之旅——合并排序

时间:2021-10-11 12:52:21

合并排序是用分治策略实现对n 个元素进行排序的算法。其基本思想是,将待排序元素分成大小大致相同的两个子集合,分别对两个子集合进行排序,最终将排好序的子集合合并成所要求的排好序的集合。

其递归描述如下:

#include <iostream>
#define N 8
typedef int Type;
using namespace::std;

Type *b = new Type[N];

void MergeSort(Type a[], int left, int right);
void Merge(Type a[], Type b[], int left, int i, int right );

void MergeSort(Type a[], int left, int right)
{
	if(left < right)
	{
		int i = (left + right) / 2;
		MergeSort(a, left, i);
		MergeSort(a, i+1, right);
		Merge(a, b, left,  i, right);  //Merge to array of 'b'
	}
}

void Merge(Type a[], Type b[], int left, int i, int right )
{
	int x = left, y = i+1, k = left;
	while((x <= i) && (y <= right))
	{
		if(a[x] < a[y])  b[k++] = a[x++];
		else b[k++] = a[y++];
	}
	while(x <= i) b[k++] = a[x++];
	while(y <= right) b[k++] = a[y++];

	for(int i = left; i < k; i++)
		a[i] = b[i];
}
int main()
{
	Type a[N] = {4,8,3,7,1,5,6,2};
	MergeSort(a, 0, 7);
	for(int i = 0; i < N; i++)
		cout << a[i] << ',';
	cout << endl;

	return 1;
}


消去递归的合并算法如下:

#include <iostream>
typedef int Type;

using namespace::std;

void Merge(Type c[], Type d[], int l, int m, int r)
{
	int i = l, j = m+1, k = l;
	while((i <= m) && (j <= r))
	{
		if(c[i] <= c[j]) d[k++] = c[i++];
		else d[k++] = c[j++];
	}
	if(i > m) for(int q = j; q <= r;  q++) d[k++] = c[q];
	else for(int q = i; q <= m; q++) d[k++] = c[q];
}

void MergePass(Type x[], Type y[], int s, int n)
{
	int i = 0;
	while( i <= n - 2 * s)
	{
		Merge(x, y, i, i+s-1, i+2*s-1);
		i = i+2 * s;
	}
	if(i + s < n) Merge(x, y, i, i+s-1, n-1);
	else for(int j = i; j <= n-1; j++) y[j] = x[j];
}

void MergeSort(Type a[], int n)
{
	Type *b = new Type[n];
	int s = 1;
	int i = 0;
	while(s < n)
	{
		MergePass(a,b,s,n); //合并到数组b
		s += s;	
		MergePass(b,a,s,n); // 合并到数组a	
		s += s;
	}
}

int main()
{
	Type num[] = {8,4,7,3,1,5,6,2};
	MergeSort(num, 8);
	for(int j = 0; j < 8;  j++)
		cout << num[j];
	int i; 
	cin >> i;
	return 1;
}

自然合并排序如下:

#include <iostream>
#define N 8
typedef int Type ;
using namespace::std;

void MergeSort_Natural(Type a[], int n);
int Scan(Type a[], Type b[], int n);
void Merge(Type a[], Type b[], int left , int mid, int right);

//自然归并排序
void MergeSort_Natural(Type a[], int n)
{
	Type *b = new Type[N];

	while(1)
	{
		if(Scan(a,b,n) == 0) break;
		if(Scan(b,a,n) == 0) break;
	}
}

/* 线性扫描数列,如果存在逆序的情况就进行合并排序
   否则返回一个为零的中间值mid   
   */ 
int Scan(Type a[], Type b[], int n)
{
	int left = 0, mid = 0, right = n-1;
	for(int i = 0; i < n-1; i++)
	{
		// 判断有没有逆序的情况出现 
		if(a[i] > a[i+1]){
			// 先设置中间值,后设置右值
			if(mid == 0)  mid = i;
			else {
				right = i;
				Merge(a, b, left , mid, right);
				left = right+1;
				mid = 0;	
				right = n-1;
			}
		}		
	}
  // 当最后一个组为最后一个数的极端情况
	if((mid !=0) && (right != 0))
		Merge(a, b, left , mid, right);	
	return mid;
}

void Merge(Type a[], Type b[], int left , int mid, int right)
{
	int i = left, j = mid+1, k = left;
	while((i <= mid) && (j <= right))
	{
		if(a[i] < a[j]) b[k++] = a[i++];
		else b[k++] = a[j++];
	}
	while(i <= mid) b[k++] = a[i++];
	while(j <= right) b[k++] = a[j++];
}

int main()
{
	Type a[N] = {4,8,3,7,1,5,6,2};

	MergeSort_Natural(a, 8);

	for(int i = 0; i < N; i++)
		cout << a[i] << ',';
	cout << endl;

//	int i;
//	cin >> i;
	return 1;
}

合并排序的一个弊端就是额外需要存储器的空间配置,在实际上的实现上,会极度影响速度和高速缓存的性能!