归并排序(dart实现)

2020-11-07  本文已影响0人  锦鲤跃龙

归并排序

1945年由约翰:冯.诺伊曼(John von Neumann)首次提出

执行流程

  1. 不断的将当前序列品骏分割成两个子序列,直到不能再分割(序列中只剩下1个元素)
  2. 不断的将两个子序列合并成1个有序序列,直到最终只剩下一个有序序列

思路

dart代码


class MergeSort<T extends Comparable<T>> extends Sort<T> {
  List<T> leftCopy ;
  @override
  sort() {
    leftCopy = List(list.length>>1);//提前定义一般长度的左边长度
    _sort(0, list.length);
  }

  ///
  /// Author: liyanjun
  /// description:  对 [begin, end) 范围的数据进行归并排序
  ///
  _sort(int begin, int end) {
    if (end - begin < 2) return;
    int mid = (end + begin) >> 1; //找到中间位置
    _sort(begin, mid); //左边归并排序
    _sort(mid, end); //右边归并排序
    _merge(begin, mid, end); //合并
  }

  ///
  /// Author: liyanjun
  /// description: 归并
  ///将 [begin, mid) 和 [mid, end) 范围的序列合并成一个有序序列
  _merge(int begin, int mid, int end) {
    int leftCopyIndex = 0; //左边的数组
    int leftCopyLength = mid - begin; //左边数组长度
    int rightIndex = mid; //右边数组索引 基于原数组
    int resultIndex = begin; //覆盖的索引
    for (var i = 0; i < leftCopyLength; i++) {
      leftCopy[i]  = list[begin + i];
    } //复制左边的数组
    while (leftCopyIndex < leftCopyLength) {
      //复制的数组遍历完即可,因为两个都是有序数组
      //如果左边数组元素小于右边数组元素,将右边数组元素放在目标索引 ,反之左边数组放入目标索引
      if (rightIndex < end && cmpElement(list[rightIndex], leftCopy[leftCopyIndex]) < 0) {//考虑稳定性,所以不用等于好
        list[resultIndex] = list[rightIndex];
        rightIndex += 1; //右边数组右移动一位
      } else {
        list[resultIndex] = leftCopy[leftCopyIndex];
        leftCopyIndex += 1; //左边数组右移动一位
      }
      resultIndex += 1; //目标数组索引移动一位
    }
  }


}

执行结果

排序前 :[20, 12, 6, 20, 17, 14, 13, 4, 19, 10]
排序后 :[4, 6, 10, 12, 13, 14, 17, 19, 20, 20]
【MergeSort<num>】
耗时:0.002s (2ms)     比较:22    交换:0
-----------------

复杂度分析

归并排序花费的时间

T(n) = 2*T(n/2) + O(n)
推导过程:
\because
T(1) = O(1);
T(n)/n = T(n/2)/(n/2) + O(1);

S(n) = T(n)/n
则有
S(1)=O(1)
S(n)= S(n/2)+O(1) = S(n/4)+O(2) = S(n/8)+O(3)=S(n/2^k)+O(k)=S(1)+O(logn)= O(logn)

\therefore
T(n) = n * S(n) = n*O(logn) = O(nlogn)

由于归并排序总是平均分割子序列,所以最好、最坏、平均时间复杂度都是O(nlogn),属于稳定排序
从代码中不难看出:归并排序的空间复杂度是 O(n/2 + logn) = O(n)
n/2用于临时存放左侧数组,logn是因为递归调用

常见的递推公式和时间复杂度

递推式 时间复杂度
T(n) = T(n/2) + O(1) O(logn)
T(n) = T(n-1) + O(1) O(n)
T(n) = T(n/2) + O(n) O(n)
T(n) = 2*T(n/2) + O(1) O(n)
T(n) = 2*T(n/2) + O(n) O(nlogn)
T(n) = T(n-1) + O(n) O(n^2)
T(n) = 2*T(n-1) + O(1) O(2^n )
T(n) = 2*T(n-1) + O(n) O(2^n)
上一篇下一篇

猜你喜欢

热点阅读