数据结构 -- 高级排序

一、希尔排序

1.1 API设计

类名 ShellSort
构造方法 ShellSort():创建ShellSort对象
成员方法 1.public static void sort(Comparable[] a):对数组内的元素进行排序
2.private static boolean greater(Comparable v,Comparable w):判断v是否大于w
3.private static void exch(Comparable[] a,int i,int j):交换a数组中,索引i和索引j处的值

1.2 实现

public class ShellSort {
    
    
    // 希尔排序是插入排序的一种,它是针对直接插入排序算法的改进。

    public static void sort(Comparable[] a) {
    
    
        // 确定增长量gap的最大值
        int gap = 1;
        while (gap < a.length / 2) {
    
    
            gap = gap * 2 + 1;
        }

        // 当增长量gap小于1,排序结束
        while (gap >= 1) {
    
    
            // 找到待插入的元素
            for (int i = gap; i < a.length; i++) {
    
    
                // a[i]就是待插入的元素
                // 把a[i]插入到a[i-h],a[i-2h],a[i-3h]...序列中
                for (int j = i; j >= gap; j -= gap) {
    
    
                    // a[i]就是待插入的元素素,依次和a[j-h],a[j-2h],a[j-3h]进行比较,
                    // 如果a[j]小,那么 交换位置,如果不小于,a[j]大,则插入完成。
                    if (greater(a[j - gap], a[j])) {
    
    
                        exch(a, j, j - gap);
                    } else {
    
    
                        break;
                    }
                }
            }
            gap/=2;
        }
    }

    // 比较v是否大于w
    private static boolean greater(Comparable v, Comparable w) {
    
    
        return v.compareTo(w) > 0;
    }

