算法 基于数据交换的排序

一、时间复杂度为o(n^2)

1.1 冒泡排序

  • 每进行一轮冒泡排序就将最大值放到后面
  • 需每次比较相邻的值取得最大值
 public static void sort(int[] array){
        int len = array.length;
        for (int i = 0; i < len - 1; i++) {
            for(int j = 0; j < len - i - 1; j++){
                if(array[j+1] > array[j]){
                    int mid = 0;
                    mid = array[j+1];
                    array[j+1] = array[j];
                    array[j] = mid;
                }
            }
        }
    }

1.2 选择排序

  • 第一轮选择最小的数与第一个位置的数进行交换
  • 第二轮选择最小的数与第二个位置的数进行交换

思路:每轮找到最小的值与前面的值进行交换

public static void sort(int[] list){
      for (int i = 0; i < list.length; i++) {
          int tmp = list[0];
          int index = 0;
          for (int j = 0; j < list.length - i ; j++) {
             if(list[j] > tmp){
                 tmp = list[j];
                 index = j;
             }
          }
          int tmp1 = list[index];
          list[index] = list[list.length - i - 1];
          list[list.length - i - 1] = tmp1;
      }
  }

1.3 插入排序

  • 从第二个数开始,将数插到前面合适的位置,当前数的位置是index,从前一个数开始,依次与当前数进行比较,大于当前数,往后移动一位,当前数占坑

特点:

  • 假设要插入的数时A,则排序的是A及A以前的数,后面的数涉及不到
  • 可能需要移动大量数据

时间复杂度:o(n^2)

public static void sort(int[] arrays) {
        for (int i = 1; i < arrays.length; i++) {
            int tmp = arrays[i];
            for (int j = i-1; j >=0; j--) {
                if(arrays[j] > tmp){
                    arrays[j+1] = arrays[j];
                    arrays[j] = tmp;
                }else {
                    continue;
                }
            }
        }
    }
  • 第二种好理解
 public static void sort(int[] arr) {
        for (int i = 1; i < arr.length; i++) {
            int j = i - 1 ;
            while (j >= 0 && arr[j] > arr[i]) {
                j--;
            }
            if(j < 0){
                int tmp = arr[i];
                for(int k = i - 1; k >= 0 ; k --){
                    arr[k+1] = arr[k];
                }
                arr[0] = tmp;
            }else {
                int tmp = arr[i];
                for(int k = i - 1; k > j ; k --){
                    arr[k+1] = arr[k];
                }
                arr[j + 1] = tmp;
            }
        }
    }

二、时间复杂度为o(N*logN)的算法

2.1 归并排序

  • 先把数组拆分
  • 分好后进行合并运算

注意:(int)3/2 = 1

 public static void sort(int[] list, int start, int end){
      if(end - start < 1){
          return;
      }
      sort(list,start,(end+start)/2);
      sort(list, (end+start)/2 + 1, end);
      merge(list,start,(end+start)/2,(end+start)/2 + 1, end);

  }
  public static void merge(int[] list, int start1, int end1, int start2, int end2){
      int[] tmp = new int[end2 - start1 + 1];
      int s1 = start1;
      int s2 = start2;
      int i = 0;
      while (s1 <= end1 && s2 <= end2){
          if(list[s1] <= list[s2]){
              tmp[i++] = list[s1++];
          }else {
              tmp[i++] = list[s2++];
          }
      }
      while (s1 <= end1){
          tmp[i++] = list[s1++];
      }
      while (s2 <= end2){
          tmp[i++] = list[s2++];
      }
      for (int j = 0; j < tmp.length; j++) {
          list[j + start1] = tmp[j];
      }
  }

参考:归并排序

2.2 快速排序

  • 空间复杂度:o(logN)~o(N)

