数据结构(归并排序)

归并排序

归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。归并排序是一种稳定的排序方法。

时间复杂度:O(n log n)

空间复杂度:O(n)

稳定性:稳定

排序过程如图所示:

在这里插入图片描述
从图中我们不难看出
第一次是一个数字为一组进行相邻两组比较,使其组内先有顺序(如果最后由剩余,则单独为一组)
第二次是两个数字为一组进行相邻两组比较,使其组内先有顺序(如果最后由剩余,则单独为一组)
第三次是四个数字为一组进行相邻两组比较,使其组内先有顺序(如果最后由剩余,则单独为一组)
第四次是八个数字为一组进行相邻两组比较,使其组内先有顺序(如果最后由剩余,则单独为一组)


我们不难看出,每一次比较时,每一组比较的数字的个数是2倍的关系

那我们如何用代码实现归并排序呢

例如 31 77 46 97 66

我们定义四个变量h1,h2,e1,e2
刚开始我们让h1,h2为组的第一个元素的下标,e1,e2为组的最后一个元素的下标
我们让下标为h1和h2的元素进行比较,将小的元素放入一个临时储存的数组里,较小元素的下标进行++操作

第一次比较

例如:h1为31下标,h2为77下标,e1为31下标,e2为77下标,进行h1和h2比较,将较小的31放入一个临时储存的数组里,h1进行++操作,这时h1大于e1,所以第一组和第二组数字已经比较完成,可以直接将h2数字继续存入临时储存的数组里,然后令h1 = e2+1;e1=h1+组的数字个数-1;h2=e1+1;e2=h2+组的数字个数-1;(这里注意不能让下标越界)继续进行如上比较
第一次比较结果为:31 77 46 97 66

第二次比较

例如:h1为31下标,h2为46下标,e1为77下标,e2为97下标,进行h1和h2比较,将较小的31放入一个临时储存的数组里,h1进行++操作,这时h1不大于e1,所以继续进行h1和h2比较,将较小的46放入一个临时储存的数组里,h2进行++操作,继续进行h1和h2比较,将较小的77放入一个临时储存的数组里,第一组和第二组数字已经比较完成,可以直接将h2数字继续存入临时储存的数组里,然后令h1 = e2+1;e1=h1+组的数字个数-1;h2=e1+1;e2=h2+组的数字个数-1;(这里注意不能让下标越界)继续进行如上比较(如果最后有单独的组那就直接存入临时储存的数组里)
第二次比较结果为:31 46 77 97 66

第三次比较
如上面操作。。。
第三次比较结果为:31 46 66 77 97

参考代码

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define LENGTH 13        //待排序的数字个数

void Meger(int arr[],int len,int width)      //归并排序的一次排序
{
	int head1,head2,tail1,tail2;
	tail2 = -1;
	int count = 0;                            //brr下标
	int *brr = (int *)malloc(sizeof(int)*len);      //用来临时存储排序中的过程
	if(brr == NULL)
	{
		return ;
	}
	
	while(1)         //进行一次归并排序
	{
		head1 = tail2+1;
		tail1 = head1+width-1;
		if(tail1>len-1)
		{
			tail1 = len-1;
		}

		head2 = tail1+1;
		tail2 = head2+width-1;
		if(tail2>len-1)
		{
			tail2 = len-1;
		}
		if(head2>tail2)
		{
			break;
		}

		while( head1 <= tail1 && head2 <= tail2 )
		{
			if(arr[head1]>arr[head2])
			{
				brr[count] = arr[head2];
				count++;
				head2++;
			}
			else
			{
				brr[count] = arr[head1];
				count++;
				head1++;
			}
		}
		while(head1<=tail1)
		{
			brr[count] = arr[head1];
			count++;
			head1++;
		}
		while(head2<=tail2)
		{
			brr[count] = arr[head2];
			count++;
			head2++;
		}
	}

	while(head1<len)
	{
		brr[count] = arr[head1];
		count++;
		head1++;
	}

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

	free(brr);
}

void MegerSort(int arr[],int len)    //归并排序
{
	for(int i=1;i<len;i*=2)
	{
		Meger(arr,len,i);
	}
}

void ShowSort(int arr[],int len)     //打印
{
	for(int i=0;i<len;i++)
	{
		printf("%2d  ",arr[i]);
	}
	printf("\n");
}

int main()
{
	srand((unsigned int)time(NULL));

	int arr[LENGTH];

	for(int i=0;i<LENGTH;i++)
	{
		arr[i] = rand()%100;   //获得随机数
	}
	ShowSort(arr,LENGTH);

	MegerSort(arr,LENGTH);    //归并排序

	ShowSort(arr,LENGTH);
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值