排序算法学习(归并排序)

1.介绍

   归并排序(Merge sort)是建立在归并操作上的一种有效的排序算法。

   该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

   作为一种典型的分而治之思想的算法应用,归并排序的实现由两种方法:

        第一种:自上而下的递归(所有递归的方法都可以用迭代重写,所以就有了第 2 种方法);

        第二种:自下而上的迭代;

    在《数据结构与算法 JavaScript 描述》中,作者给出了自下而上的迭代方法。但是对于递归法,作者却认为:

        However, it is not possible to do so in JavaScript, as the recursion goes too deep for the language to handle.

        然而,在 JavaScript 中这种方式不太可行,因为这个算法的递归深度对它来讲太深了。

    说实话,我不太理解这句话。意思是 JavaScript 编译器内存太小,递归太深容易造成内存溢出吗?

    还望有大神能够指教。和选择排序一样,归并排序的性能不受输入数据的影响,但表现比选择排序好的多,

    因为始终都是 O(nlogn) 的时间复杂度。代价是需要额外的内存空间。

 

2.步骤

   第一步:申请空间,使其大小为两个已经排序序列之和,该空间用来存放合并后的序列;

   第二步:设定两个指针,最初位置分别为两个已经排序序列的起始位置;

   第三步:比较两个指针所指向的元素,选择相对小的元素放入到合并空间,并移动指针到下一位置;

   第四步:重复步骤 3 直到某一指针达到序列尾;

   第五步:将另一序列剩下的所有元素直接复制到合并序列尾。

 

3.JavaScript实现

    function mergeSort(arr) {  // 采用自上而下的递归方法
         var len = arr.length;
         if(len < 2) {
              return arr;
        }
        var middle = Math.floor(len / 2),
        left = arr.slice(0, middle),
        right = arr.slice(middle);
        return merge(mergeSort(left), mergeSort(right));
    }

    function merge(left, right)
    {
         var result = [];

         while (left.length && right.length) {
              if (left[0] <= right[0]) {
                   result.push(left.shift());
               } else {
                  result.push(right.shift());
               }
           }

          while (left.length)
               result.push(left.shift());

          while (right.length)
               result.push(right.shift());

           return result;
     }

 总结:归并算法我理解的实现

            第一步:其实是merge方法,写法是定义两个数组,如果两个数组都存在,

                         拿各自第一个元素,比较后把小的放到定义的另一个数组里面(也就是额外的内存空间)

                         不是都存在,就那其中一方了

            第二步:mergeSort方法,不停的拆分左右数组,直到只有1个元素(所谓的递归就是递归了merge方法)

            注:其实内部实现感觉也挺复杂,可以上手试试代码

 

4.Python实现

   def mergeSort(arr):
       import math
       if(len(arr)<2):
             return arr
        middle = math.floor(len(arr)/2)
        left, right = arr[0:middle], arr[middle:]
        return merge(mergeSort(left), mergeSort(right))

    def merge(left,right):
        result = []
        while left and right:
           if left[0] <= right[0]:
              result.append(left.pop(0))
           else:
              result.append(right.pop(0));
        while left:
            result.append(left.pop(0))
        while right:
            result.append(right.pop(0));
        return result

 

5.Go实现

   func mergeSort(arr []int) []int {
        length := len(arr)
        if length < 2 {
                return arr
        }
        middle := length / 2
        left := arr[0:middle]
        right := arr[middle:]
        return merge(mergeSort(left), mergeSort(right))
   }

   func merge(left []int, right []int) []int {
         var result []int
         for len(left) != 0 && len(right) != 0 {
                 if left[0] <= right[0] {
                        result = append(result, left[0])
                        left = left[1:]
                 } else {
                        result = append(result, right[0])
                        right = right[1:]
                }
         }

        for len(left) != 0 {
                result = append(result, left[0])
                left = left[1:]
        }

        for len(right) != 0 {
                result = append(result, right[0])
                right = right[1:]
        }

        return result
   }

 