要点:

  • 在程序第一步要判断(start < end),不然数组中只有一个元素时,会造成死循环。
  • array[low] 赋值给array[high]时,也要判断high和low的关系。
  • 判断数组边界时,尽量不要使用等于号,可能会造成栈溢出。
    *已经排序号好的不需要再排序
    赋值的时候一定要判断left<right
 public static void sort(int[] list, int start, int end){
      if(start >= end){
          return;
      }
      int tmp = list[start];
      int left = start;
      int right = end;
      while (left < right){
          while (list[right] > tmp && left < right){
              right --;
          }
          if(left < right) {
              list[left++] = list[right];
          }
          while (list[left] < tmp && left < right){
              left++;
          }
          if(left < right) {
              list[right++] = list[left];
          }
      }
      list[right] = tmp;
      sort(list, start, right - 1);
      sort(list, right + 1, end);
  }

2.3 堆排序

参考:堆排序算法
初始堆建立堆

思路:首先要进行堆初始化,即从最后一个非叶子结点调整堆,这样的结果是次大值维持在第二层,这样在节点数量减少时,可以从头结点初始堆。

 public static void sort(int[] array) {
        int length = array.length;
        //从最后一个父节点往上调整堆,调整堆时,一个堆拥有的头结点数时总节点数的一半-1,从0开始
        //调整初始堆
        for (int i =  length / 2 - 1; i >= 0; i--) {
            adjustHeap(array, length, i);
        }
        //每次将头结点与最后一个节点进行交换
        for (int i = length - 1; i >= 0; i--) {
            int mid = array[i];
            array[i] = array[0];
            array[0] = mid;
            adjustHeap(array,i,0);
        }

    }

    /**
     *
     * @param array
     * @param length 要调整的堆中元素的个数
     * @param i 传过来的父节点
     *
     */
    private static void adjustHeap(int[] array, int length, int i) {
        //调整的策略是:将一个父节点和两个子节点中最大的值给父节点
        //2*i+1:父节点的左子节点,2*i+2:父节点的右子节点
        //flag指向头结点
        //index指向右子节点
        int flag = i;
        int index = 2*i + 1;
        int value = array[i];
        //比较两个子节点的较大值
        while (index < length){
            if(index + 1 < length){
                if(array[index + 1] > array[index]){
                    index = index + 1;
                }
            }
            if(array[flag] < array[index]){
                int mid = array[flag];
                array[flag] = array[index];
                array[index] = mid;
                flag = index;
                index = 2*index + 1;
            }else {
                break;
            }
        }
    }

2.4 希尔排序

  • 插入排序的优化
    需自定义规定步长,步长逐渐缩小,就能逐渐排序
  public static void sort(int[] array) {
        for (int i = 1; i <= 3; i++) {
            foot(array,i);
        }
    }
    public static void foot(int[] array, int n){
        for (int i = n; i < array.length; i++) {
            for(int j = i; j >= 0; j = j - n){
                if(j - n >= 0 && array[j] > array[j - n]){
                    int mid = array[j-n];
                    array[j - n] = array[j];
                    array[j] = mid;
                }
            }
        }
    }
  • 第二种解法
public static void sort(int[] arrays) {
        for (int gap = arrays.length / 2; gap > 0; gap /= 2) {
            for (int i = gap; i < arrays.length; i++) {
                int tmp = arrays[i];
                for (int j = i - gap; j >= 0; j = j - gap) {
                    if (arrays[j] > tmp) {
                        arrays[j + gap] = arrays[j];
                        arrays[j] = tmp;
                    }else {
                        continue;
                    }
                }
            }
        }
    }

三、8种排序的比较

3.1 复杂度

在这里插入图片描述

3.2 参考

8种排序的比较

3.3 时间复杂度

  • 冒泡排序最好的时间复杂度只需要比较一轮,因此最优的时间复杂度是o(n)。
  • 选择排序最好的时间复杂度也要进行n轮比较,确定每轮的最小的值,因此是o(n^2)。
  • 插入排序,最优每轮插入一个,无需移动,因此最优的时间复杂度是0(n)

在这里插入图片描述

  • K是整数的范围
  • 桶排序不了解,就记住一个计数和基数
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值