zoukankan      html  css  js  c++  java
  • 归并排序(Merge sort)

    很多的算法都是递归的结构,递归的目的呢,是在自己调用自己的时候,将问题分解成更小的问题,这个过程也叫做divide-and-conquer,通过把原来的问题的一个大问题,分解成一个更小的问题,再把更小的问题分解成微不足道的问题,再一一解决所有所有的问题。
    devide-and-conquer一般是这样来解决问题的:
    Divide:将问题分解成更小的,但是相似的问题
    Conquer:递归解决这些小问题,如果小问题已经足够小,直接解决;否则可以重复Divide的过程
    Combine:将解决小问题的方案合并和大的解决方案中,从而解决更大的问题
    今天要说的归并排序,就是这样的一种模式。

    归并排序算法

    Divide:将n个要排序的元素分成两半,各占n/2
    Conquer:用归并排序分别对两个n/2的元素排序
    Combine:将两个排序的结果合并(Merge),产出最终结果
    这是一个递归的过程,那递归到什么时候是个头呢?
    当被分割的序列长度是1了,就该结束了,一个元素就不用排序了吧。
    设想一个我们有
    MERGE(A, p, q, r)
    A就是我们要排序的序列
    p,q,r都是A的index,满足条件p<=q<r,我们假设A[p..q]和A[q+1..r]是已经排序排好的,是有序的数组,于是我们总共有n个元素需要排序n = r - p + 1。
    还是用打牌的观点来说,假如我们现在把一副牌洗乱,然后分成两堆,左右各一半。然后分别将左右两堆按从小到大排序,牌面均向上。
    现在,我们想把这两堆牌合并在一起,并且是有序叠放的。就可以这样做:

    • 比较左边和右边的牌,取小的那一张,拿出来,扣在桌子上。
    • 再次比较两堆牌,取较小的一张,拿出来,扣在桌子上
    • 重复上面的动作,知道所有的牌都合并在一起。
      这就是归并排序。
      可是这里面有个小问题,但某些情况下,可以左边已经没有牌了,右边还有一堆。这时候去比较左右两边的时候,是不是要先检查一下是否还有牌呢?
      举个例子,左边的牌是
      1,3,4,5
      右边的牌是
      2,6,7,8
      我们来做归并排序:
    1. 比较左右两堆,取出最小的1,扣在桌上
    2. 比较左右两堆,取出最小的2,扣在桌上
    3. 比较左右两堆,取出最小的3,扣在桌上
    4. 比较左右两堆,取出最小的4,扣在桌上
    5. 比较左右两堆,取出最小的5,扣在桌上
      现在呢,1,2,3,4,5都排好序了,左边牌堆没有牌了。右边还有3张。那比较左右两边的时候,左边不就是null了?
      这个时候呢,可以考虑弄个正无穷∞出来,两个牌堆是
      1,3,4,5,∞和2,6,7,8,∞那就不用判断了。
      根据这个思想,得出我们的伪代码。

    伪代码

    Merge(left, right)
    	let result[1..left.length+right.length] be new arrays
    	n = 0
    	m = 0
    	while n < left.length and m < right.length
    		if left[n] <= right [m]
    			result.add(left[n])
    			n = n + 1
    		else
    			result.add(right[m])
    			m = m + 1
    	result.add(left[n..left.length])//如果还有剩下,加入左边剩余的部分
    	result.add(right[m..right.length])//如果右边还有剩下,加入右边部分
    return result
    

    但是,怎么体现递归呢?
    这儿还得有一段

    Merge-Sort(seq, p, r)
    	if seq.length <=1
    		return seq
    	middle = seq.length / 2
    	left = Merge-Sort(seq[1..middle])
    	right = Merge-Sort(seq[middle..seq.length])
    	return Merge-Sort(left, right)
    

    Python实现

    def merge(left, right):
    	result = []
    	n, m = 0, 0
    	while n < len(left) and m < len(right):
    		if left[n] <= right[m]:
    			result.append(left[n])
    			n += 1
    		else:
    			result.append(right[m])
    			m += 1
    	
    	result += left[n:]
    	result += right[m:]
    	return result
    
    def sort(seq):
    	if len(seq) <= 1:
    		return seq
    
    	middle = int(len(seq) / 2)
    	left = sort(seq[:middle])
    	right = sort(seq[middle:])
    	return merge(left, right)
    

    源码:Github-Syler-Fun-Merge-Sort-Python

    Java实现

    		public static void sort(int[] seq, int left, int right) {
            if (left < right) {
                int middle = (left + right) / 2;
                sort(seq, left, middle);
                sort(seq, middle + 1, right);
                merge(seq, left, right);
            }
        }
    
        public static void merge(int[] seq, int l, int r) {
            int mid = (l + r) / 2;
            int i = l;
            int j = mid + 1;
            int count = 0;
            int temp[] = new int[r - l + 1];
            while (i <= mid && j <= r) {
                if (seq[i] < seq[j]) {
                    temp[count++] = seq[i++];
                } else {
                    temp[count++] = seq[j++];
                }
            }
            while (i <= mid) {
                temp[count++] = seq[i++];
            }
            while (j <= r) {
                temp[count++] = seq[j++];
            }
            count = 0;
            while (l <= r) {
                seq[l++] = temp[count++];
            }
        }
    

    源码:Github-Syler-Fun-Merge-Sort-Java


    作者:xiao.chun(小春)
    我的独立博客:http://1few.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.

  • 相关阅读:
    JS 正则查找与替换
    MySQL 批量插入值
    Python/Django 批量下载Excel
    Python/Django 下载Excel2007
    Python/Django 下载Excel2003
    Python3安装Scrapy
    服务器响应状态码
    细说同域-同父域-跨域
    细说Ajax跨域
    PostgreSQL学习
  • 原文地址:https://www.cnblogs.com/asis/p/6838537.html
Copyright © 2011-2022 走看看