【分治算法】根号n段归并排序算法

目录

一. 问题描述

二. 标准归并排序算法

2.1 基本思想

2.2 时间复杂度分析

2.3 代码实现

三. 根号n段归并排序算法

3.1 时间复杂度分析

3.2 k路归并算法

3.3 Python代码实现根号n段归并排序算法


一. 问题描述


二. 标准归并排序算法

2.1 基本思想

        分治策略求解:

  • 将原始数据A中的元素分成两个子集合:A[1:n/2]和A[n/2:];
  • 分别对这两个子集合单独排序;
  • 将已排序的两个子序列归并成一个含有n个元素的排序好的序列。

        这样的一个排序过程称为归并排序(Merge sort)。

2.2 时间复杂度分析

        在归并排序中,Merge过程(即合并操作)花费时间与两数组元素总数成正比。(可表示为cn,其中c为某正常数,n为元素数)。原因是每次从两数组A和B中取出一个最小值minv,取出的过程需要A[0]和B[0]两个元素的比较,其中A、B非降序排列。

       

        则归并排序MergeSort的排序时间用递推关系式表示如下:

         结论:标准归并排序的时间复杂度为O(nlogn).

2.3 代码实现

# Merge sort
def Merge(a1,a2):
    i,j = 0,0
    a = []
    while i < len(a1) and j < len(a2):
        if a1[i] < a2[j]:
            a += [a1[i]]
            i += 1
        else:
            a += [a2[j]]
            j += 1
    if i == len(a1):
        a += a2[j:]
    else:
        a += a1[i:]
    return a
def Merge_sort(a):
    if len(a) == 1:
        return a
    elif len(a) == 2:
        if a[0]>a[1]:
            return [a[1],a[0]]
        else:
            return a
    else:
        mid = math.ceil(len(a)/2)
        a1,a2 = Merge_sort(a[0:mid]),Merge_sort(a[mid:])
        return Merge(a1,a2)

三. 根号n段归并排序算法

3.1 时间复杂度分析

3.2 k路归并算法

参考:Tournament Tree (Winner Tree) and Binary Heap - GeeksforGeeks

3.3 Python代码实现根号n段归并排序算法

Note:下面代码可以实现功能,但太丑了,后续待改进

def k_merge(A:list):
    result = []
    k = len(A)
    depth = math.ceil(math.log2(k))
    # 用inf或-inf补全Winner Tree,保证len(A) = 2**depth
    # 由于本例中,每次取出最小值,故用inf补全
    for i in A:
        i.append(math.inf)
    for i in range(2**depth - k):
        A.append([math.inf])

    # 构建 Winner Tree:Winner Tree[1]对应根节点
    # Note:Winner Tree中保存的时子序列号,不是元素值
    # 共有1-(2**depth-1)个结点,这里多了1个,目的是让下标为1对应开始序号1
    Winner_Tree = [0]*(2**depth)
    # 先构建最下面1层
    j = 0
    for i in range(2**(depth-1),2**depth):
        if A[j][0] < A[j+1][0]:
            Winner_Tree[i] = j
        else:
            Winner_Tree[i] = j+1
        j += 2
    
    # 还有depth-1层没有构建
    for i in range(depth-1,0,-1):
        son_tree = Winner_Tree[2**i:2**(i+1)]
        # print(son_tree)
        begin = 0
        for j in range(2**(i-1),2**i):
            # print(A[son_tree[begin]][0])
            # print(A[son_tree[begin+1]][0])
            c = 1
            if A[son_tree[begin]][0] < A[son_tree[begin+1]][0]:
                Winner_Tree[j] = son_tree[begin]
            else:
                Winner_Tree[j] = son_tree[begin+1]
            begin += 2
    # print(Winner_Tree)

    # k个子序列中,第一个元素最小的k索引
    mink = Winner_Tree[1]
    while A[mink][0] != inf:
        result.append(A[mink][0])
        A[mink].pop(0)
        if mink%2 == 0:
            partner = mink+1
        else:
            partner = mink-1
        if A[mink][0] < A[partner][0]:
            new = mink
        else:
            new = partner

        if new == 0:
            junction = 2**(depth-1)
        else:
            junction = 2**(depth-1) + int(math.log2(new))
        Winner_Tree[junction] = new
        # father是结点编号
        j = depth - 1
        while junction != 1:
            father = 2**(j-1) + int((junction-2**j)/2)
            if junction%2 == 0:
                partner = junction + 1
            else:
                partner = junction - 1
            if A[Winner_Tree[junction]][0] < A[Winner_Tree[partner]][0]:
                Winner_Tree[father] = Winner_Tree[junction]
            else:
                Winner_Tree[father] = Winner_Tree[partner]
            
            junction = father
            j -= 1
        
        mink = Winner_Tree[1]
    return result
def sqrt_Merge_sort(a:list):
    if len(a) == 1:
        return a
    elif len(a) == 2:
        if a[0]>a[1]:
            return [a[1],a[0]]
        else:
            return a
    # 这里一定要认定3为基本解之一:因为根号3下取整为1,根号4下取整为2,因此3作为1个序列来看
    elif len(a) == 3:
        a = a.copy()
        p,q = min(a),max(a)
        a.remove(p)
        a.remove(q)
        return [p,a[0],q]
    else:
        # 划分为dif个子序列 如:长度为8的序列,分为2个子序列
        dif = math.floor(math.sqrt(len(a)))
        A = []
        for i in range(dif-1):
            A.append(a[dif*i:dif*(i+1)])
        A.append(a[dif*(i+1):])
        # 每个子序列排序
        A = [sqrt_Merge_sort(i) for i in A]
        # 合并
        res = k_merge(A)
        return res
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值