普林斯顿大学算法课 Algorithm Part I Week 3 快速排序 Quicksort
发明者: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的更多相关文章
- 普林斯顿大学算法课 Algorithm Part I Week 3 排序算法复杂度 Sorting Complexity
计算复杂度(Computational complexity):用于研究解决特定问题X的算法效率的框架 计算模型(Model of computation):可允许的操作(Allowable oper ...
- 普林斯顿大学算法课 Algorithm Part I Week 3 归并排序 Mergesort
起源:冯·诺依曼最早在EDVAC上实现 基本思想: 将数组一分为(Divide array into two halves) 对每部分进行递归式地排序(Recursively sort each ha ...
- 普林斯顿大学算法课 Algorithm Part I Week 3 排序的应用 System Sorts
排序算法有着广泛的应用 典型的应用: 排序名称 排序MP3音乐文件 显示Google的网页排名的搜索结果 按标题顺序列出RSS订阅 排序之后下列问题就变得非常简单了 找出中位数(median) 找出统 ...
- 普林斯顿大学算法课 Algorithm Part I Week 3 重复元素排序 - 三路快排 Duplicate Keys
很多时候排序是为了对数据进行归类,这种排序重复值特别多 通过年龄统计人口 删除邮件列表里的重复邮件 通过大学对求职者进行排序 若使用普通的快排对重复数据进行排序,会造成N^2复杂度,但是归并排序和三路 ...
- 普林斯顿大学算法课 Algorithm Part I Week 3 求第K大数 Selection
问题 给定N个元素的数组,求第k大的数. 特例当k=0时,就是求最大值,当k=N-1时,就是求最小值. 应用顺序统计求top N排行榜 基本思想 使用快速排序方法中的分区思想,使得a[k]左侧没有更小 ...
- 普林斯顿大学算法课 Algorithm Part I Week 3 排序稳定性 Stability
稳定性(Stability):先按性质A排序,再按性质B排序,性质B相同的那些项是否仍然是按性质A排序的? 一个稳定的排序,相同值的元素应仍保持相对顺序(relative order) 稳定的算法:插 ...
- 普林斯顿大学算法课 Algorithm Part I Week 3 自我总结
要熟练掌握比较器Comparator public final Comparator<T> MY_COMPARATOR = new myComparator(); //定义比较器 .... ...
- 普林斯顿大学算法课 Algorithm Part I Week 3 比较器 Comparators
比较器接口(Comparator interface):用可选顺序(alternate order)进行排序 public interface Comparator<key> int co ...
- 普林斯顿大学算法课 Algorithm Part I 学习资源
网友笔记参考 果壳Mooc首页 revilwang的专栏 白色咖啡 Weiran Liu的渣技术小专栏 Bug表:http://findbugs.sourceforge.net/bugDescript ...
随机推荐
- 命令行参数解析:getopt,getopt_long
#include <unistd.h> int getopt(int argc, char * const argv[], const char *optstring); extern c ...
- fragment低版本
http://bbs.csdn.net/topics/390271980 Fragment框架开发东西确实很方便,但是恼人的是从4.0才开始支持.以前的版本必须用兼容模式开发,本人在网上找了大量资料, ...
- Android开发之ExpandableListView扩展(BaseExpandableListAdapter的使用)(完整版)
Android开发之ExpandableListView扩展(BaseExpandableListAdapter的使用)(完整版)
- Oracle10g安装中遇到的错误及解决办法
linux解决xhost: unable to open display实用技巧:在Linux下设置xhost方法步骤 第一步:用root登陆linux,启动vnc服务:第二步:根据vnc起来的端口, ...
- 动态可视化库Vis.js:社交关系谱
Form Here:http://code.csdn.net/news/2819345 Vis.js 是一个动态的.基于浏览器的可视化库,可处理大量的动态数据并能与这些数据进行交互操作.该项目是由Al ...
- poj 1050 To the Max_dp求最大子矩阵和
题意:求最大子矩阵和 利用dp[i]每次向下更新,构成竖起的单条矩阵,再按不小于零就加起来来更新,构成更大的矩阵 #include <iostream> #include<cstdi ...
- GroundworkCSS ♥ Tables
微信公众平台开发(41)一键关注微信公众平台账号 - 方倍工作室 - 博客园 微信公众平台开发(41)一键关注微信公众平台账号 GroundworkCSS ♥ Tables Example Layou ...
- Android的Bitmap和BitmapDrawable类解析-android学习之旅(六十)
使用简单图片 使用Drawable对象 bitmap和BitmapDrawable对象 package peng.liu.test; import android.app.Activity; impo ...
- 找出诡异的Bug:数据怎么存不进去
带着学生做课程设计.程序一大,课程中做过了小项目,练过了分解动作,一到合起来了,难免还是要乱了分寸.事实上,实战的功夫,就是这样出来的.(课程设计指导视频链接(第36课时,3.18 银行系统开发).课 ...
- 获取oracle sql语句中绑定变量值的方法
在诊断 sql的性能问题时,我们有时候须要获取其绑定变量的实际值,然后将此实际值带入到sql语句其中,用原来的sql构成select语句(带where条件),实际的运行一下,看一下选择性怎样. 本文就 ...