左神视频day02——插入排序、选择排序、随机快速排序、堆排序

1. 随机快速排序(不稳定)

  • l + (int) (Math.random() * (r - l + 1)) 解析:
    • 假设 l = 4,r = 9
    • 目的:随机选择 4 ~ 9 之间的一个数,使它与末尾的数交换位置
    • Math.random() * ( 9 - 4 )所得出的范围是 [ 0 , 4 ]
    • Math.random() * ( 9 - 4 + 1 )所得出的范围是 [ 0 , 5 ] ,所以这里采用 r - l + 1
    • l + (int) (Math.random() * (r - l + 1)) 表示的则是 [ 4 , 9 ] 之间的数,符合题意
    • partition 方法的作用是先将与所选随机值相同的值放在一起,然后得到它们的范围。假设是 1,3,4,5,5,5,5,6,8 ,则 p[0] 表示第一个5,p[1] 表示最后一个5
    • if (arr[l] < arr[r]) { swap(arr, ++less, l++ ); 这一步交换的意义是:当前面找到和 5 相同的值时,l++,那么后面执行这个交换操作可以把前面找到的 5 往后面移,以此将5移动到一块。
    • less 表示小于 5 的区域,最开始里面是空,所以 less = l-1
    • more 表示大于 5 的区域,最开始里面只有最右边的值(5),所以 more = r 。循环结束后通过 swap(arr, more, r); 将最后面的 5 加入到前面集结好的 555 的末尾处。
    • 由于是随机在中间取的值(假设是5)与末尾值进行的交换,然后用这个末尾值开始普通快排,所以它的时间复杂度是 O(nlogn) 。
    • 快排常数项的操作和数量很少,所以它被广泛使用。
public class QuickSort {

    public static void quickSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        quickSort(arr, 0, arr.length - 1);
    }

    public static void quickSort(int[] arr, int l, int r) {
        if (l < r) {
            swap(arr, l + (int) (Math.random() * (r - l + 1)), r);
            int[] p = partition(arr, l, r);
            quickSort(arr, l, p[0] - 1);
            quickSort(arr, p[1] + 1, r);
        }
    }

    public static int[] partition(int[] arr, int l, int r) {
        int less = l - 1;
        int more = r;
        while (l < more) {
            if (arr[l] < arr[r]) {
                swap(arr, ++less, l++);
            } else if (arr[l] > arr[r]) {
                swap(arr, --more, l);
            } else {
                l++;
            }
        }
        swap(arr, more, r);
        return new int[]{less + 1, more};
    }

    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static void main(String[] args) {
        QuickSort sort = new QuickSort();
        int[] arr = {5, 3, 5, 6, 1, 4, 5, 8, 5};
        sort.quickSort(arr);

        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + ","); //1,3,4,5,5,5,5,6,8
        }
    }
}

2. 堆排序(不稳定)

public class HeapSort {

    public static void heapSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        for (int i = 0; i < arr.length; i++) {
            heapInsert(arr, i);
        }
        int size = arr.length;
        swap(arr, 0, --size);
        while (size > 0) {
            heapify(arr, 0, size);
            swap(arr, 0, --size);
        }
    }

    public static void heapInsert(int[] arr, int index) {
        while (arr[index] > arr[(index - 1) / 2]) {
            swap(arr, index, (index - 1) / 2);
            index = (index - 1) / 2;
        }
    }

    public static void heapify(int[] arr, int index, int size) {
        int left = index * 2 + 1;
        while (left < size) {
            int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
            largest = arr[largest] > arr[index] ? largest : index;
            if (largest == index) {
                break;
            }
            swap(arr, largest, index);
            index = largest;
            left = index * 2 + 1;
        }
    }

    public static void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static void main(String[] args) {
        HeapSort a = new HeapSort();
        int[] arr = {3, 2, 4, 5, 9, 6, 4, 7, 8, 4, 1};
        a.heapSort(arr);
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + ","); //1,2,3,4,4,4,5,6,7,8,9
        }
    }
}

3.插入排序(稳定)

  • 将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n2)。是稳定的排序方法。类似于玩扑克牌,手里的牌都排好序了,每抽一张牌时便将它插入到合适的位置,使手里的扑克牌一直有序。

4.选择排序(不稳定)

  • 每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法。

你可能感兴趣的:(左神视频笔记)