排序算法的java实现及复杂度总结1

各种排序算法总结和复杂度总结:

  1. 冒泡排序

     public static void bubbleSort(int[] arr){
            //每次都要进行类型判断防止非空操作和无效的比较操作
            if (arr == null || arr.length < 2) {
                return;
            }
    
            for (int i = 0;i < arr.length - 1;i++){
                for (int j = 0; j < arr.length - 1 -i ; j++) {
                    if (arr[j] > arr[j+1]){
                        int t;
                        t=arr[j];
                        arr[j]=arr[j+1];
                        arr[j+1]=t;
                    }
                }
            }
        }
    

    冒泡排序是每个把最大的值都放在最后面进行排序

    时间复杂度O(N^2)

    空间复杂度O(1)

  2. 对数器的概念(这个后面自己在进行总结各种对数器,看老师的给的自己总结下来)

    • 想测试的方法A
    • 绝对正确但是复杂度高的B
    • 产生一个输入的随机样本,短的就行
    • 二方法输出结果进行比较
  3. 选择排序

     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;
                    }
                }
                int t;
                t = arr[i];
                arr[i] = arr[min];
                arr[min] = t;
            }
        }
    

    选择排序是选出最小的值然后放在最前面

    时间复杂度O(N^2)

    空间复杂度O(1)

  4. 插入排序

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

    插入排序就像打牌一样,把新抓进来的数 从尾到头进行插入

  5. 递归函数的时间复杂度的估算方法

    利用到的是master公式

    T(N)=a*T(N/b)+O(N^d)

    N是原来的样本量

    N/b是子过程的样本量

    O(N^d)是除了样本量剩下的子过程的大小

    例如:

    二边递归找最大值

    T(N) = 2*T(N/2) + o(1)

    结果:

    上面的结果为O(2^log(2,2))

  6. 归并排序

    public static void mergeSort(int[] arr) {
        if (arr == null || arr.length < 2) {
            return;
        }
        mergeSort(arr, 0, arr.length - 1);
    }
    
    private static void mergeSort(int[] arr, int l, int r) {
        //递归先找出出口
        if (l == r) {//只剩下自己了一定是有序的
            return;
        }
        int mid = l + ((r - l)>>2);//等同于这个东西(l + r) / 2因为l+r可能会超过正数的范围进行溢出
        mergeSort(arr, l, mid);
        mergeSort(arr, mid + 1, r);
        merge(arr, l, mid, r);
    
    }
    
    private static void merge(int[] arr, int l, int mid, int r) {
        int[] hlep = new int[r - l + 1];//暂存数组
        int i = 0;//转移数组
        int p1 = l;//左指针标记左边的数组的开头
        int p2 = mid + 1;//右指针标记右边的开头
        while (p1 <= mid && p2 <= r) {//进行比较归并
            hlep[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
        }
        while (p1 <= mid) {//剩下的加入
            hlep[i++] = arr[p1++];
        }
        while (p2 <= r) {//剩下的加入
            hlep[i++] = arr[p2++];
        }
        //填回原来的数组中
        for (i = 0; i < r - l + 1; i++) {
            arr[l + i] = hlep[i];
        }
    }
    

    把整个序列分成二部分,分成一个的时候就已经是有序序列了,然后在进行合并就可以了

    时间复杂度这里就运用到了前面的master公式

    T(N)=2T(N/2)+O(N)

    a =2 b = 2 d= 1

    所以整个的复杂度为

    O(N*logN)

    空间复杂度O(N)//因为借用到了一个等长的额外变量进行存储中间值,所以空间复杂度是O(N)

  7. 归并排序解决实际问题-小和问题,逆序对问题

    • 小和问题:
    public static int mergeSort(int[] arr, int l, int r) {
        if (l == r) {
            return 0;
        }
        int mid = l + ((r - l) >> 2);
        return mergeSort(arr, l, mid) + mergeSort(arr, mid + 1, r) + merge(arr, l, mid, r);
    }
    
    private static int merge(int[] arr, int l, int mid, int r) {
        int[] help = new int[r - l + 1];
        int result = 0;
        int i = 0;//标记help的长度
        int p1 = l;
        int p2 = mid + 1;
        while (p1 <= mid && p2 <= r) {
            //左右二边都是有序的,如果右边的值大于当前的值,代表从这个数以后的值都大于这个值,而且右边的本来就在左边的右边
            result += arr[p1] < arr[p2] ? arr[p1] * (r - p2 + 1) : 0;
            help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
        }
        while (p1 <= mid){
            help[i++] = arr[p1++];
        }
        while ( p2 <= r) {
            help[i++] = arr[p2++];
        }
        for (int j = 0; j < help.length; j++) {
            arr[l+j] = help[j];
        }
        return result;
    }
    

    利用归并排序去解决问题,递归时找到递归出口和把大问题化成同样的小问题

    • 逆序对问题

      只更改while里面的代码既可
      while (p1 <= mid && p2 <= r) {
          //左右二边都是有序的,如果右边的值大于当前的值,代表从这个数以后的值都大于这个值,而且右边的本来就在左边的右边
          result += arr[p1] > arr[p2] ?   (mid - p1 + 1) : 0;
          help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
      }
      

    里面的help数组要改成小于等于 不然会丢失一些数,前面小和是要保证相等的时候,前面的不动,后面的动,不然也会丢失一些数据值的

posted @ 2020-12-02 10:16  蓝天白云zzz  阅读(126)  评论(0)    收藏  举报