博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
排序之 快速排序
阅读量:4944 次
发布时间:2019-06-11

本文共 3770 字,大约阅读时间需要 12 分钟。

采用算法导论上的实现方式,用java实现。

快排算法核心的部分便是partition过程,这里的partition采取最后一个元素作为pivot,i和j两个指针都从头向后扫描,如下图所示,数组被分为4个部分。

 

算法执行的过程:

 

代码实现:包括快速排序寻找第K大元素洗牌算法

 

import java.util.Arrays;import java.util.Random;public class MySort {    /**     * 快速排序     *      * @param a     */    public static void quickSort(int[] a) {        qSort(a, 0, a.length - 1);    }    private static void qSort(int[] a, int p, int r) {        if (p < r) {
// 递归算法不要忘记了出口 int q = partition(a, p, r); qSort(a, p, q - 1); qSort(a, q + 1, r); } } private static int partition(int[] a, int p, int r) { int x = a[r]; int i = p - 1; int j = p; for (j = p; j < r; j++) { if (a[j] <= x) { i++; swap(a, i, j); } } swap(a, i + 1, r); return i + 1; } private static void swap(int[] a, int i, int j) { if (i != j) { int tmp = a[i]; a[i] = a[j]; a[j] = tmp; } } /** * 返回第k大的元素。 * * @param a * @param k * @return */ public static int selectKSmallest(int[] a, int k) { if (k >= a.length || k < 0) return -1; qSelect(a, k, 0, a.length - 1); return a[k]; } private static void qSelect(int[] a, int k, int p, int r) { if (p < r) { int q = partition(a, p, r); if (q > k) qSelect(a, k, p, q - 1); else if (q < k) qSelect(a, k, q + 1, r); else return; } } /** * 洗牌算法 * * @param a */ public static void shuffle(int[] a) { for (int i = 0; i < a.length; i++) { int k = new Random().nextInt(i + 1);// return a random value in // [0,i]. int tmp = a[k]; a[k] = a[i]; a[i] = tmp; } } public static void main(String[] args) { int[] a = { 2, 8, 7, 1, 3, 5, 6, 4 }; System.out.println("before sorting:" + Arrays.toString(a)); quickSort(a); System.out.println("after sortint:" + Arrays.toString(a)); shuffle(a); System.out.println("after shuffling:" + Arrays.toString(a)); System.out.println(selectKSmallest(a, 3)); }}

 

 

正确性证明:

 

 

双指针向内的快速排序:   Algorithms里讲的很好,看

import java.util.Arrays;public class test {    public static void quickSort2(int[] a) {        qSort(a, 0, a.length - 1);    }    /**     * 注意1:递归终止条件 l>=r      * 注意2:i和j初始位置,用do while保证至少有一次变化,不会原地不动     * 注意3:j最终的位置是要和l交换的位置。     * 注意4:对于跟pivot相等的情况,应该停住两个指针并交换,虽然交换次数增多,但是保证partition更平均,复杂度更低。     */    private static void qSort(int[] a, int l, int r) {        if (l >= r)            return;        int t = a[l];        int i = l, j = r + 1;        while (true) {            do {                i++;            } while (i <= r && a[i] < t);            do {                j--;            } while (a[j] > t);            if (i > j)                break;            swap(a, i, j);        }        swap(a, l, j);        qSort(a, l, j - 1);        qSort(a, j + 1, r);    }    private static void swap(int[] a, int i, int j) {        int tmp = a[i];        a[i] = a[j];        a[j] = tmp;    }    public static void main(String[] args) {        int[] a = { 1, 1, 1, 1, 1 };        System.out.println(Arrays.toString(a));        quickSort2(a);        System.out.println(Arrays.toString(a));    }}

 

 

快速排序细节及优化:

1. pivot随机化:不一定每次都选第一个为pivot, 可以先做 swap(a[0], a[rand(l,r)]);或者选取三个样本中的中位数作为pivot

2. 两个指针移动的时候对于跟pivot相等的元素,应该停住交换,而不是跨过。(虽然增加了交换时间,但是保证了极端情况,比如元素全部相等情况下,partition分区极不均匀的情况。)

3. r-l 小于一定的cutoff之后,选用insertion sort等方法。

4. 3-way-partation。:当数组有大量重复元素时,这种优化复杂度甚至可以降到线性。

 

转载于:https://www.cnblogs.com/jdflyfly/p/3897331.html

你可能感兴趣的文章
outlook 设置163邮箱
查看>>
mysql优化——show processlist命令详解
查看>>
Solr服务器搭建
查看>>
画世界怎么用光影_世界绘画经典教程:水彩光影魔法教程
查看>>
win+rsync+php,跨平台的fswatch+rsync同步备份
查看>>
vue2 cdn 加载html,vue项目中使用CDN加载
查看>>
数组转集合踩坑
查看>>
node.js的异步I/O、事件驱动、单线程
查看>>
vue cli3 子目录问题
查看>>
github.com访问慢解决
查看>>
微服务架构最强详解
查看>>
转:哈夫曼树详解
查看>>
.Net Core Identity外面使用Cookie中间件
查看>>
【坐在马桶上看算法】算法1:最快最简单的排序——桶排序
查看>>
C#中泛型之Dictionary
查看>>
强连通分量
查看>>
使用Code First模式开发如何更新数据库(转载)
查看>>
sqoop导出工具
查看>>
Codeforces Round #376 (Div. 2)
查看>>
Codeforces 607D Power Tree 线段树 (看题解)
查看>>