算法基础:排序之归并排序

归并排序较插入排序要好很多,时间复杂度为 nlogn ,在数据量很大的情况下跟插入排序比起来,那优势就非常明显了。

归并排序的代码如下:

#include <stdio.h>
#define MAXSIZE 100
void MergeSort(int a[], int s, int e);				//递归分解过程
void Merge(int a[], int s, int m, int e);			//实际的归并函数

int main()
{
	int a[MAXSIZE];
	int n;
	printf("Enter N to represent number of digit:");
	while(1 == scanf("%d", &n))
	{
		int i;
		printf("Input %d number(s): ", n);
		for(i = 0; i < n; ++i)
			scanf("%d", &a[i]);
		MergeSort(a, 0, n - 1);
		printf("After MergeSort: ");
		for(i = 0; i < n; ++i)
			printf("%d ", a[i]);
		printf("\n\nEnter N to represent number of digit:");
	}
	return 0;
}

void MergeSort(int a[], int s, int e)				//递归分解过程
{
	if(s < e)
	{
		int m = (s + e) / 2;
		MergeSort(a, s, m);
		MergeSort(a, m + 1, e);
		Merge(a, s, m, e);
	}
}

void Merge(int a[], int s, int m, int e)			//实际的归并函数
{
	int x[MAXSIZE], y[MAXSIZE];
	int lena = m - s + 1;
	int lenb = e - m;
	x[lena] = 1 << 10;
	y[lenb] = 1 << 10;
	int i;
	for(i = 0; i < lena; ++i)
		x[i] = a[s + i];
	for(i = 0; i < lenb; ++i)
		y[i] = a[m + 1 + i];
	int p, q;
	p = q = 0;
	for(i = s; i <= e; ++i)
	{
		if(x[p] < y[q]) 
			a[i] = x[p++];
		else 
			a[i] = y[q++];
	}
}
运行效果:




将归并排序和插入排序进行比较:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAXSIZE 100000

void MergeSort(int a[], int s, int e);				//递归分解过程
void Merge(int a[], int s, int m, int e);			//实际的归并函数
void insertSortAscending(int array[], int n);		//升序插入排序

int main()
{
	int a[MAXSIZE];
	int n, i;
	clock_t start, finish;

	printf("Enter N to represent number of digit:");
	while(1 == scanf("%d", &n))
	{
		//产生n个随机数
		srand(time(NULL));
		for(i = 0; i < n; ++i)
			a[i] = rand() % 100000;

		//归并排序及耗时
		start = clock();
		MergeSort(a, 0, n - 1);
		finish = clock();
		printf("MergeSort Time used: %lfs\n", (double)(finish - start) / CLOCKS_PER_SEC);

		//插入排序及耗时
		start = clock();
		insertSortAscending(a, n);
		finish = clock();
		printf("InsertSort Time used: %lfs\n", (double)(finish - start) / CLOCKS_PER_SEC);

		printf("\nEnter N to represent number of digit:");
	}
	return 0;
}

void MergeSort(int a[], int s, int e)				//递归分解过程
{
	if(s < e)
	{
		int m = (s + e) / 2;
		MergeSort(a, s, m);
		MergeSort(a, m + 1, e);
		Merge(a, s, m, e);
	}
}

void Merge(int a[], int s, int m, int e)			//实际的归并函数
{
	int x[MAXSIZE], y[MAXSIZE];
	int lena = m - s + 1;
	int lenb = e - m;
	x[lena] = 1 << 10;
	y[lenb] = 1 << 10;
	int i;
	for(i = 0; i < lena; ++i)
		x[i] = a[s + i];
	for(i = 0; i < lenb; ++i)
		y[i] = a[m + 1 + i];
	int p, q;
	p = q = 0;
	for(i = s; i <= e; ++i)
	{
		if(x[p] < y[q]) 
			a[i] = x[p++];
		else 
			a[i] = y[q++];
	}
}

void insertSortAscending(int array[], int n)
{
	int i;
	for(i = 1; i < n; ++i)
	{
		int key = array[i];
		int j = i - 1;
		while(j >= 0 && key < array[j])
		{
			array[j+1] = array[j];
			array[j] = key;
			j--;
		}
	}
}



比较两种方法的运行效果:


可以看到在数据量为1000的时候归并反而更慢,其原因并不是算法的低效性,而是我写的代码中,每次合并都创建了两个临时数组,分配这些内存需要花较多时间。解决的方法是创建一个大小与待排序数组相同的全局数组来代替。这就不需要再每次合并的时候分配内存了。

当数据量越来越大的时候,可以看到归并排序有明显的优势。


如有错误,请批评指正,谢谢。

你可能感兴趣的:(排序,递归,归并排序,分治)