• 数据结构与算法之-归并排序算法的实现
  • 发布于 1个月前
  • 52 热度
    0 评论
原理
拆分:将数组分成2个子数组,然后对子数组继续进行拆分,直到只有单个元素为止
合并:将2个子数组中的元素依次比较放到辅助数组中,比较完成后,这2个子数组就排序好了,再将辅助数组中的元素覆盖原数组中这2个子数组索引处的元素即可

合并的原理图

示例
package wxw.mengyuan;

/**
 * 归并排序
 */
public class MergeSorting {

  // 辅助数组
  private static Comparable[] assit = null;

  /**
   * 对数组中的元素进行排序
   *
   * @param arr 要排序的数组
   */
  public static void sort(Comparable[] arr) {
    // 初始化辅助数组,与真实数组一样的长度
    assit = new Comparable[arr.length];

    // 调用重载方法进行排序
    sort(arr, 0, arr.length - 1);
  }

  /**
   * 对数组中的索引start-end的元素进行分组排序
   *
   * 原理
   * (1) 求开始索引、结束索引的中间索引
   * (2) 将数组中 [开始索引, 中间索引] 的数据作为一个群组A,内部进行再次分组
   * (3) 将数组中 [中间索引+1, 结束索引] 的数据作为一个群组B,内部进行再次分组
   *
   * @param arr 要排序的数组
   * @param start 开始索引
   * @param end 结束索引
   */
  private static void sort(Comparable[] arr, int start, int end) {
    // 当开始索引与结束索引相遇时,则结束排序
    if (end <= start) {
      return;
    }
    // 堆代码 duidaima.com
    // 求中间索引
    int mid = (start + end) / 2;

    // 分组排序
    // [开始索引, 中间索引] 的数据作为一个群组A,内部进行再次分组排序
    // [中间索引+1, 结束索引] 的数据作为一个群组B,内部进行再次分组排序
    sort(arr, start, mid);
    sort(arr, mid+1, end);

    // 将两个群组A、B进行合并排序
    merge(arr, start, mid, end);
  }

  /**
   * 合并两个群组的数据,并排序
   *
   * 原理
   * (1) 将数组中 [开始索引, 中间索引] 的数据作为一个群组A,这个群组内部是已排序好了的
   * (2) 将数组中 [中间索引+1, 结束索引] 的数据作为一个群组B,这个群组内部是已排序好了的
   * (3) 在辅助数组上指定一个索引指针i,默认指向开始索引
   * (4) 在群组A上指定一个索引指针p1,默认指向开始索引
   * (5) 在群组B上指定一个索引指针p2,默认指向 中间索引+1
   * (6) 比较群组A、B当前索引指针对应的值
   *     (A) 若群组A数据大于群组B数据,则将群组B数据放入辅助数组的索引指针i对应的数据处,群组A当前索引指针+1、辅助数组的索引指针i+1
   *     (B) 若群组B数据大于群组A数据,则将群组A数据放入辅助数组的索引指针i对应的数据处,群组B当前索引指针+1、辅助数组的索引指针i+1
   * (7) 当群组A 或 群组B中没有数据了,则将另一个群组数据全部填入辅助数组的索引指针i及其后面的数据处
   * (8) 将辅助数组中 [开始索引, 结束索引] 的数据拷贝回原数组
   *
   * @param arr 要排序的数组
   * @param start 开始索引
   * @param mid 中间索引
   * @param end 结束索引
   */
  private static void merge(Comparable[] arr, int start, int mid, int end) {
    // 定义3个指针
    // 辅助表的索引指针,从开始索引开始
    int i = start;
    // 第一个群组的索引指针,从开始索引开始
    int p1 = start;
    // 第二个群组的索引指针,从 中间索引+1 开始
    int p2 = mid + 1;

    // 若群组A、B都还有数据,则比较各自当前索引指针对应的值
    while (p1 <= mid && p2 <= end) {
      if (greater(arr[p1], arr[p2])) {
        // 群组A数据大于群组B数据
        assit[i++] = arr[p2++];
      } else {
        // 群组B数据大于群组A数据
        assit[i++] = arr[p1++];
      }
    }

    // 群组A没有数据了,将群组B的数据填入辅助数组中
    if (p1 > mid) {
      while (p2 <= end) {
        assit[i++] = arr[p2++];
      }
    }

    // 群组B没有数据了,将群组A的数据填入辅助数组中
    if (p2 > end) {
      while (p1 <= mid) {
        assit[i++] = arr[p1++];
      }
    }

    // 将辅助数组中的数据拷贝到原数组中
    System.arraycopy(assit, start, arr, start, end - start + 1);
  }

  /**
   * 比较两个元素
   *
   * @return true:第一个元素大于第二个元素;false:第一个元素不大于第二个元素
   */
  private static boolean greater(Comparable v, Comparable w) {
    return v.compareTo(w) > 0;
  }

}

用户评论