归并排序算法优化

1. 什么是归并排序?

更详细的解释可以百度,这里说说其主要思想:

归并排序是采用分治思想,将所有的数均匀的分成n个等分的组,然后依次取(x, x+1) 2个等分组,将他们合并排序,形成一个新的组,然后递归即可,最后会合并为一个组,这个组就是有序的。

示范一下:

要排序的11个数 : [8, 3, 4, 2, 22, 17, 13, 66, 9, 2, 100]

第1步:分成11个等分:{[3] , [8], [2] , [4], [17] , [22], [66], [13], [2], [9], [100]}

第2步:每2组合并并排序,如f([3], [8]) → [3, 8], f([2] , [4]) → [2, 4]

得到6个新的分组{[3, 8], [2, 4], [17, 22], [66, 13], [2, 9], [100]},其中100因为没有其他分组与其合并,故单独做为一个分组

重复一次第2步:合并分组f([3, 8], [2, 4]) → [2, 3, 4, 8],类似的,合并完后得到3个新的分组{[2, 3, 4, 8], [13, 17, 22, 66], [2, 9, 100]}

继续重复第2步,最后会得到一个有序的大分组

可以看出,每次合并排序后,每个新的组内部是有序的,但组和组之间仍然是无序的。再次合并时,由于2个有序的组合并比2个无序的组合并要快得多,故归并排序是效率是比较高的。

2. 问题

在合并分组时,对合并排序的做法很简单,就是同时遍历2个组,取出最小的数放到合并后的组中即可:

def Merge(pairList1, pairList2):
    mergeList = [];

    while True:
        if len(pairList1) == 0 or len(pairList2) == 0:
             break;

        #append mix num to mergeList
        if pairList1[0] <=  pairList2[0]:
            mergeList.append(pairList1[0]);
            del pairList1[0];
        else:
            mergeList.append(pairList2[0]);
            del pairList2[0];

    #append remain num to mergeList, only one pair list will be remain
    mergeList += pairList1 + pairList2;
    return mergeList;

这时,有一种情况会降低合并效率,如有2个有序分组[1, 2, 3, 4, 5], [10],我们会发现,该Merge函数会和10比较5次后(因为每次第一组的数都小于10,每次都会放第一组的数到mergeList中),才会把第一组中的数据合并完。

对于这种情况,我们知道2分查找可以高效的知道10应该插入有序数列[1, 2, 3, 4, 5]的某个位置,由此,可以减少比较的次数。

3. python code

operateTimes = 0;

def BinaryInsert(num, startNum, endNum, sortList):
    #if only 2 num, return
    global operateTimes;
    operateTimes += 1;

    if endNum - startNum < 2:
        for i in range(startNum, endNum - startNum + 1):
            if num <= sortList[i]:
                sortList.insert(i, num);
                break;
        else:
            sortList.insert(endNum+1, num);
        return;

    midleNum = (startNum + endNum) / 2;
    checkNum = sortList[midleNum];

    if checkNum == num:
        sortList.insert(midleNum, num);
    elif checkNum > num:
        return BinaryInsert(num, startNum, midleNum - 1, sortList);
    else:
        return BinaryInsert(num, midleNum + 1, endNum, sortList);

def Merge(pairList1, pairList2):
    mergeList = [];

    while True:
        if len(pairList1) == 0 or len(pairList2) == 0:
             break;

        #If do not use BinaryInsert, comment forlowing code
        if len(pairList1) == 1:
            BinaryInsert(pairList1[0], 0, len(pairList2) - 1, pairList2);
            del pairList1[0];
            break;

        if len(pairList2) == 1:
            BinaryInsert(pairList2[0], 0, len(pairList1) - 1, pairList1);
            del pairList2[0];
            break;   

        global operateTimes;
        operateTimes += 1;

        #append mix num to mergeList
        if pairList1[0] <=  pairList2[0]:
            mergeList.append(pairList1[0]);
            del pairList1[0];
        else:
            mergeList.append(pairList2[0]);
            del pairList2[0];

    #append remain num to mergeList, only one pair list will be remain
    mergeList += pairList1 + pairList2;
    return mergeList;    

def MergeSort(sequenceList):
    sequenceLen = len(sequenceList);
    if sequenceLen <= 1:
        return sequenceList[0];

    pairList = [];
    pairNum = 0;
    while pairNum <  sequenceLen / 2:
        #Merge each pairs
        #{a1, a2, a3, a4, a5} --> {(a1, a2), (a3, a4), (a5)}
        pairList.append(Merge(sequenceList[2*pairNum], sequenceList[2*pairNum + 1]));
        pairNum += 1;

    if sequenceLen % 2 == 1:
        pairList.append(sequenceList[-1]);
    print pairList;
    return MergeSort(pairList);

############################# main ##################################
if __name__ == ‘__main__‘:
    sequence = [8, 3, 4, 2, 22, 17, 13, 66, 9, 2, 100];

    sequenceList = [];
    for i in sequence:
        sequenceList.append([i]);

    sortSequence = MergeSort(sequenceList);
    print "After", operateTimes, "times, merge sort sequence is", sortSequence;

测试结果:

1> 未优化的代码共需 27 次:

