归并排序

归并排序,先拆后合

动画演示:
                      归并排序动画演示
要对其“先拆后合”,理应通过下标值进行,
假设有个长度为10的数组,则下标为  0123456789,
拆的过程:
        0123456789
        01234  56789
        012  34  567  89
        01  2  3  4  56  7  8  9
        0  1  5  6

        并不难发现,这个过程其实是一棵二叉树:
                                                            0123456789
                                        _____________/  \_____________
                                      /                                                          \
                                  01234                                                    56789
                        _____/  \_____                                      _____/  \_____
                      /                          \                                  /                          \
                  012                          34                            567                          89
                _/  \_                      _/  \_                      _/  \_                      _/  \_
              /          \                  /          \                  /          \                  /          \
            01            2              3              4              56            7              8              9
          /  \                                                          /  \
        0      1                                                      5      6

合并的过程:
        自下而上合并,
        如将[0],  [1]  合并为同时包含这两个数的序列,  对比大小调整其顺序
        另如将[0,  1,  2],  [3,  4]  合并,此时这两个子序列已有序,要将其合并需要:
                1、定义一个临时列表  temp_datas
                2、定义两个游走下标,i,  j,初始值分别为两个子序列的第一个值,  由于两个子序列都已经有序,
                      因此,只需要依次把更小的那个放到临时列表中,最后再拷贝回原列表就可以了

是否可通过遍历二叉树的方式,来进行此算法,答案是可以的。
1、拆分:可以通过对半拆分找到左右孩子
2、合并:需要自下而上且先把左右孩子变成有序,这和后序遍历是一样的

递归方式实现:
def merge_sort_recursion4(datas):
    def _divide(start_index, end_index):
        if start_index == end_index:
            return
        mid = (start_index + end_index) // 2
        _divide(start_index, mid)
        _divide(mid + 1, end_index)
        temp_i, i, j = start_index, start_index, mid + 1
        while i <= mid and j <= end_index:
            if datas[i] <= datas[j]:
                temp_datas[temp_i] = datas[i]
                i += 1
            else:
                temp_datas[temp_i] = datas[j]
                j += 1
            temp_i += 1
        while i <= mid:
            temp_datas[temp_i] = datas[i]
            i += 1
            temp_i += 1
        while j <= end_index:
            temp_datas[temp_i] = datas[j]
            j += 1
            temp_i += 1

        for i in range(start_index, end_index + 1):
            datas[i] = temp_datas[i]

    temp_datas = [0] * len(datas)
    _divide(0, len(datas) - 1)

    return datas
非递归方式实现一:

        利用栈,先把每趟拆分过程全部记录下来,然后依次从栈中每趟的拆分结果取出,进行合并,
        这种方式将拆分与合并进行分离,加强了代码的可读性

def merge_sort_iteration6(datas):
    length = len(datas)
    mid = (length - 1) // 2
    op_stack = [[(0, mid), (mid+1, length - 1)], ]
    while True:
        divides = op_stack[-1]
        new_divides = []
        for d in divides:
            if d[0] == d[1]:
                continue
            mid = (d[0] + d[1]) // 2
            new_divides.append((d[0], mid))
            new_divides.append((mid+1, d[1]))
        if not new_divides:
            break
        op_stack.append(new_divides)

    temp_datas = [0] * length
    while op_stack:
        divides = op_stack.pop()
        for k in range(0, len(divides), 2):
            i, mid = divides[k]
            j, end = divides[k+1]
            temp_i = i
            while i <= mid and j <= end:
                if datas[i] <= datas[j]:
                    temp_datas[temp_i] = datas[i]
                    i += 1
                else:
                    temp_datas[temp_i] = datas[j]
                    j += 1
                temp_i += 1
            while i <= mid:
                temp_datas[temp_i] = datas[i]
                i += 1
                temp_i += 1
            while j <= end:
                temp_datas[temp_i] = datas[j]
                j += 1
                temp_i += 1
            for i in range(divides[k][0], end+1):
                datas[i] = temp_datas[i]
    return datas
非递归方式实现二:

        这种方式不是把拆分过程看作是二叉树,而是偏数学的一个方式:
        一开始是  2个  2个为一组进行合并处理,而后是  4个  4个为一组:
        从2开始等比增长
        一、step  =  2
                01  23  45  67  89
        二、step  =  4
                0123  4567  89
        三、step  =  8
                01234567  89
        二中出现了89这样长度小于step的序列,这种的只要将其与前一个序列4567进行合并就行了

def merge_sort_math6(datas):
    def _merge(start, mid, j, end):
        i = temp_i = start
        while i <= mid and j <= end:
            if datas[i] <= datas[j]:
                temp_datas[temp_i] = datas[i]
                i += 1
            else:
                temp_datas[temp_i] = datas[j]
                j += 1
            temp_i += 1
        while i <= mid:
            temp_datas[temp_i] = datas[i]
            i += 1
            temp_i += 1
        while j <= end:
            temp_datas[temp_i] = datas[j]
            j += 1
            temp_i += 1
        for i in range(start, end+1):
            datas[i] = temp_datas[i]

    length = len(datas)
    temp_datas = [0] * length
    step = 2
    while step <= length:
        i = 0
        while i + step - 1 < length:
            end = i + step - 1
            mid = (i + end) // 2
            _merge(i, mid, mid+1, end)
            i += step
        if i < length:
            _merge(i - step, i-1, i, length - 1)
        step *= 2
    return datas