• 算法


    冒泡排序

    public static void bubbleSort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        for (int i = arr.length - 1; i > 0; i--) {
            for (int j = 0; j < i; j++) {
                if (arr[j] > arr[j + 1]) {
                    swap(arr, j);
                }
            }
        }
    }
    

    冒泡排序比较简单,但是容易出现冗余的循环,即使是一个已经排序的数组传入仍然需要遍历 O(n ^ 2)。

    选择排序

    public static void selectSort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        for (int i = 0; i < arr.length - 1; i++) {
            int min = i;
            for (int j = i + 1; j < arr.length; j++) {
                if (arr[min] > arr[j]) {
                    min = j;
                }
            }
            if (i != min) {
                swap(arr, i, min);
            }
        }
    }
    

    选择排序时间复杂度也是 O(n ^ 2)。

    插入排序

    public static void insertSort(int[] arr) {
        if (arr == null || arr.length < 2) return;
        for (int i = 1; i < arr.length; i++) {
            for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--) {
                swap(arr, j, j + 1);
            }
        }
    }
    

    插入排序,有可能是 O(n) 也有可能是 O(n^2),和数据是否已经有序有关。

    希尔排序

    public static void shellSort(int[] array) {
        int gap = array.length;
        while (true) {
            if (gap == 1) {
                break;
            }
            gap /= 2;
            for (int i = gap; i < array.length; i++) {
                for (int j = i; j - gap >= 0; j = j - gap) {
                    if (array[j] < array[j - gap]) {
                        swap(array, j, j - gap);
                    }
                }
            }
        }
    }
    

    希尔排序的关键是步长的选择,时间复杂度为 O(n3/2)。

    归并排序

    public static void mergeSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        mergeSort(arr, 0, arr.length - 1);
    }
    
    
    public static void mergeSort(int[] arr, int l, int r) {
        if (l == r) {
            return;
        }
        int mid = l + ((r - l) >> 2);
        mergeSort(arr, l, mid);
        mergeSort(arr, mid + 1, r);
        merge(arr, l, mid, r);
    }
    
    public static void merge(int[] arr, int l, int m, int r) {
        //这个数组是临时生成的,使用过后又马上销毁,最大的长度为排序数组的长度,所以额外空间为 O(n)
        int[] helper = new int[r - l + 1];
        int i = 0;
        int p1 = l;
        int p2 = m + 1;
        while (p1 <= m && p2 <= r) {
            helper[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
        }
        //下面两个循环有且只有一个会执行
        while (p1 <= m) {
            helper[i++] = arr[p1++];
        }
        while (p2 <= r) {
            helper[i++] = arr[p2++];
        }
        //需要注意 l 为归并的左边界,不是定值 0
        for (int j = 0; j < helper.length; j++) {
            arr[l + j] = helper[j];
        }
    }
    

    归并排序使用了递归的方式,利用 master 公式可以分析分治思路算法的时间复杂度。关于 master 公式可以参看这篇文章。归并排序使用了额外的存储空间,时间复杂度为 O(n * logn),空间复杂度为 O(n)。

  • 相关阅读:
    CodeForces gym Nasta Rabbara lct
    bzoj 4025 二分图 lct
    CodeForces 785E Anton and Permutation
    bzoj 3669 魔法森林
    模板汇总——快读 fread
    bzoj2049 Cave 洞穴勘测 lct
    bzoj 2002 弹飞绵羊 lct裸题
    HDU 6394 Tree 分块 || lct
    HDU 6364 Ringland
    nyoj221_Tree_subsequent_traversal
  • 原文地址:https://www.cnblogs.com/chenxianbin/p/11874236.html
Copyright © 2020-2023  润新知