排序算法总结

2019-07-20

import java.net.Socket;
import java.util.Arrays;
import java.util.ConcurrentModificationException;

/**
 * @ClassName SortDemo
 * @Author wangyudi
 * @Date 2019/7/20 14:44
 * @Version 1.0
 * @Description
 */
public class SortDemo {
    /**
     * 选择排序:每次选择排列一个位置
     * 注意点:数组最后一个位置不需要选择
     * 每次和最小值进行比较
     *
     * @param a
     */
    public void selectSort(Comparable[] a) {
        if (a == null) return;
        int length = a.length;
        if (a.length == 0 || a.length == 1) return;

        int min = 0;//每次选择排序中,最小数的索引值
        for (int i = 0; i < length - 1; i++) {
            min = i;//用于记录最小值所在的索引
            for (int j = i + 1; j < length; j++) {
                if (less(a[j], a[min])) min = j; //注意
            }
            exch(a, i, min);
        }
    }

    ;

    /**
     * 插入排序:将当前指针所指的元素插入到前面的排序数组中
     * 注意点:插入排序从索引为1 的元素开始插入排序
     *
     * @param arr
     */
    public void insertSort(Comparable[] arr) {
        if (arr == null) return;
        int length = arr.length;
        if (arr.length == 0 || arr.length == 1) return;
        for (int i = 1; i < length; i++) {
            for (int j = i; j > 0 && less(arr[j], arr[j - 1]); --j) {
                exch(arr, j, j - 1);
            }
        }
    }

    /**
     * 希尔排序:将数组以h为间隔分为若干个数组;解决了插入排序中,交换次数过多的情况
     * 注意点:最后一次希尔排序h为1;
     *
     * @param arr
     */
    public void hillSort(Comparable[] arr) {
        if (arr == null) return;
        int length = arr.length;
        if (arr.length == 0 || arr.length == 1) return;
        int h = 1;
        while (h < length / 3) h *= 3;
        while (h >= 1) {
            for (int i = h; i < length; i++) {
                for (int j = i; j > h - 1 && less(arr[j], arr[j - h]); j -= h) {
                    exch(arr, j, j - h);
                }
            }
            h = h / 3;
        }
    }

    /**
     * 归并排序(递归):将数组不断地等分,然后归并;
     * 归并:将两个有序的数组归并后任然是有序数组
     * 这里使用的是非原地归并,为了避免在归并排序中平频繁地创建数组,这里初始时创建了和输入数组一样大的数组
     *
     * @param arr
     */
    public void mergeSort(Comparable[] arr) {
        if (arr == null) return;
        int length = arr.length;
        if (arr.length == 0 || arr.length == 1) return;
        Comparable[] temp = new Comparable[length]; //用于归并的辅助数组
        mergeSortCore(arr, 0, length - 1, temp);
    }

    private void mergeSortCore(Comparable[] arr, int lo, int hi, Comparable[] temp) {
        if (lo >= hi) return;
        int mid = lo + (hi - lo) / 2;
        mergeSortCore(arr, lo, mid, temp);
        mergeSortCore(arr, mid + 1, hi, temp);
        merge(arr, lo, mid, hi, temp);
    }

    private void merge(Comparable[] arr, int lo, int mid, int hi, Comparable[] temp) {
        for (int i = lo; i <= hi; i++) {
            temp[i] = arr[i];
        }
        int p = lo;
        int q = mid + 1;
        for (int i = lo; i <= hi; i++) {
            if (p > mid) arr[i] = temp[q++];
            else if (q > hi) arr[i] = temp[p++];
            else if (less(arr[p], arr[q])) arr[i] = temp[p];
            else arr[i] = temp[q];
        }
    }

    /**
     * 归并排序(自下而上):从11 22 44合并数组
     */

    public void mergeSort2(Comparable[] arr) {
        if (arr == null) return;
        int length = arr.length;
        if (arr.length == 0 || arr.length == 1) return;
        Comparable[] temp = new Comparable[length];
        for (int size = 1; size < length; size *= 2) { //遍历所有长度的子数组 1,2,4,8……
            for (int i = 0; i < length - size; i = i + 2 * size) {//遍历所有需要遍历的两个子数组
                merge2(arr, i, i + size - 1, min(i + 2 * size - 1, length - 1), temp);
            }
        }
    }

    private int min(int a, int b) {
        return a < b ? a : b;
    }

    private void merge2(Comparable[] arr, int lo, int mid, int hi, Comparable[] temp) {
        for (int i = lo; i <= hi; i++) {
            temp[i] = arr[i];
        }
        int p = lo;
        int q = mid + 1;
        for (int i = lo; i <= hi; i++) {
            if (p > mid) arr[i] = temp[q++];
            else if (q > hi) arr[i] = temp[p++];
            else if (less(arr[p], arr[q])) arr[i] = temp[p];
            else arr[i] = temp[q];
        }
    }

    /**
     * 快速排序:选择排序数组中的一个数,然后对其进行分割
     */
    public void quickSort(Comparable[] arr) {
        if (arr == null) return;
        int length = arr.length;
        if (arr.length == 0 || arr.length == 1) return;
        quickSortCore(arr, 0, length - 1);
    }