6.Java实现   

     public class MergeSort implements IArraySort {

        @Override
        public int[] sort(int[] sourceArray) throws Exception {
           // 对 arr 进行拷贝,不改变参数内容
          int[] arr = Arrays.copyOf(sourceArray, sourceArray.length);

          if (arr.length < 2) {
              return arr;
          }
          int middle = (int) Math.floor(arr.length / 2);

          int[] left = Arrays.copyOfRange(arr, 0, middle);
          int[] right = Arrays.copyOfRange(arr, middle, arr.length);

         return merge(sort(left), sort(right));
      }

     protected int[] merge(int[] left, int[] right) {
         int[] result = new int[left.length + right.length];
         int i = 0;
         while (left.length > 0 && right.length > 0) {
             if (left[0] <= right[0]) {
                 result[i++] = left[0];
                 left = Arrays.copyOfRange(left, 1, left.length);
             } else {
                 result[i++] = right[0];
                 right = Arrays.copyOfRange(right, 1, right.length);
             }
         }

        while (left.length > 0) {
            result[i++] = left[0];
            left = Arrays.copyOfRange(left, 1, left.length);
        }

        while (right.length > 0) {
            result[i++] = right[0];
            right = Arrays.copyOfRange(right, 1, right.length);
        }

        return result;
     }
}

 

7.PHP实现

    function mergeSort($arr)
   {
       $len = count($arr);
       if ($len < 2) {
          return $arr;
       }
      $middle = floor($len / 2);
      $left = array_slice($arr, 0, $middle);
      $right = array_slice($arr, $middle);
      return merge(mergeSort($left), mergeSort($right));
   }

   function merge($left, $right)
  {
     $result = [];

     while (count($left) > 0 && count($right) > 0) {
        if ($left[0] <= $right[0]) {
            $result[] = array_shift($left);
        } else {
            $result[] = array_shift($right);
        }
    }

    while (count($left))
        $result[] = array_shift($left);

    while (count($right))
        $result[] = array_shift($right);

    return $result;
  }

 

8.C++实现(迭代版)

   template<typename T> // 整數或浮點數皆可使用,若要使用物件(class)時必須設定"小於"(<)的運算子功能
  void merge_sort(T arr[], int len) {
      T *a = arr;
      T *b = new T[len];
      for (int seg = 1; seg < len; seg += seg) {
          for (int start = 0; start < len; start += seg + seg) {
              int low = start, mid = min(start + seg, len), high = min(start + seg + seg, len);
              int k = low;
              int start1 = low, end1 = mid;
              int start2 = mid, end2 = high;
             while (start1 < end1 && start2 < end2)
                  b[k++] = a[start1] < a[start2] ? a[start1++] : a[start2++];
              while (start1 < end1)
                  b[k++] = a[start1++];
              while (start2 < end2)
                  b[k++] = a[start2++];
          }
          T *temp = a;
          a = b;
          b = temp;
      }
      if (a != arr) {
         for (int i = 0; i < len; i++)
              b[i] = a[i];
         b = a;
      }
      delete[] b;
  }

 

9.C++实现(递归版)

    void Merge(vector<int> &Array, int front, int mid, int end) {
    // preconditions:
    // Array[front...mid] is sorted
    // Array[mid+1 ... end] is sorted
    // Copy Array[front ... mid] to LeftSubArray
    // Copy Array[mid+1 ... end] to RightSubArray
    vector<int> LeftSubArray(Array.begin() + front, Array.begin() + mid + 1);
    vector<int> RightSubArray(Array.begin() + mid + 1, Array.begin() + end + 1);
    int idxLeft = 0, idxRight = 0;
    LeftSubArray.insert(LeftSubArray.end(), numeric_limits<int>::max());
    RightSubArray.insert(RightSubArray.end(), numeric_limits<int>::max());
    // Pick min of LeftSubArray[idxLeft] and RightSubArray[idxRight], and put into Array[i]
    for (int i = front; i <= end; i++) {
         if (LeftSubArray[idxLeft] < RightSubArray[idxRight]) {
            Array[i] = LeftSubArray[idxLeft];
            idxLeft++;
         } else {
            Array[i] = RightSubArray[idxRight];
            idxRight++;
          }
       }
   }

  void MergeSort(vector<int> &Array, int front, int end) {
    if (front >= end)
        return;
    int mid = (front + end) / 2;
    MergeSort(Array, front, mid);
    MergeSort(Array, mid + 1, end);
    Merge(Array, front, mid, end);
  }

 

学习来源:https://www.runoob.com/w3cnote/merge-sort.html

 

   

posted @ 2020-09-03 15:12  小窝蜗  阅读(171)  评论(0编辑  收藏  举报