《算法》阅读笔记-2.3 快速排序

2.3 快速排序

2.3.1 基本算法

算法描述:快速排序也是分治的排序算法(归并排序也是分治),将数组分成两个部分独立排序,步骤:

1.    打乱

2.    选择切分点(切分点左半部分小于等于切分点,有半部分大于等于切分点)

3.    切分点左半部分排序

4.    切分点有半部分排序

代码如下:

public static void sort(Comparator[] a){
    StdRandom.shufflea(a);//打乱顺序,消除对输入的依赖
    sort(a,0,a.length -1);
}

public 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);
}

选择切分点的方法:

1.    先取a[lo]作为切分元素,循环如下操作,直到满足结束条件

2.    从数组左端开始向右扫描直到找到一个大于等于切分点的元素 (用索引i表示)

3.    从数组右端开始向左扫描直到找到一个小于等于切分点的元素 (用索引j表示)

4.    交换找到的这连个元素 (交换索引i和j所指的元素)

5.    结束条件:两个指针相遇(i>=j); 指针到达数组边界(i==hi / j==lo)

private static int partition(Comparable[] a, int lo, int hi) {
    int i =lo,j = hi + 1;
    Comparable v = a[lo];
    while(true){
        while(less(a[++i],v)) if(i == hi) break;
        while(less(v,a[--j]))if(j == lo) break;
        if(i>= j) break;
        exch(a,i,j);
    }
    each(a,lo,j);//将v = a[lo]放入正确的位置
    return j;
}

2.3.2性能分析:

优势:比较次数少,排序效率最终更依赖切分点的大小

切点:切分不平衡时低效。如:ICI从最小的元素切分,第二次错第二小的元素切分,这样每次调用只移动一个元素,导致一个大子数组需要切分很多次

2.3.3算法改进:

2.3.3.1切换到插入排序

1.对于小数组,快速排序比插入排序慢

2.在排序小数组时切换到插入排序,将

if(hi <= lo) return;

替换为

if(hi <= lo + M) {Insertion.sort(a,lo,hi);return;}

2.3.3.2三取样切分

1.使用子数组中一小部分的中位数来切分数组,代价是需要计算中位数。

2.将选取的元素放在数组末尾作为“哨兵”来去掉partition()中的边界检查。

2.3.3.3三向切分排序

对于含有大量重复元素的数组,算法在重复数字的位置也会进行切分,而这些切分是没有必要的。改进方法是:将数组切分为三部分:小于、等于、大于切分元素。

算法描述:维护一个指针lt使得a[lo,..lt-1]中的元素小于v;一个指针gt使得a[gt+1..hi]中的元素大于v,一个指针i使得a[lt..i-1]中的元素等于v,a[i..gt]中的元素还未确定

1.    a[i]小于v,将a[lt]和a[i]交换,将lt和i加1;

2.    a[i]大于v,将a[gt]和a[i]交换,将lt和i减1;

3.    a[i]等于v,将i加1;

代码如下:

private static void sort(Comparable[] a,int lo,int hi){
    if(hi<= lo) return;
    int lt =lo, i = lo + 1,gt = hi;
    Comparable v = a[lo];
    while(i<= gt){
        int cmp =a[i].comparaTo(v);
        if     (cmp < 0)exch(a,lt++,i++);
        else if(cmp> 0)exch(a,i,gt--);
        else             i++;
    }
    sort(a,lo,lt-1);
    sort(a,gt+1,hi);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值