数据结构——归并排序

由于准备复习考研,趁闲暇时练练算法,偶然看到一篇归并排序的文章,提起了兴趣,于是捣腾一番,查阅了一些资料以及几位大神的博客,做以下记录。


参考资料:


白话经典算法系列之五 归并排序的实现

http://blog.csdn.net/morewindows/article/details/6678165

《大话数据结构》第9章 排序 9.8 归并排序(上)

http://www.cnblogs.com/cj723/archive/2011/04/25/2026751.html

《大话数据结构》第9章 排序 9.8 归并排序(下)

http://www.cnblogs.com/cj723/archive/2011/04/26/2026886.html



1、算法思想:

[数据结构]中要合并两个有序线性表时,每次取出头部较小的一个加入合并的表后面,再读其下一个,最后剩下的那个线性表中的所有元素全部加速合并表后面。


2、利用这种思想对数据排序

:利用递归的思想,将一个数组、链表一直均等分割下去,直到每个组只剩下一个为止;

:将之前分割后的数组两两之间合并,结果再两两合并....一直合并下去,直到只剩下一个数组。



3、源代码之递归实现

#include <stdio.h>
#include "list_sort.h"

//merge a segment of an array, minimum at the first
void merge1( int *arr, int first, int mid, int last, char *temp )
{
	int i = first;
	int j = mid + 1;
	int k = 0;


	while ( i <= mid && j <= last )
	{
		if ( arr[i] < arr[j])
			temp[k++] = arr[i++];
		else
			temp[k++] = arr[j++];
	}

	while ( i <= mid )
		temp[k++] = arr[i++];

	while ( j <= last )
		temp[k++] = arr[j++];

	for ( k = first; k <= last; k++ )
		arr[k] = temp[k - first];
}

//use temp to save memory
void mergeSort1( int *arr, int first, int last, char *temp )
{
	if ( first < last )
	{
		int mid = (first + last) / 2;
		mergeSort1 ( arr, first, mid, temp );
		mergeSort1 ( arr, mid + 1, last, temp );
		merge1 ( arr, first, mid, last, temp );
	}
}


void merge_Array_Sort1(int *arr, int len)
{
	char temp[len + 1];

	mergeSort1(arr, 0, len - 1, temp);
}


4、递归实现的时间复杂度和空间复杂度分析

整个归并排序需要将数组拆分log2N次,即调用了log2N次递归函数。

每次递归都对N个数据进行了操作。所以,时间复杂度为:O(N*logN)

由于栈有log2N层,每一层总共要维护N个数据,所以空间复杂度也是:O(N*logN)


这样看来,其时间复杂度、空间复杂度并不高。

递归算法易于读懂、实现起来较为容易,但是其空间复杂度仍可进一步下降。所以我再用非递归的方法实现了归并排序。



5、非递归的归并排序


#include <stdio.h>
#include <stdlib.h>
#include "list_sort.h"

void merge2( int *arr1, int *arr2, int first, int mid, int last )
{
	int i = first;
	int j = mid + 1;
	int k = first;

	while ( i <= mid && j <= last )
	{
		if ( arr1[i] < arr1[j])
			arr2[k++] = arr1[i++];
		else
			arr2[k++] = arr1[j++];
	}

	while ( i <= mid )
		arr2[k++] = arr1[i++];

	while ( j <= last )
		arr2[k++] = arr1[j++];
}



//将arr1(长度为len),每段间隔为s,两两合并到arr2
void mergeSort2( int *arr1, int *arr2, int len, int s )
{
	int i = 0;
	int j = 0;

	int first;
	int mid;
	int last;

	//所有长度为s的分段两两合并
	int times = len / (2 * s);

	for ( i = 0; i < times; i++ )
	{
		first = 2 * i * s;
		mid = first + s - 1;
		last = first + 2 * s - 1;

		merge2( arr1, arr2, first, mid, last);
	}

	//倒数第二段长度为s,最后一段长度大于0、小于s
	int remain = len % (s * 2);
	first = 2 * times * s;

	if ( remain > s )
	{
		mid = first + s - 1;
		last = len - 1;
		merge2( arr1, arr2, first, mid, last );
	}
	else
		for( j = first; j < len; j++ )
			arr2[j] = arr1[j];

}


void merge_Array_Sort2( int *arr, int len )
{
	int i;

	int *temp = (int *)malloc(sizeof(int) * len);

	int s = 1;
	while (s < len)
	{
		mergeSort2 ( arr, temp, len, s );
		s *= 2;

		for (i = 0; i < len; i++)
		{
			arr[i] = temp[i];
		}
	}
}


易得其空间复杂度为N。









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值