《算法》希尔排序、归并排序、快速排序、三向切分的快速排序

1.希尔排序

//希尔排序,《算法》p163
package algorithm;

public class Shell_p163 {
    public void sort(int[] a){
        int N = a.length;
        int h = 1;
        while(h < N/3){h = 3*h + 1;}
        while(h >= 1){
            for(int i = h; i < N; i++){//遍历a[h]之后的数组元素
                for(int j = i; j > 0; j -= h){//将a[i]插入到a[i-h],a[i-2h]……的适当位置
                    if(a[j] < a[j-h]){
                        int temp = a[j];
                        a[j] = a[j-h];
                        a[j-h] = temp;
                    }                       
                }
            }
            h = h/3;
        }
        for(int i = 0; i < N; i++){
            System.out.println(a[i]);
        }
    }   
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] a = {5,4,3,2,1};
        Shell_p163 test = new Shell_p163();
        test.sort(a);
    }
}

思路:
调整a[0],a[h],a[2h]…
a[1],a[h+1],a[2h+1]…
a[2],a[h+2],a[2h+2]…
a[3],a[h+3],a[2h+3]…
……分别是有序的,将a[i]插入到a[i-h],a[i-2h]……的适当位置,
本程序中,h以1/3的速度减小,当h最后为1的时候,全部排序结束。

2.归并排序

//自顶向下归并排序,《算法》p171
package algorithm;

public class Merge_p171 {
    private static int[] aux;
    public static void merge(int[] a, int lo, int mid, int hi){
        int i = lo;
        int j = mid + 1;
        for(int k = lo; k <= hi; k++){aux[k] = a[k];}
        for(int k = lo; k <= hi; k++){
            if (i > mid){a[k] = aux[j++];}//左侧数组已用完
            else if (j > hi){a[k] = aux[i++];}//右侧数组已用完
            else if (aux[j] < aux[i]){a[k] = aux[j++];}//右侧当前数比左侧当前数小时,用右侧的数,j++;
            else {a[k] = aux[i++];}//左侧当前数小于等于右侧当前数,用左侧的数,i++;
        }       
    }
    public static void sort(int[] a){
        aux = new int[a.length];
        sort(a, 0, a.length-1);
    }
    private static void sort(int[] a, int lo, int hi){
        if(hi <= lo){return;}
        int mid = (lo + hi)/2;
        sort(a, lo, mid);
        sort(a, mid+1, hi);
        merge(a, lo, mid, hi);
    }
    public static void display(int[] a){
        for(int i = 0; i < a.length; i++){
            System.out.println(a[i]);
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] a = {5,4,3,2,1};
        Merge_p171.sort(a);
        Merge_p171.display(a);
    }
}

思路:
使用递归的方法,分治思想
归并是说,让两个有序的子数组归并到一个有序的数组,先将两个子数组复制到辅助数组aux,指针i指向第一个子数组的第一个元素aux[i],j指向第二个子数组的第一个元素aux[j]。通过判断aux[i]和aux[j],不断给a[k]赋值。
一个数组可以两个子数组归并而来,两个子数组是它们的两个子数组归并而来……
通过递归调用,整个过程可以描述为,先归并a[0],a[1],再归并a[2],a[3]再归并a[0]~a[3],再归并a[4],a[5],再归并a[6],a[7]再归并a[4]~a[7],……以此类推,最后完成两个大数组的归并,完成排序

//自底向上的归并排序,《算法》p175
package algorithm;

public class MergeBU_p176 {
    private static int[] aux;
    public void merge(int[] a, int lo, int mid, int hi){
        int i = lo;
        int j = mid + 1;
        for(int k = lo; k <= hi; k++){aux[k] = a[k];}
        for(int k = lo; k <= hi; k++){
            if (i > mid){a[k] = aux[j++];}
            else if (j > hi){a[k] = aux[i++];}
            else if (aux[j] < aux[i]){a[k] = aux[j++];}
            else {a[k] = aux[i++];}
        }       
    }
    public void sort(int[] a){
        int N = a.length;
        aux = new int[N];
        int size;
        for(size = 1; size < N; size *=2){
            for(int lo = 0; lo < N-size; lo += (2*size)){
                int mid = lo + size - 1;
                int hi = lo + size + size - 1;
                merge(a, lo, mid, Math.min(hi, N-1));
            }
        }
    }
    public void display(int[] a){
        for(int i = 0; i < a.length; i++){
            System.out.println(a[i]);
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] a = {5,4,3,2,1};
        MergeBU_p176 test = new MergeBU_p176();
        test.sort(a);
        test.display(a);
    }

}

思路:
自底向下的归并是说先令size=1,归并(a[0],a[1])(a[2],a[3])(a[4],a[5])……再令size翻倍,归并(a[0]~a[3])(a[4]~a[7])……
再令size翻倍……如此循环下去,直到size大于N。注意归并的时候,数组长度不一定为2的幂,所以在归并的末尾指针要取Math.min(hi, N-1)。

3.快速排序

//快速排序,《算法》p184
package algorithm;

public class Quick_p182 {
    public void sort(int[] a){
        sort(a, 0, a.length-1);
    }
    private void sort(int[] 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);
    }
    private int partition(int[] a, int lo, int hi) {
        // TODO Auto-generated method stub
        int i = lo;
        int j = hi + 1;                         
        int v = a[lo];
        while(true){
            while(a[++i] < v){if(i == hi) break;}
            while(a[--j] > v){if(j == lo) break;}
            if(i >= j){break;}
            int temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }
        int temp = a[lo];
        a[lo] = a[j];
        a[j] = temp;    
        return j;
    }
    public void display(int[] a){
        for(int i = 0; i < a.length; i++){
            System.out.println(a[i]);
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] a = {5,4,3,2,1};
        Quick_p182 test = new Quick_p182();
        test.sort(a);
        test.display(a);
    }
}

思路:
分治思想
排序所有元素时,首先为第一个元素找到一个适合的位置j,使得索引0~j-1的元素都小于a[j],j+1~a.length-1的元素都大于a[j]
再排序0~j-1的元素,再排序j+1~a.length-1的元素

//三向切分的快速排序,《算法》p189
package algorithm;

public class Quick3way_p189 {
    public void sort(int[] a){
        sort(a, 0, a.length-1);
    }
    private void sort(int[] a, int lo, int hi){
        if (hi <= lo) return;
        int lt = lo, gt = hi, i = lo + 1;
        int v = a[lo];
        while(i <= gt){
            if(a[i] < v){
                exch(a, i, lt);
                i++;
                lt++;
            }
            else if(a[i] > v){
                exch(a, i, gt);
                gt--;
            }
            else {i++;}
        }
        sort(a, lo, lt-1);
        sort(a, gt+1, hi);
    }
    private void exch(int[] a, int i, int j){
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }

    public void display(int[] a){
        for(int i = 0; i < a.length; i++){
            System.out.println(a[i]);
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] a = {5,4,3,2,1};
        Quick3way_p189 test = new Quick3way_p189();
        test.sort(a);
        test.display(a);
    }
}

思路:
调整全部数组后,将数组切分成三个部分,lo~lt-1是小于a[i]的元素,gt+1~hi是大于a[i]的元素,lt~gt是等于aa[i]的元素。
再将lo~lt-1排序,再将gt+1~hi排序,不断递归。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值