2> 优化的代码降低到 23 次了:

时间: 2024-12-29 01:04:17

归并排序算法优化的相关文章

自底向上的归并排序算法

1.什么是自底向上的归并排序? 说到底,不管是前面说的自顶向下的归并排序还是现在讲的自底向上的归并排序,其实质都是归并. 来看看一个演示过程:          这个就是待排序的数组序列          先将数组序列以2个元素为一组分成4组,每个组内部分成2个子序列进行向上合并           这是合并之后的效果           然后以4个元素为一组分成2组,每个组内部分成2个子序列进行向上合并           这是合并之后的效果           然后以8个元素为一组分成1个组

SQL Server 聚合函数算法优化技巧

Sql server聚合函数在实际工作中应对各种需求使用的还是很广泛的,对于聚合函数的优化自然也就成为了一个重点,一个程序优化的好不好直接决定了这个程序的声明周期.Sql server聚合函数对一组值执行计算并返回单一的值.聚合函数对一组值执行计算,并返回单个值.除了 COUNT 以外,聚合函数都会忽略空值. 聚合函数经常与 SELECT 语句的 GROUP BY 子句一起使用. v1.写在前面 如果有对Sql server聚合函数不熟或者忘记了的可以看我之前的一片博客.sql server 基

性能优化——算法优化

背景 由于某种原因,我们系统需要记录另一个系统中一个表里的id.但是,当我们记录完了以后,别人系统可能会删除那个表里的一些数据,这样的话,我们这边就多了一些无效数据,所以,我们必须的找到这些无效的id,然后将其删除. 开始,我们的实现是这样:我们将记录下来的所有id放在一个list里,然后传到另一个系统,他将他们已经删除的id返回.具体处理代码如下: <pre name="code" class="java">public String findDele

必须知道的八大种排序算法【java实现】(三) 归并排序算法、堆排序算法详解

一.归并排序算法 基本思想: 归并(Merge)排序法是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并排序示例: 合并方法: 设r[i-n]由两个有序子表r[i-m]和r[m+1-n]组成,两个子表长度分别为n-i +1.n-m. j=m+1:k=i:i=i; //置两个子表的起始下标及辅助数组的起始下标 若i>m 或j>n,转⑷ //其中一个子表已合并完,比较选取结束 //选取r[i]和r[j]

归并排序算法--java

归并排序(Merge)是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的.然后再把有序子序列合并为整体有序序列. 归并排序是建立在归并操作上的一种有效的排序算法.该算法是采用分治法(Divide and Conquer)的一个非常典型的应用. 将已有序的子序列合并,得到完全有序的序列:即先使每个子序列有序,再使子序列段间有序.若将两个有序表合并成一个有序表,称为2-路归并. 归并排序算法稳定,数组需要O(n)的额外空间,链表需要O(log(n))

算法之-归并排序算法

归并排序是效率还是比较高的算法.其中的分治法是常用的一种解决问题的方法,现在流行的云计算其实就是一种分治法的应用. 所谓的分治法,字面解释就是"分而治之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.这个思想在实际工作中的作用非常大,特别是处理大数据和做复杂运算的时候. 归并排序的基础是归并操作merge,即将两个有序数组合并为一个有序数组. 归并排序的算法思路为: 第一次扫描数组,将数组中相邻的两个元素mer

递归分治算法(一)-归并排序算法

前言: 分治法是一种算法设计思想,所谓分治,意为分而治之,是指将一个难以直接解决的大问题,递归的分割成一些规模的较小的问题,以便逐个解决.采用分治法设计的算法通常用到递归算法来实现,故标题为递归分治. 归并排序算法 归并就是将两个或两个以上的有序表合并成一个新的有序表.归并排序就是将无序的待排序的序列分解成若干个有序的子序列,并把有序子序列合并为整体有序序列的过程.一般分为2-路归并排序和多路归并排序. 他的大概流程如下图: 我们来看看java代码怎么写的: package guibing; /

数据结构实践——归并排序算法的改进

本文是针对[数据结构基础系列(9):排序]的项目. [项目 - 归并排序算法的改进] 采用归并排序.快速排序等高效算法进行排序,当数据元素较少时(如n≤64),经常直接使用直接插入排序算法等高复杂度的算法.这样做,会带来一定的好处,例如归并排序减少分配.回收临时存储区域的频次,快速排序减少递归层次等. 试按上面的思路,重新实现归并排序算法. [参考解答] #include <stdio.h> #include <malloc.h> #include <stdlib.h>

冒泡排序及其算法优化分析

1.基本冒泡排序 冒泡排序的基本思想:假设被排序的记录数组d[1...N]垂直竖立,将每个记录d[i]看作是一个气泡,那么重的气泡就会向下下沉,轻的气泡就会向上升.每次都是相邻的两个气泡d[i]和d[i+1]进行比较.如果d[i]>d[i+1],那么就交换两个气泡,然后在比较d[i+1]和d[i+2],以此类推,知道所有的气泡都有序排列.假设排序20,37,11,42,29. 第1次冒泡:20.37,11,42,29 d[0]和d[1]比较 第2次冒泡:20,11,37,42,29 d[1]和d