Java常用的八种排序算法与代码实现(二):归并排序法、快速排序法

注:这里给出的代码方案都是通过递归完成的

---
归并排序(Merge Sort):
  分而治之,递归实现
  如果需要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分进行分别排序,再将排好序的数组合并在一起,这样整个数组就有序了
  归并排序是稳定的排序算法,时间复杂度为O(nlogn),空间复杂度是O(n)
  图解:
  在这里插入图片描述
  代码:

/**
   * 归并排序
   *
   * @param arr 待排数组
   * @param low 归并起始位置
   * @param high 归并截至位置
   */
  public static void mergeSort(int[] arr, int low, int high) {
    int mid = (low + high) / 2;
    if (low < high) {
      // 分开
      mergeSort(arr, low, mid);
      mergeSort(arr, mid + 1, high);
      // 合并
      mergeArray(arr, low, mid, high);
    }
  }

  private static void mergeArray(int[] arr, int low, int mid, int high) {
    int[] temp = new int[high - low + 1];
    // 数组被分成两部分,进行合并
    // 两个数组中的元素进行比较,小的进入temp中
    int i = low;
    int k = 0;
    int j = mid + 1;
    while (i <= mid && j <= high) {
      if (arr[i] <= arr[j]) {
        temp[k++] = arr[i++];
      } else {
        temp[k++] = arr[j++];
      }
    }
    while (i <= mid) {
      temp[k++] = arr[i++];
    }
    while (j <= high) {
      temp[k++] = arr[j++];
    }
    // 将temp数组中的数据,重新灌入被排序数组,此时数组顺序已经排好
    for (int l = 0; l < temp.length; l++) {
      arr[low + l] = temp[l];
    }
  }

注:
  空间复杂度又称渐进空间复杂度,指的是随数据量的增加,额外需要使用的空间开销。前一次归并后的数组空间,可以被接下来的操作使用。所以该排序的空间复杂度是O(n)

---
快速排序(QuockSort):
  如果需要排序数组中下标从p到r之间的一组数据,我们会选择从p到r之间的任意一个数据作为区分点,我们遍历p到r之间的数据,将小于区分点的数据放左边,大于区分点的数据放右边,然后将区分点放到中间
  快速排序是一种原地排序,不稳定的排序,时间复杂度为O(nlogn),空间复杂度是O(n)
  图解:
  在这里插入图片描述在这里插入图片描述  代码:

/**
   * 快速排序
   *
   * @param arr 待排数组
   * @param low 排序起始位置
   * @param high 排序终止位置
   */
  public static void quockSort(int[] arr, int low, int high) {
    if (low > high) {
      return;
    }
    int i = low;
    int j = high;
    int pivot = arr[low];
    while (i < j) {
      // 如果选取两端的数作为pivot,那么循环要从基数的对面开始,选取中间的基数则不需要考虑这个问题
      while (i < j && arr[j] > pivot) {
        j--;
      }
      while (i < j && arr[i] <= pivot) {
        i++;
      }
      if (i < j) {
        int c = arr[i];
        arr[i] = arr[j];
        arr[j] = c;
      }
    }
    int p = arr[i];
    arr[i] = arr[low];
    arr[low] = p;
    quockSort(arr, low, i - 1);
    quockSort(arr, i + 1, high);
  }

---
  测试方法及生成随机数组方法:

/**
   * 生成一个长度5-10的随机数组
   *
   * @return 随机数组
   */
  private static int[] initArray() {
    int len = 5 + new Random().nextInt(6);
    int[] arr = new int[len];
    for (int i = 0; i < arr.length; i++) {
      arr[i] = new Random().nextInt(100);
    }
    return arr;
  }

public static void main(String[] args) {
    int[] arr2 = initArray();
    System.out.println("排序之前的数组是:" + Arrays.toString(arr2));
    quockSort(arr2,0,arr2.length-1);
    System.out.println("排序之后的数组是:" + Arrays.toString(arr2));
  }

---
  关于 如果选取两端的数作为pivot,那么循环要从基数的对面开始 的参考博客:
https://blog.csdn.net/w282529350/article/details/50982650

---
测试结果,亲测有效:

归并:
  排序之前的数组是:[71, 79, 11, 20, 68, 78, 95]
  排序之后的数组是:[11, 20, 68, 71, 78, 79, 95]
快速:
  排序之前的数组是:[44, 25, 17, 44, 71, 25, 66, 96, 36]
  排序之后的数组是:[17, 25, 25, 36, 44, 44, 66, 71, 96]

猜你喜欢

转载自blog.csdn.net/Kirito19970409/article/details/83583583