    public void quickSortCore(Comparable[] arr, int lo, int hi) {
        if (lo >= hi) return;
        int mid = partition(arr, lo, hi);
        quickSortCore(arr, lo, mid - 1);
        quickSortCore(arr, mid + 1, hi);
    }

    /**
     * 将数组切分,并返回切分比较值所在的索引
     *
     * @param arr
     * @param lo
     * @param hi
     * @return
     */
    private int partition(Comparable[] arr, int lo, int hi) {
        Comparable v = arr[lo];
        int i = lo;
        int j = hi + 1;
        while (true) {
            //i指向数组范围内比基准数大的值,或者数组最后一个元素
            //j指向数组范围内比基准数小的值,或者数组第一个元素
            while (arr[++i].compareTo(v) <= 0) if (i == hi) break;
            while (arr[--j].compareTo(v) >= 0) if (j == lo) break;
            if (i >= j) break;
            exch(arr, i, j);
        }
        exch(arr, lo, j);
        return j;
    }


    /**
     * 三向切分 快速排序方法:适用于数组中有大量相同元素的排序算法
     * 将数组分为 小于 等于 大于三部分
     * partition3Way 需要两个指针和遍历指针
     */
    public void quickSort3Way(Comparable[] arr) {
        if (arr == null) return;
        int length = arr.length;
        if (arr.length == 0 || arr.length == 1) return;
        quickSort3WayCore(arr, 0, length - 1);
    }

    private void quickSort3WayCore(Comparable[] arr, int lo, int hi) {
        if (lo >= hi) return;
        int[] result = partition3Way(arr, lo, hi);
        quickSort3WayCore(arr, lo, result[0] - 1);
        quickSort3WayCore(arr, result[1] + 1, hi);

    }

    private int[] partition3Way(Comparable[] arr, int lo, int hi) {
        int lp = lo;//指向小于部分尾部
        int gp = hi;//指向大于部分头部
        Comparable value = arr[lo];
        int i=lo+1;
        while(i<=gp) { //i是用于遍历数组来切分的指针变量
            int cmp = arr[i].compareTo(value);
            if (cmp > 0) {//arr[i]比较大
                exch(arr, i, gp--);
            } else if (cmp < 0) {
                exch(arr, lp++, i++); //注意,这里会调节数组
            }
        }
        int[] result = new int[]{lp, gp};
        return result;
    }

    /**
     * 堆排序:用一个数组实现最大堆(最大优先队列)
     * 注意点:保存数据的第一个索引没有使用
     * 这里实现的堆排序中,使用了数组的第一个元素 k 2k+1 2k+2
     *
     * @param arr
     */
    public void heapSort(Comparable[] arr) {
        if (arr == null) return;
        int length = arr.length;
        if (arr.length == 0 || arr.length == 1) return;
        //堆有序化, 从倒数第二排开始 sink
        for (int i = (length - 1) / 2; i >= 0; i--) {
            sink(arr, i, length - 1);
        }
        //排序,将堆顶最大的数交换到数组的末尾,然后堆顶数据sink
        int last = length - 1;
        while(last!=0){
            exch(arr,0,last--);
            sink(arr,0,last);
        }
    }

    private void sink(Comparable[] arr, int k, int last) {
        while ((2 * k + 1) <= last) { //有子节点
            int j = 2 * k + 1;
            if ((j + 1) <= last) if (arr[j].compareTo(arr[j + 1]) < 0) j += 1; //去子节点中的较大者
            if (arr[k].compareTo(arr[j]) >= 0) break;
            exch(arr, k, j);
            k = j; //替换比较对象索引
        }
    }

    /**
     * 交换
     *
     * @param a
     * @param i
     * @param j
     */
    public static void exch(Comparable[] a, int i, int j) {
        Comparable temp;
        temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }

    /**
     * 比较
     *
     * @param a
     * @param b
     * @return
     */
    public static boolean less(Comparable a, Comparable b) {
        return a.compareTo(b) < 0;
    }

    /**
     * 显示当前数组
     *
     * @param a
     */
    public static void show(Comparable[] a) {
        System.out.println(Arrays.toString(a));
    }

    /**
     * 判断数组是否有序
     *
     * @param a
     * @return
     */
    public static boolean isSorted(Comparable[] a) {
        for (int i = 0; i < a.length - 1; i++) {
            if (a[i].compareTo(a[i + 1]) > 0) {
                System.out.println("false");
                return false;
            }
        }
        System.out.println("true");
        return true;
    }
}


class TestCase {
    public static void main(String[] args) {
        SortDemo sortDemo = new SortDemo();
        Integer[] a = new Integer[]{34, 2, 5, 4, 45, 6, 22};
//        sortDemo.selectSort(a);
//        SortDemo.isSorted(a);

//        sortDemo.insertSort(a);
//        SortDemo.isSorted(a);

//        sortDemo.mergeSort(a);
//        SortDemo.isSorted(a);

//        sortDemo.mergeSort2(a);
//        SortDemo.isSorted(a);

//        sortDemo.quickSort(a);
//        SortDemo.isSorted(a);

//        sortDemo.quickSort3Way(a);
//        SortDemo.isSorted(a);

//        sortDemo.heapSort(a);
//        SortDemo.isSorted(a);
    }
}

 

上一篇:[I cannot be cast to java.lang.Comparable


下一篇:java – 在接口中实现Comparable