双调排序进阶:对任意长度的序列排序(C语言)
- 双调排序回顾+进阶
- 进阶双调排序怎么实现
阅读之前注意:
本文阅读建议用时: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
如果本文对你有帮助,不如请我一罐可乐吧 🍼