发明者:Sir Charles Antony Richard Hoare

基本思想:

  • 先对数据进行洗牌(Shuffle the array)
  • 以数据a[j]为中心进行分区(Partition),使得a[j]左侧的数据都小于等于a[j],a[j]右侧的数据都大于等于a[j]

  • 分区完后递归排序

分区演示(partitioning demo)

重复操作指导i和j指针相遇

  • 当a[i] < a[lo]时,令i从左往右扫描
  • 当a[j] > a[lo]时,令j从右往左扫描
  • 交换a[i]和a[j]

当指针相遇时

  • 交换a[lo]和a[j]

Java实现

public class Quick
{
private static int partition(Comparable[] a, int lo, int hi)
{
int i = lo, j = hi + 1;
while (true)
{
while (less(a[++i], a[lo]))
if (i == hi) break; // 从左向右找到不小于a[lo]的元素 while (less(a[lo], a[--j]))
if (j == lo) break; // 从右向左找到不大于a[lo]的元素 if (i >= j) break; // 指针相遇
exch(a, i , j); // 交换 } exch(a, lo, j); // 和比较元素交换
return j; // 返回比较元素所在的下标
} public static void sort(Comparable[] a)
{
StdRandom.shuffle(a); // 先对数组进行洗牌,复杂度是N
sort(a, 0, a.length - 1);
} private static void sort(Comparable[] a, int lo, int hi)
{
if (hi <= lo) return;
int j = partition(a, lo, hi);
sort(a, lo, j-1);
sort(a, j+1, hi);
}
}

实现细节(implementation details)