    // 交换
    private static void exch(Comparable[] a, int i, int j) {
    
    
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

1.3 测试

public class ShellSortTest {
    
    
    public static void main(String[] args) {
    
    
        String[] arr = {
    
    "aa","bb","mm","zz","dd","cc"};
        ShellSort.sort(arr);
        for (String s : arr) {
    
    
            System.out.print(s+" ");
        }
    }
}

二、归并排序

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。
在这里插入图片描述

2.1 API设计

类名 MergeSort
构造方法 MergeSort():创建MergeSort对象
成员方法 1.public static void sort(Comparable[] a):对数组内的元素进行排序
2.private static void sort(Comparable[] a, int lo, int hi):对数组a中从索引lo到索引hi之间的元素进行排序
3.private static void merge(Comparable[] a, int lo, int mid, int hi):从索引lo到所以mid为一个子组,从索引mid+1到索引hi为另一个子组,把数组a中的这两个子组的数据合并成一个有序的大组(从索引lo到索引hi)
4.private static boolean less(Comparable v,Comparable w):判断v是否小于w
5.private static void exch(Comparable[] a,int i,int j):交换a数组中,索引i和索引j处的值
成员变量 1.private static Comparable[] assist:完成归并操作需要的辅助数组

2.2 实现

/**
 * 归并排序是分治思想的最典型的例子
 */
public class MergeSort {
    
    
    private static Comparable[] assist;//归并所需要的辅助数组

    // 排序
    public static void sort(Comparable[] a) {
    
    
        assist = new Comparable[a.length];
        int lo = 0;
        int hi = a.length - 1;
        sort(a, lo, hi);
    }

    // 对数组a中从lo到hi的元素进行排序
    private static void sort(Comparable[] a, int lo, int hi) {
    
    
        if (hi <= lo) {
    
    
            return;
        }

        int mid = lo + (hi - lo) / 2;

        // 对lo到mid之间的元素进行排序
        sort(a, lo, mid);
        // 对mid+1到hi之间的元素进行排序
        sort(a, mid + 1, hi);
        // 对lo到mid这组数据和mid到hi这组数据进行归并
        merge(a, lo, mid, hi);
    }

    // 对数组中,从lo到mid为一组,从mid+1到hi为一组,对这两组数据进行归并
    private static void merge(Comparable[] a, int lo, int mid, int hi) {
    
    
        // lo到mid这组数据和mid+1到hi这组数据归并到辅助数组assist对应的索引处
        int i = lo; // 定义一个指针,指向assist数组中开始填充数据的索引
        int p1 = lo; // 定义一个指针,指向第一组数据的第一个元素

        int p2 = mid + 1; // 定义一个指针,指向第二组数据的第一个元素

        // 比较左边小组和右边小组中的元素大小,哪个小,就把哪个数据填充到assist数组中
        while (p1 <= mid && p2 <= hi) {
    
    
            if (less(a[p1], a[p2])) {
    
    
                assist[i++] = a[p1++];
            } else {
    
    
                assist[i++] = a[p2++];
            }
        }

        // 上面的循环结束后,如果推出循环的条件是p1<=mid,则证明左边小组中的数据已经归并完毕,如果退出循环的条件是p2<=hi,则证明
        // 右边小组的数据已经填充完毕
        // 所以需要把未填充完毕的数据继续填充到ssist中,下面两个循环,会执行其中的一个
        while (p1 <= mid) {
    
    
            assist[i++] = a[p1++];
        }
        while (p2 <= hi) {
    
    
            assist[i++] = a[p2++];
        }
        
        // 到现在为止,assist数组中,从lo到hi的数组是有序的,再把数据拷贝到a数组中对应的索引处
        for (int index=lo;index<=hi;index++){
    
    
            a[index] = assist[index];
        }
    }

    // 比较
    private static boolean less(Comparable v, Comparable w) {
    
    
        return v.compareTo(w) < 0;
    }

    // 交换
    private static void exch(Comparable[] a, int i, int j) {
    
    
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

2.3 测试

public class MergeSortTest {
    
    
    public static void main(String[] args) {
    
    
        String[] arr = {
    
    "aa","bb","mm","zz","dd","cc"};
        MergeSort.sort(arr);
        for (String s : arr) {
    
    
            System.out.print(s+" ");
        }
    }
}

三、快速排序

快速排序是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
在这里插入图片描述

3.1 API设计

类名 QuickSort
构造方法 QuickSort():创建QuickSort对象
成员方法 1.public static void sort(Comparable[] a):对数组内的元素进行排序
2.private static void sort(Comparable[] a, int lo, int hi):对数组a中从索引lo到索引hi之间的元素进行排序
3.public static int partition(Comparable[] a,int lo,int hi):对数组a中,从索引 lo到索引 hi之间的元素进行分组,并返回分组界限对应的索引
4.private static boolean less(Comparable v,Comparable w):判断v是否小于w
5.private static void exch(Comparable[] a,int i,int j):交换a数组中,索引i和索引j处的值

3.2 实现

public class QuickSort {
    
    

    // 排序
    public static void sort(Comparable[] a) {
    
    
        int lo = 0;
        int hi = a.length - 1;
        sort(a, lo, hi);
    }

    // 对数组a中从索引lo到索引hi之间的元素进行排序
    private static void sort(Comparable[] a, int lo, int hi) {
    
    
        if (hi <= lo) {
    
    
            return;
        }
        // 对a数组中,从lo到hi的元素进行切分
        int partition = partition(a, lo, hi);
        // 对左边分组中的元素进行排序
        sort(a, lo, partition - 1);
        // 对右边分组中的元素进行排序
        sort(a, partition + 1, hi);
    }

    // 对数组a中,从索引 lo到索引 hi之间的元素进行分组,并返回分组界限对应的索引
    public static int partition(Comparable[] a, int lo, int hi) {
    
    
        Comparable key = a[lo];// 把最左边的元素当做基准值
        int left = lo;// 定义一个左侧指针,初始指向最左边的元素
        int right = hi + 1;// 定义一个右侧指针,初始指向左右侧的元素下一个位置
        //进行切分
        while (true) {
    
    
            // 先从右往左扫描,找到一个比基准值小的元素
            while (less(key, a[--right])) {
    
    //循环停止,证明找到了一个比基准值小的元素
                if (right == lo) {
    
    
                    break; //已经扫描到最左边了,无需继续扫描
                }
            }

            //再从左往右扫描,找一个比基准值大的元素
            while (less(a[++left], key)) {
    
    //循环停止,证明找到了一个比基准值大的元素
                if (left == hi) {
    
    
                    break;//已经扫描到了最右边了,无需继续扫描
                }
            }

            if (left >= right) {
    
    
                //扫描完了所有元素,结束循环
                break;
            } else {
    
    
                //交换left和right索引处的元素
                exch(a, left, right);
            }
        }

        //交换最后rigth索引处和基准值所在的索引处的值
        exch(a, lo, right);
        return right;//right就是切分的界限
    }

    // 比较
    private static boolean less(Comparable v, Comparable w) {
    
    
        return v.compareTo(w) < 0;
    }

    // 交换
    private static void exch(Comparable[] a, int i, int j) {
    
    
        Comparable t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
}

3.3 测试

public class QuickSortTest {
    
    
    public static void main(String[] args) {
    
    
        String[] arr = {
    
    "aa","bb","mm","zz","dd","cc"};
        QuickSort.sort(arr);
        for (String s : arr) {
    
    
            System.out.print(s+" ");
        }
    }
}

Guess you like

Origin blog.csdn.net/m0_46218511/article/details/118176974