快速排序
来源:互联网 发布:围棋点目软件 编辑:程序博客网 时间:2024/06/07 01:08
快速排序
先看个例子:
对于数组 a = [427 353 112 914 141 555 96 696 294 883]
,我们选择tmp = a[0]
作为我们的枢纽元,在实现第一轮排序后,我们要实现的效果是数组a
分成两部分,前面的部分元素全部小于等于**tmp,后面部分全部大于等于**tmp。取i = 0; j = a.length-1; tmp = a[0]
第一轮排序过程如下
1. 从j开始,我们找到第一个小于 tmp=427 的元素,为 a[8]=294,将 a[j] 值存储到 i 位置,此时数组为
a = [294 353 112 914 141 555 96 696 294 883]
。同时,i++ (因为当前元素已经确保小于等于 tmp)
2. 从 i 开始,我们找到第一个大于 tmp=427 的元素,为 a[3] = 914,将 a[i] 值存储到 j 位置,此时数组为 a = [294 353 112 914 141 555 96 696 914 883]
,同时 j–
3. 循环步骤1和步骤2,直到 i >= j
。最后,将 tmp 值赋予 a[i]。
4. 经过第一趟排序后,我们数组的值为 a = [294 353 112 96 141 294 555 696 914 883]
。此时我们发现,a[0..5]
的值小于等于tmp,a[6..9]
的值大于等于 tmp。
在第一轮排序后我们得到两个数组,分别为 S1 = a[0..5], S2 = a[6..9]
,这时我们再对这两个数组各自执行上述步骤,不断递归下去,则最终可以得到一个排序数组。
上述步骤可总结为:
- 如果当前数组元素个数小于等于1,直接返回
- 选择数组中任一元素,称为枢纽元,这里为了方便我们选择
i = 0
为枢纽元,值设为 tmp - 设数组左端点为 i,右端点为 j。
- 在每轮排序中,我们将当前数组分为两个数组 S1,S2。其中 S1 数组的所有值均小于等于 tmp,S2 的所有元素均大于等于 tmp。
- 执行
quickSort(S1), quickSort(S2)
以第一个元素为枢纽元的实现如下
void quickSort(int[] a, int left, int right) { if (left >= right) return; int x = a[left]; int i = left; int j = right; while (i < j) { while (i < j && a[j] > x) j--; if (i < j) a[i++] = a[j]; while (i < j && a[i] < x) i++; if (i < j) a[j--] = a[i]; } a[i] = x; // 此处注意将a[i]替换回枢纽元元素 quickSort(a, i+1, right); quickSort(a, left, i-1); }
其平均运行时间为O(N log N)
。最坏运行时间为O(N^2)
上面为了理解简单,我们的枢纽元直接选择了数组的第一个元素,当数组是随机的时候,则不存在问题,因为现在所有元素都是等价的,但如果该数组是预排序或者反序的,则我们可发现,所有元素只能被划入集合S1
或集合S2
。假设数组是预排序的,且 a[0] != [a1]
(相等则是另一种类似情况),则第一轮排序后 S1=a[0], S2=a[1...n]
,则此时 O(n^2)
;同理,当数组是逆序时,同样有 O(N^2)
。故直接使用数组的第一个元素是不好的选择。
通常情况下,随机选择数组任意一位作为枢纽元素是安全的,这里我们选择数组的中间位置的元素,代码如下
void Quick(int *a, int left, int right){ if (left >= right) return; int prvot = (left+right) / 2; int tmp = a[prvot]; int i = left; int j = right; while (i < j) { while (i < j && a[j] > tmp) j--; if (i < j) { a[prvot] = a[j]; prvot = j; } while (i < j && a[i] < tmp) i++; if (i < j) { a[prvot] = a[i]; prvot = i; j--; // 这里注意,否则出现重复值时可能进入死循环 } } a[prvot] = tmp; Quick(a, prvot+1, right); Quick(a, left, prvot-1);}
完整代码参考: quickSort.cpp
- 快速排序
- 快速排序
- 快速排序
- 快速排序!
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 快速排序
- 前端学习3(free code camp part.1)
- EditText输入密码隐藏或显示文本
- Android 7.0 CTS测试设置
- 24点游戏算法
- 前端百科
- 快速排序
- Java集合架构详解
- XMind中主题连接线格式修改教程
- WebRTC学习资料大全
- 面试:C++中static关键字的作用(转)
- ckeditor富文本编辑器的使用
- 线性表的链式存储结构
- 大数加法-Tsinsen A1087.高精度加法
- 优酷的订阅丢失解决方法