  • 原地分区(Partitioning in-place):不用开辟额外的辅助数组
  • 终止循环:检查两个指针是否相遇
  • 边界:(j == lo)的检查是多余的,但(i == hi)的检查是必要的
  • 保留随机性(Preserving randomness):需要洗牌(Shuffling)来保证运动(Performance guarantee)
  • 相同的值(Equal keys):当存在重复的元素,最好将指针停在和比较元素相同的位置上(When duplicates are present, it is (counter-intuitively) better to stop on keys equal to the partitioning item's key.)

复杂度平均情况分析(average-case analysis):平均复杂度为 1.39NlgN,比归并排序还快

运行特征(Performance characteristic)

  • 最坏情况(Worst case):1/2*N^2

    • 几乎不会出现
  • 平均情况(Average case):比较次数约等于1.39NlgN
    • 比归并排序多出39%的比较次数
    • 但是由于更少的数据交换,实际中比归并排序更快
  • 随机洗牌(Random shuffle):  
    • 对最坏情况的概率性保证(Probabilistic guarantee)
    • 经过实验验证的数学模型的基础(Basic for math model that can be validated with experiments.)
  • 留心:出现以下情况时,运算是平方级的(quadratic)
    • 当数组逆序排列
    • 当存在多个重复元素   

特性(Properties):

  • 快速排序是一种原地排序算法(in-place sorting algorithm)
  • 不具有稳定性

实践上的改善(practical improvements)

改善1:使用插入排序对小的子序列进行排序

  • 即使是快速排序,也对小数组有不少的开销
  • 当数组大小达到10时,停止(Cutoff)插入排序
  • 大概有20%的改善
private static void sort(Comparable[] a, int lo, int hi)
{
if (hi <= lo + CUFOFF -1)
{
Insertion.sort(a, lo, hi);
return;
}
int j = partition(a, lo, hi);
sort(a, lo, j-1);
sort(a, j+1, hi);
}

改善2:使用平均数作为比较元素

  • 最好的选择是比较元素刚好是中值
  • 通过取样估计中值(Estimate true median by taking median of sample.)
  • 对三个取样元素取平均值
  • 大概有10%的改善
private static void sort(Comparable[] a, int lo, int hi)
{
if (hi <= lo) return; int m = medianOF3(a, lo, lo + (hi - lo)/2, hi);
swap(a, lo, m); int j = partition(a, lo, hi);
sort(a, lo, j-1);
sort(a, j+1, hi);
}

普林斯顿大学算法课 Algorithm Part I Week 3 快速排序 Quicksort的更多相关文章

  1. 普林斯顿大学算法课 Algorithm Part I Week 3 排序算法复杂度 Sorting Complexity

    计算复杂度(Computational complexity):用于研究解决特定问题X的算法效率的框架 计算模型(Model of computation):可允许的操作(Allowable oper ...

  2. 普林斯顿大学算法课 Algorithm Part I Week 3 归并排序 Mergesort

    起源:冯·诺依曼最早在EDVAC上实现 基本思想: 将数组一分为(Divide array into two halves) 对每部分进行递归式地排序(Recursively sort each ha ...

  3. 普林斯顿大学算法课 Algorithm Part I Week 3 排序的应用 System Sorts

    排序算法有着广泛的应用 典型的应用: 排序名称 排序MP3音乐文件 显示Google的网页排名的搜索结果 按标题顺序列出RSS订阅 排序之后下列问题就变得非常简单了 找出中位数(median) 找出统 ...

  4. 普林斯顿大学算法课 Algorithm Part I Week 3 重复元素排序 - 三路快排 Duplicate Keys

    很多时候排序是为了对数据进行归类,这种排序重复值特别多 通过年龄统计人口 删除邮件列表里的重复邮件 通过大学对求职者进行排序 若使用普通的快排对重复数据进行排序,会造成N^2复杂度,但是归并排序和三路 ...

  5. 普林斯顿大学算法课 Algorithm Part I Week 3 求第K大数 Selection

    问题 给定N个元素的数组,求第k大的数. 特例当k=0时,就是求最大值,当k=N-1时,就是求最小值. 应用顺序统计求top N排行榜 基本思想 使用快速排序方法中的分区思想,使得a[k]左侧没有更小 ...

  6. 普林斯顿大学算法课 Algorithm Part I Week 3 排序稳定性 Stability

    稳定性(Stability):先按性质A排序,再按性质B排序,性质B相同的那些项是否仍然是按性质A排序的? 一个稳定的排序,相同值的元素应仍保持相对顺序(relative order) 稳定的算法:插 ...

  7. 普林斯顿大学算法课 Algorithm Part I Week 3 自我总结

    要熟练掌握比较器Comparator public final Comparator<T> MY_COMPARATOR = new myComparator(); //定义比较器 .... ...

  8. 普林斯顿大学算法课 Algorithm Part I Week 3 比较器 Comparators

    比较器接口(Comparator interface):用可选顺序(alternate order)进行排序 public interface Comparator<key> int co ...

  9. 普林斯顿大学算法课 Algorithm Part I 学习资源

    网友笔记参考 果壳Mooc首页 revilwang的专栏 白色咖啡 Weiran Liu的渣技术小专栏 Bug表:http://findbugs.sourceforge.net/bugDescript ...

随机推荐

  1. 变态最大值(nyoj)

    变态最大值 描述 Yougth讲课的时候考察了一下求三个数最大值这个问题,没想到大家掌握的这么烂,幸好在他的帮助下大家算是解决了这个问题,但是问题又来了. 他想在一组数中找一个数,这个数可以不是这组数 ...

  2. Mfgtool

    For bootstrap mode, it refers to the communcation between the host and ROM codes through serial down ...

  3. 1.C语言关键字(auto break case char const swtich)

    ANSI C标准C语言共有32个关键字,分别为: auto break case char const continue default do double else enum extern floa ...

  4. Servlet中Web.xml的配置详解

    1 定义头和根元素 部署描述符文件就像所有XML文件一样,必须以一个XML头开始.这个头声明可以使用的XML版本并给出文件的字符编码. DOCYTPE声明必须立即出现在此头之后.这个声明告诉服务器适用 ...

  5. codility上的练习(3)

    今天发现又出了lesson 3... 不过题目都很简单…… (1) Min-avg-slice 给定一个长度为n的整数数组,找到一个连续的子数组,数组元素的平均值最小. 数据范围N [1..10^5] ...

  6. "NO 3D support is available from the host"

    https://forums.opensuse.org/showthread.php/494522-No-3d-Support-or-graphics-accelleration http://ask ...

  7. cf467A George and Accommodation

    A. George and Accommodation time limit per test 1 second memory limit per test 256 megabytes input s ...

  8. 【POJ】3468 A Simple Problem with Integers ——线段树 成段更新 懒惰标记

    A Simple Problem with Integers Time Limit:5000MS   Memory Limit:131072K Case Time Limit:2000MS Descr ...

  9. 模块化利器:RequireJS常用知识

    1. 模块化 目前常见的模块化开发方式,全局空间方式是最基本的一种,另外常见的还有遵循AMD规范的开发方式,遵循CMD规范的开发方式,和ECMAScript 6的开发方式.需要说明的是,CMD和ES6 ...

  10. 求S=a+aa+aaa+aaaa+aa...a的值

    问题描述:求S=a+aa+aaa+aaaa+aa...a的值,其中a是一个数字,由输入a(1 <= a <= 9)表示,相加的元素个数由输入b(b<= 1000)表示. 这个算法的优 ...