归并排序算法优化

Posted organic

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了归并排序算法优化相关的知识,希望对你有一定的参考价值。

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 次:

image

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

image

以上是关于归并排序算法优化的主要内容,如果未能解决你的问题,请参考以下文章

归并排序算法优化

算法一个小白的算法笔记: 归并排序算法的编码和优化 (,,? ? ?,,)

算法归并排序 小和 问题

jdk8源码legacyMergeSort算法=插入排序+分治思想+归并优化,其实就这么简单

jdk8源码legacyMergeSort算法=插入排序+分治思想+归并优化,其实就这么简单

归并排序