• 算法


    要点:先递归向下拆分,再递归向上合并,合并后的元素是有序的,分而治之的思想。

    为了理解起来简单,算法内部多了数组的创建过程。是可以优化的,可以看一下其它的归并版本。

      1 public class MergeSort<T extends Comparable> {
      2 
      3     private T[] sort(T[] arr, int left, int right) {
      4         // 拆分中点
      5         int middle = (right + left) / 2;
      6         // 如果只有一个数,即左标右标相等,跳出递归
      7         if (left == right) {
      8             return (T[]) new Comparable[]{arr[left]};
      9         }
     10         printSplit(arr, left, middle);
     11         // 左子列递归
     12         T[] leftArr = sort(arr, left, middle);
     13         printSplit(arr, middle + 1, right);
     14         // 右子列递归
     15         T[] rightArr = sort(arr, middle + 1, right);
     16         // 合并
     17         return merge(leftArr, rightArr);
     18     }
     19 
     20     private T[] merge(T[] leftArr, T[] rightArr) {
     21         int lengthLeft = leftArr.length;
     22         int lengthRight = rightArr.length;
     23         // 左子列的游标
     24         int left = 0;
     25         // 右子列的游标
     26         int right = 0;
     27         // 新建数组的游标
     28         int cur = 0;
     29         // 新建放合并元素的数组
     30         T[] mergeArr = (T[]) new Comparable[leftArr.length + rightArr.length];
     31         // 放满了就退出
     32         while (cur < mergeArr.length) {
     33             // 右标移动到末尾了,就把左子列的都放到数组里
     34             if (right == lengthRight) {
     35                 while (left < lengthLeft) {
     36                     mergeArr[cur] = leftArr[left];
     37                     left++;
     38                     cur++;
     39                 }
     40             }
     41             // 左子列的数比右子列的小,放到数组里,移动游标
     42             while (left < lengthLeft && leftArr[left].compareTo(rightArr[right]) <= 0) {
     43                 mergeArr[cur] = leftArr[left];
     44                 left++;
     45                 cur++;
     46             }
     47             // 左子列移动到末尾了,就把右子列的都放到数组里
     48             if (left == lengthLeft) {
     49                 while (right < lengthRight) {
     50                     mergeArr[cur] = rightArr[right];
     51                     right++;
     52                     cur++;
     53                 }
     54             }
     55             // 右子列的数比左子列的小,放到数组里,移动游标
     56             while (right < lengthRight && rightArr[right].compareTo(leftArr[left]) < 0) {
     57                 mergeArr[cur] = rightArr[right];
     58                 right++;
     59                 cur++;
     60             }
     61         }
     62         printMerge(mergeArr);
     63         return mergeArr;
     64     }
     65 
     66     private void printSplit(T[] arr, int left, int right) {
     67         String[] stringArr = new String[]{" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "};
     68         for (int i = left; i <= right; i++) {
     69             stringArr[i] = "*";
     70         }
     71         for (T n : arr) {
     72             System.out.print(n);
     73         }
     74         System.out.println();
     75         for (String s : stringArr) {
     76             System.out.print(s);
     77         }
     78         System.out.println(" => 拆分");
     79     }
     80 
     81     private void printMerge(T[] arr) {
     82         for (T n : arr) {
     83             System.out.print(n);
     84         }
     85         System.out.print(" => 合并");
     86         System.out.println();
     87     }
     88 
     89     public void sort(T[] arr) {
     90         Comparable[] newArr = sort(arr, 0, arr.length - 1);
     91         for (int i = 0; i < arr.length; i++) {
     92             arr[i] = (T) newArr[i];
     93         }
     94     }
     95 
     96     public static void main(String[] args) {
     97         Integer[] arr = new Integer[]{1, 3, 8, 7, 6, 9, 5, 4, 3, 2, 0};
     98         MergeSort ms = new MergeSort();
     99         ms.sort(arr);
    100     }
    101 
    102     /**
    103      * 13876954320
    104      * ******      => 拆分
    105      * 13876954320
    106      * ***         => 拆分
    107      * 13876954320
    108      * **          => 拆分
    109      * 13876954320
    110      * *           => 拆分
    111      * 13876954320
    112      *  *          => 拆分
    113      * 13 => 合并
    114      * 13876954320
    115      *   *         => 拆分
    116      * 138 => 合并
    117      * 13876954320
    118      *    ***      => 拆分
    119      * 13876954320
    120      *    **       => 拆分
    121      * 13876954320
    122      *    *        => 拆分
    123      * 13876954320
    124      *     *       => 拆分
    125      * 67 => 合并
    126      * 13876954320
    127      *      *      => 拆分
    128      * 679 => 合并
    129      * 136789 => 合并
    130      * 13876954320
    131      *       ***** => 拆分
    132      * 13876954320
    133      *       ***   => 拆分
    134      * 13876954320
    135      *       **    => 拆分
    136      * 13876954320
    137      *       *     => 拆分
    138      * 13876954320
    139      *        *    => 拆分
    140      * 45 => 合并
    141      * 13876954320
    142      *         *   => 拆分
    143      * 345 => 合并
    144      * 13876954320
    145      *          ** => 拆分
    146      * 13876954320
    147      *          *  => 拆分
    148      * 13876954320
    149      *           * => 拆分
    150      * 02 => 合并
    151      * 02345 => 合并
    152      * 01233456789 => 合并
    153      *
    154      * 136789 - 02345 => 稳定性和合并过程说明
    155      * ^      . ^     => []
    156      * ^      .  ^    => 右比左小 => [0] => 【包含赋值和移动,下同】
    157      *  ^     .  ^    => 左比右小 => [0, 1]
    158      *  ^     .   ^   => 右比左小 => [0, 1, 2]
    159      *  ^     .   ^   => 左右相等,左侧含等号,右侧不含,跳过 => [0, 1, 2]
    160      *   ^    .   ^   => 左右相等,进入 => [0, 1, 2, 3]
    161      *   ^    .    ^  => 右比左小 => [0, 1, 2, 3, 3] => 顺序未改变,稳定
    162      *   ^    .     ^ => 右比左小 => [0, 1, 2, 3, 3, 4]
    163      *   ^    .      ^=> 右比左小 => [0, 1, 2, 3, 3, 4, 5] => 右标 = 右子列长度
    164      *    ^   .       => 左子列剩余元素移入数组 => [0, 1, 2, 3, 3, 4, 5, 6]
    165      *     ^  .       => 左子列剩余元素移入数组 => [0, 1, 2, 3, 3, 4, 5, 6, 7]
    166      *      ^ .       => 左子列剩余元素移入数组 => [0, 1, 2, 3, 3, 4, 5, 6, 7, 8]
    167      *       ^.       => 左子列剩余元素移入数组 => [0, 1, 2, 3, 3, 4, 5, 6, 7, 8, 9] => 左标 = 左子列长度
    168      * 游标cur = 数组长度,退出循环,完成合并过程
    169      *
    170      * 每层遍历一遍,遍历了logn次
    171      * => 遍历次数:nlogn
    172      * => 时间复杂度:O(nlogn)
    173      * => 稳定性:稳定
    174      *
    175      */
    176 
    177 }
  • 相关阅读:
    VC实现开机自启动
    用Shell扩展实现源代码统计程序
    在(CListView)列表视图中添加右键菜单的方法
    关于打开外部程序并且发送一个按键消息 (转
    vc中运行外部程序的方法
    如何在 XCode 4.2 設定部分程式碼不使用 ARC 方式分享(转)
    Xcode调试断点不停止解决方案!(转)
    NSString+NSMutableString+NSValue+NSAraay用法汇总 (转)
    对于Retain和Assign属性的理解(转)
    基于Xcode4开发第一个iPhone程序:“Hello World”(转)
  • 原文地址:https://www.cnblogs.com/SamNicole1809/p/12793829.html
Copyright © 2020-2023  润新知