排序-归并排序(递归,非递归)(C语言)

归并排序是一种稳定的排序算法,基于分治思想,通过递归或非递归方式将序列分成两半,分别排序后再合并。递归实现的空间复杂度为O(n+logn),非递归为O(n)。文章提供了两种实现方式的详细代码,并分析了性能。
摘要由CSDN通过智能技术生成

归并排序

选自菜鸟教程
图片选自菜鸟教程
在这里插入图片描述
图片选自
小天狼星_布莱克

结构定义

#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 100  //排序数组个数最大值

typedef struct {
	int a[MAXSIZE + 1];   //a[0]用作哨兵或临时变量
	int length;           //顺序表长度
}SqList;

思路

原理:假设初始序列有 n 个记录,则可以看成是 n 个有序的子序列,每个子序列长度为 1 ,然后两两归并,得到 [n / 2] ([x]表示不小于 x 的最小整数)个长度为 2 或 1 的有序序列;再两两归并,…… ,重复,直至得到一个长度为 n 的有序序列,这种排序方法称为 2 路归并排序

性能分析

稳定排序
所有记录都要扫描一遍,需进行 logn(都默认log2n) 次(完全二叉树深度)
空间复杂度:递归:O(n + logn);非递归:O(n).
因为递归需要深度为 logn 的栈空间,所以内存大一点
时间复杂度:

归并排序最好情况最坏情况平均情况
-nlognnlognnlogn

归并排序(递归)

/* 归并排序 */
/* 封装函数,便于调用 */
void MergeSort(SqList* L)
{
	MSort(L->a, L->a, 1, L->length);
}

/* 归并排序算法 */
void MSort(int SR[], int TR1[], int s, int t)
{
	int m;
	int TR2[MAXSIZE + 1];
	if (s == t)    //如果子序列个数为 1
		TR1[s] = SR[s];
	else
	{
		m = (s + t) / 2;    //将SR[s......t]平分为SR[s...m]和SR[m + 1...t]
		MSort(SR, TR2, s, m);  //递归地将SR[s......m]归并为有序的TR2[s......m]
		MSort(SR, TR2, m + 1, t);  //递归地将SR[m + 1......t]归并为有序的TR2[m + 1......t]
		Merge(TR2, TR1, s, m, t);   //将TR2[s...m]和TR2[m + 1...t]归并为有序的TR1[s...t]
	}
}

/* 合序归并 */
void Merge(int SR[], int TR[], int i, int m, int n)
{
	int j, k;

/* 将SR[i...m]和SR[m + 1...n] 由小到大并入TR */
	for (j = m + 1, k = i; i <= m && j <= n; k++)
	{
		if (SR[i] < SR[j])
			TR[k] = SR[i++];
		else
			TR[k] = SR[j++];
	}

	if (i <= m)   //如果SR[m + 1...n]已经全部填入到TR,但是SR[i...m]还没有全部填入到TR
	{
		for (int l = 0; l <= m - i; l++)
			TR[k + l] = SR[i + l];      //将剩余的SR[i...m]填入到TR
	}
	else         //如果SR[i...m]已经全部填入到TR,但是SR[m + 1...n]还没有全部填入到TR
		for (int l = 0; l <= n - j; l++)
			TR[k + l] = SR[j + l];      //将剩余的SR[j...n]填入到TR
}

对于Merge()函数中的该代码

/* 将SR[i...m]和SR[m + 1...n] 由小到大并入TR */
	for (j = m + 1, k = i; i <= m && j <= n; k++)
	{
		if (SR[i] < SR[j])
			TR[k] = SR[i++];
		else
			TR[k] = SR[j++];
	}

即 将子序列 SR[i…m],SR[m + 1…n] 由小到大并入TR,TR[i…n]有序
在这里插入图片描述

归并排序(非递归)

因为递归占内存,所以我们可以用迭代替换递归

/* 归并排序(非递归)*/
void MergeSort2(SqList* L)
{
	int* TR = (int*)malloc(L->length * sizeof(int));
	int k = 1;
	while (k < L->length)
	{
		MergePass(L->a, TR, k, L->length);  //将子序列两两归并入TR
		k *= 2;         //子序列长度加倍
		MergePass(TR, L->a, k, L->length);  //将已经两两归并的有序序列再次归并入L->a
		k *= 2;         //子序列长度加倍
	}
}

/* 合序归并(非递归) */
/*  s 代表子序列之间相差的个数  ,即 1, 2, 4, 8...... */
void MergePass(int SR[], int TR[], int s, int n)
{
	int i = 1;

    /* s 代表子序列之间相差的个数 */
	while (i <= n - (2 * s) + 1)  //两两归并
	{
		Merge(SR, TR, i, i + s - 1, i + (2 * s) - 1);
		i = i + 2 * s;
	}

	/* 处理最后的尾数 */
	if (i < n - s + 1)       //归并最后两个序列
		Merge(SR, TR, i, i + s - 1, n);
	else    
//如果只剩下单个子序列,将它直接加入到TR中(不管有序性).
//例:1,2,3,4,5. s = 1.    1与2归并,3与4归并,5归并不了,将5直接加入到TR中
		for (int j = i; j <= n; j++)
			TR[j] = SR[j];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mirror_zz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值