双调排序进阶:对任意长度的序列排序(C语言)

双调排序进阶:对任意长度的序列排序(C语言)

996.icu LICENSE

  • 双调排序回顾+进阶
  • 进阶双调排序怎么实现

阅读之前注意:

本文阅读建议用时:20min
本文阅读结构如下表:

项目下属项目测试用例数量
双调排序回顾+进阶0
进阶双调排序怎么实现1

双调排序回顾+进阶

双调排序是基于四元素排序发展起来的一种排序方法,单纯的双调排序适用于2的幂次方个元素的序列的排序。而选择排序和冒泡排序都属于三元素排序。
四元素排序的思想是这样的,比如说有(3,2,1,4)这一个序列,我们要按照从小到大(升序)的顺序来排序。
(3,2,1,4)–>(2,3)(4,1)–>(2,1)(4,3)–>(1,2)(3,4)。

以上过程可总结为这样的规律(实现整体升序):
第一步,序列等分,第一部分升序,第二部分降序
第二步,两个子序列对应元素比较互换;
第三步,对两个子序列均升序排序。1

经过个人的思考,我认为原理可用下图表示:
第一步的升序和降序是为了找出一个等位值,第二步把两个子序列对应位置的元素进行比较,找到这个等位值,把小于等位值的交换到第一个子序列,大于等位值的交换到第二个子序列,所以第三步中只需要分别对子序列进行排序即可实现整体的排序。

那么对于不是2的幂次方个元素的序列,我们怎么能采用双调排序吗?通常思路是:把序列补充为有2的幂次方个元素,再采用双调排序。显然这种方法非常浪费空间,不建议使用。

我的思路是在原有排序思想上进行一小点的改动。
我们还是以最终实现整体升序为例。因为对于任意序列,要么是奇序列,要么是偶序列。对于奇序列,做以下改进:
第一步,还是等长划分,但第二个序列会多一个元素,第一部分升序,第二部分降序;
第二步,两个子序列对应元素比较互换,只是其中对应的元素,第二个序列是从第二个元素开始(即子序列一的1号元素对应子序列二的2号元素,子序列一的2号元素对应子序列二的3号元素… …);
第三步,对两个子序列均升序排序。

其中关键步骤在于第二步,为什么比较的元素,对于第二个子序列应该从第二个元素开始算呢?

因为在第二步中,我们是要把小于等位值的换到第一个子序列中,由于第二个子序列是降序排序的,所以最后一个元素(最小)很有可能被换到第一个子序列中。你可能会问,那么第二个子序列的第一个元素不用考虑吗?是的,不用考虑!

请你仔细想想,如果这第一个元素比等位值大,显然应该留在第二个序列当中,如果比等位值小呢,我们换过去给子序列一的可都是比这个元素小的,可别忘了子序列二是降序排列的,而从子序列一中换过来的又都是比等位值大的(也就大于这个元素,即把子序列一中大于这个元素的都换到了子序列二)。因此经过第二步交换后,子序列一中不可能有元素大于子序列二的第一个元素。所以第三步还是两个子序列均升序即可实现最终的升序。

进阶双调排序怎么实现

我们在原有C程序的基础上实现进阶的双调排序。
参考以下代码:

#include<stdio.h>
#include<stdlib.h>
#define up 1
#define down 0
#define N 45

void generateNum(int *a,int num)
{
	for (int i = 0; i < num; i++){
		a[i] = rand() % 100;
	}
}

void compare(int *a, int *b, int type)
{
	int tmp = 0;
	if (type == up){
		if (*a > *b){
			tmp = *a;
			*a = *b;
			*b = tmp;
		}
	}
	else if (type == down){
		if (*a < *b){
			tmp = *a;
			*a = *b;
			*b = tmp;
		}
	}
	else
		printf("err,type\n");
}


void sort(int *a, int num, int type)
{
	if (num <= 1)
		return;
	int n = num / 2;
	sort(a, n, type);//升
	sort(a + n, n + num % 2, 1 - type);//降                                 
	for (int i = 0; i < n; i++)//中间过程
		compare(&a[i], &a[i + n + num % 2], type);
	sort(a, n, type);//升
	sort(a + n, n + num % 2, type);//升
}

void main()
{
	int *a = (int *)malloc(N*sizeof(int));
	generateNum(a, N);//生成随机数组
	sort(a, N, up);//双调排序
	for (int i = 0; i < N; i++)
		printf("%d ", a[i]);
	system("pause");
}

以上我增加了一个随机生成数组的函数,而双调排序的改进,仅仅只需要在sort()函数中加上num%2,即可实现对任意长度的序列进行排序。
代码中sort()函数中的注释:升与降对应第一步,中间过程对应第二步,升与升对应第三步。2

如果本文对你有帮助,不如请我一罐可乐吧 🍼
在这里插入图片描述


  1. 方法基于《GPU高性能运算之CUDA》–5.1.1. ↩︎

  2. 程序改进自上一篇博客《双调排序思想及实现》. ↩︎

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值