@shaobaobaoer
2018-05-28T00:38:43.000000Z
字数 2383
阅读 1291
按照下述原则编写快速排序非递归算法:
(以流程图或盒图等形式画出)
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
至于快速排序算法,会在后面有详细的解释。这边给出的是题目的构造
(可说明如何使用或改进完善教材程序)
备注: 我这里的快速排序算法和教材上给出的不太一样。该算法来自于 数据结构考研笔记 殷人昆著 。
虽然实现方法不一样,但是基本思想还是一样的。并且按照这个方法完成了作业。
传入参数Right ,Left 。表示需要排序的数组的一部分 (如果要对数组a下标从i到j的部分排序,那就传入的参数为Right=j,Left=i
。
并将基准数记为 a[Left]
比如说传入的数组为a[10]={6 1 2 7 8 3 4 5 10 9}
a | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|---|
value | 6 | 1 | 2 | 7 | 8 | 3 | 4 | 5 | 10 | 9 |
对上述数组进行快读排序,传入的参数为Right=j,Left=0
此时 i=0;j=9
a | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|---|
value | 6 | 1 | 2 | 7 | 8 | 3 | 4 | 5 | 10 | 9 |
I/J | i | j |
哨兵 j 先从左边开始移动,移动到一个比基准数小的位置。这里 j 会移动到 7 的位置。之后开始移动 i 。从右边开始移动,移动到一个比基准数大的位置。第一次移动后结果如下:
a | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|---|
value | 6 | 1 | 2 | 7 | 8 | 3 | 4 | 5 | 10 | 9 |
I/J | i | j |
然后交换i和j的位置。并再一次进行如上的排序,直到i和j相遇
a | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|---|
value | 6 | 1 | 2 | 5 | 8 | 3 | 4 | 7 | 10 | 9 |
I/J | i | j |
- 第三次i j 内推。 i j 在 3 的地方。交换该位置与基准数。本次排序结束。
a | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|---|---|
value | 6 | 1 | 2 | 5 | 8 | 3 | 4 | 7 | 10 | 9 |
I/J | i j |
总结来说就是这样:
/* 0 1 2 3 4 5 6 7 8 9
* 6 1 2 7 8 3 4 5 10 9
* 3 1 2 5 4 6 8 7 10 9
* L M R
* 较长的序列在前面的情况,长序列上下界入栈,
* 下次会对长的序列排序
*/
任何递归算法都可以通过栈来实现。这点毋庸置疑。快速排序算法也可以用非递归算法实现。所需要用到的数据模型是 栈 。
大体的伪代码如下:
int QK_sort_NonRecursion(int Array[]) {
LinkStack<int> s;
s.Push(0); s.Push(n - 1); //注意压栈顺序,这里先压入的是0<Left>后压入的 n-1<Right>
while (!s.IsEmpty()) {
s.Pop(Right);
s.Pop(Left);//注意出栈顺序
while (Right - Left > 2) {
///当子序列长度大于三的时候,那就没有排序完毕
mid = QK_sort_Partition(Array, Left , Right ); //先将表进行一次排序
///按照题目要求,先对长度短的子表进行排序,并将另一子表的上下界入栈保存
if (Right - mid > mid - Left) {
//右边长,那就R_Right,R_Left入栈。并对左边的子表进行排序
} else {
//左边长,那就L_Right,L_Left入栈。并对右边的子表进行排序
}
if (Right - Left == 2) 比较排序
if (Right - Left == 3) 比较排序
}
}
这点和教材上的代码较为类似。
(说明工程所含有的所有源代码文件和支持文件(如输入输出的文本文件)及其功能)
文件名 | 文件类型 | 功能简介 | 备注 |
---|---|---|---|
Node.h | head file | 节点类 | 来自 沈俊老师的代码 |
LinkStack.h | head file | 栈类 | 来自 沈俊老师的代码 |
Assistance.h | head file | 辅助程序 | 来自 沈俊老师的代码 |
main.cpp | cpp file | 主程序 | QK_sort_Recursion 快速排序递归算法 QK_sort_Partition 完成一趟快速排序的过程 QK_sort_NonRecursion 快速排序非递归算法 |
CMakeLists.txt | CMAKE file | CMAKE | Clion 辅助文件 |
cmake-build-debug | Document | 编译程序的文件夹 | Clion 生成的编译程序 |
(要求几组具有代表性的数据,要求附如下所示的运行效果图, 或是实际运行的输入输出文件)
5.(包括题目的难易、调试过程等)
我觉得这道题目出题的角度很新颖。从某种程度上来说,这种结合比较排序算法的快速排序。从某种程度上比原本的快速排序算法更加优秀一些。
总之,觉得这道题目挺不错的。让我对快速排序算法有了新的理解和认识。
另外,教材中学习到的算法和我以前看到的快速排序算法有些不太一样。但是整体的思路还是一样的。我把教材中的代码仔细看了看,发现确实教材代码和我的代码有些不太一样,具体表现在 I 和 J 的位置调度上。最终两者的结果是一样的。(一开始看到我第一次排序和参考代码对比不一样的时候有点愣住,才发现自己掌握的快排和老师的有点不太一样)
总之,条条大路通罗马,尽管方法不一样,但是思路正确,最终自己经过调试DEBUG后还是能够实现的。