双调排序进阶:对任意长度的序列排序
来源:互联网 发布:js遍历jsonarray对象 编辑:程序博客网 时间:2024/06/04 01:35
双调排序思想及实现
- 双调排序回顾+进阶
- 进阶双调排序怎么实现
阅读之前注意:
本文阅读建议用时:20min
本文阅读结构如下表:
双调排序回顾+进阶
双调排序是基于四元素排序发展起来的一种排序方法,单纯的双调排序适用于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 45void 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
- 双调排序思想及实现
- 阅读之前注意
- 双调排序回顾进阶
- 进阶双调排序怎么实现
- 方法基于《GPU高性能运算之CUDA》–5.1.1. ↩
- 程序改进自上一篇博客《双调排序思想及实现》. ↩
- 双调排序进阶:对任意长度的序列排序
- 双调排序程序解析(可对任意长度的序列排序)
- 对ListView任意列排序
- STL对已排序的序列进行排序和运算
- 冒泡排序--对指定的区间序列排序
- 建立可对任意属性排序的对象集合
- 建立可对任意属性排序的对象集合
- C++方法对输入的任意数进行排序
- 使用回调实现对一组任意类型的对象做快速排序
- 对任意长度的矢量求和
- C++ 字符串序列 进行长度 排序的同时,保持字典序排序
- 【归并排序】【逆序对】序列
- 统计任意长度字符串中各个字符及个数——计数排序的又一个应用
- 利用冒泡排序法,对任意数组进行排序;
- 对输入的字符串按照字母序列排序并输出
- 对给定的分数进行排序输出排名序列
- 序列的排序
- 排序不同长度的数据项
- 测试格式
- 深度学习: translation invariant (平移不变性)
- ES6学习13章:Promise对象
- lwp和线程区别
- 游戏开发学习笔记(十五)怪物系统
- 双调排序进阶:对任意长度的序列排序
- 微信小程序----App生命周期
- bash shell的配置
- 2017.12.18 第七、八天-java接口对接
- 【知识整理】Axios-如何发送一个GET请求
- git Download github 项目
- Spacevim
- 面向对象的理解
- 分答项目_技能点:手机端屏幕向上滑动添加内容