归并排序

本文介绍了归并排序的基本原理及其实现过程,并结合插入排序进行了优化。通过分治策略将数组细分,利用merge函数合并有序数组,最终实现高效排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

void merge (int* a, int n, int temp, int m);

void divideSort (int *a, int n, int m) 
{
	if (n < m)
	{
		int temp = (n + m) / 2;
		divideSort (a, n, temp);
		divideSort (a, temp + 1, m);  //分解 解决 分解到叶子节点的时候已经解决了
		merge (a, n, temp, m);        //合并
	}
}

void merge (int *a, int n, int temp, int m)
{
	int i, j, nl, ml;
	int *b, *c;
	nl = temp - n + 1;
	ml = m - temp;
	
	if ((b = (int *) malloc (sizeof (int) * nl)) == NULL)
	     exit (0);

        if ((c = (int *) malloc (sizeof (int) * m1)) == NULL)
        {
             free (b);
             exit (0);
        }

        for (i = 0; i != nl; i++)
		b[i] = *(a + n + i);

	for (i = 0; i != ml; i++)
		c[i] = *(a + temp + i + 1);

	int x = 0, y = 0;
	for (i = n; i <= m; i++)
	{
		if (b[x] > c[y])
		{
			*(a + i) = c[y++];
			if (y > ml)
				break;
		}
		else
		{
			*(a + i) = b[x++];
			if (x > nl)
				break;
		}
	}
	
	int len = (x > nl) ? ml - y : nl - x;

	if (x > nl)
		for (j = 0; j < len; j++)
			*(a + i++) = c[y++];
	if (y > ml)
		for (j = 0; j < len; j++)
			*(a + i++) = b[x++];
        free (b);
        free (c);
 }


归并排序有2个核心思想:

1.已经排好序的2个数组,他们合并成一个有序的数组用的时间复杂度时n(上面的merge)

2.通过分治的思想把原来的一个数组细分到叶子节点,然后回归


在temp  = (n + m) / 2 可以可以看出它是一个2叉树,通过一步步的递归最后到达叶子节点,然后调用merge函数进行归并

递归一个2叉树需要logn + 1层,每一层的代价都是cn 那么 时间复杂度就是nlogn 了

在数量小的时候

1.分解:将N个数分成各含 n / 2个数的子序列

2.解决:用归并算法对2个子序列进行排序

3.合并:合并2个已经排序的子序列的到排序结果



虽然归并排序的时间复杂度要比插入排序小, 但是对于在数目很小的时候,插入排序的速度还是要快的(二次函数与一次函数的交点)

所以可以通过将归并的最小子序列长度设为k ,而在k个数的排序时,插入排序要来的快,于是就可以将插入排序和归并排序结合起来


void merge (int* a, int n, int temp, int m);

void insertSort (int *a, int length)
{
	int i, j, temp;
	
	for (j = 1; j < length; j++)
	{
		temp = *(a + j);
		i = j - 1;

		while (i >= 0 && *(a + i) > temp)
		{
			*(a + i + 1) = *(a + i);
			i--;
		}
		*(a + i + 1) = temp;
	}

}

void divideSort (int *a, int n, int m, int k)
{
	if (m - n >= k)
	{
		int temp = (n + m) / 2;
		divideSort (a, n, temp, k);
		insertSort (a + n, temp - n + 1);
		divideSort (a, temp + 1, m, k);
		insertSort (a + temp + 1, m - temp);
		merge (a, n, temp, m);
	}
}

void merge (int *a, int n, int temp, int m)
{
	int i, j, nl, ml;
	int *b, *c;
	nl = temp - n + 1;
	ml = m - temp;
	
	if ((b = (int *) malloc (sizeof (int) * nl)) == NULL
     || (c = (int *) malloc (sizeof (int) * ml)) == NULL)
		exit (0);

	for (i = 0; i != nl; i++)
		b[i] = *(a + n + i);

	for (i = 0; i != ml; i++)
		c[i] = *(a + temp + i + 1);

	int x = 0, y = 0;
	for (i = n; i <= m; i++)
	{
		if (b[x] > c[y])
		{
			*(a + i) = c[y++];
			if (y > ml)
				break;
		}
		else
		{
			*(a + i) = b[x++];
			if (x > nl)
				break;
		}
	}
	
	int len = (x > nl) ? ml - y : nl - x;

	if (x > nl)
		for (j = 0; j < len; j++)
			*(a + i++) = c[y++];

	if (y > ml)
		for (j = 0; j < len; j++)
			*(a + i++) = b[x++];
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值