【问题标题】:4-Way MergeSort Challenge - Python4 路合并排序挑战 - Python
【发布时间】:2021-06-04 11:46:57
【问题描述】:

我正在尝试编写一个 MergeSort 函数,它将数组拆分为 4 个数组,而不是像常规的 MergeSort 那样分成 2 个数组。

我尝试遵循 2-way mergeSort 并将其实现到 4-way 但我一直卡在递归调用中,我不明白问题出在哪里..

我编写了一个调用自身 4 次的 merge_sort_4 函数和应该合并 4 个数组而不是 2 个数组的 merge4 函数。

我知道我班上的一些人通过 3 次调用常规 Merge 函数解决了这个问题,但我认为这有点忽略了这个挑战的重点..

如果解决的唯一方法是使用常规合并,请告诉我,如果不是,请帮我找出问题

这是我的代码

def merge_sort_4(lst, start, end):
    if start < end:
        quarter1 = (start + end) // 4
        quarter2 = (start + end) // 2
        quarter3 = (end - quarter1 - 1)

        merge_sort_4(lst, start, quarter1)
        merge_sort_4(lst, quarter1 + 1, quarter2)
        merge_sort_4(lst, quarter2 + 1, quarter3)
        merge_sort_4(lst, quarter3 + 1, end)

        merge4(lst, start, quarter1, quarter2, quarter3, end)


def merge4(lst, start, q1, q2, q3, end):
    first_q_list = lst[start:q1 + 1]
    sec_q_list = lst[q1 + 1:q2 + 1]
    third_q_list = lst[q2 + 1:q3 + 1]
    last_q_list = lst[q3 + 1:end + 1]

    first_q_list.append(float('inf'))
    sec_q_list.append(float('inf'))
    third_q_list.append(float('inf'))
    last_q_list.append(float('inf'))

    i = 0  # first sublist index
    j = 0  # sec sublist index
    m = 0  # third sublist index
    n = 0  # last sublist index

    for k in range(start, end + 1):
        if first_q_list[i] <= sec_q_list[j] and first_q_list[i] <= third_q_list[m] and first_q_list[i] <= last_q_list[
        n]:
            lst[k] = first_q_list[i]
            i += 1

        elif sec_q_list[j] <= third_q_list[m] and sec_q_list[j] <= last_q_list[n]:
            lst[k] = sec_q_list[j]
            j += 1

        elif third_q_list[m] <= last_q_list[n]:
            lst[k] = third_q_list[m]
            m += 1
        else:
            lst[k] = last_q_list[n]
            n += 1

提前感谢您的帮助!

【问题讨论】:

  • 到目前为止您尝试过什么?你怎么知道它不起作用?您是否浏览过代码或单独测试过任何部分?您对可能出现的问题有任何怀疑吗?

标签: python sorting mergesort array-merge


【解决方案1】:

好的,所以我对这里可能有问题的事情有一些想法,但是您并没有真正说明您需要什么帮助,所以首先我想为您指出正确的方向,以了解如何解决这个问题自己。

在您编写任何代码进入merge4merge_sort_4 之前,您能描述一下它们的前置条件和后置条件是什么吗?即,在调用其中一个之前,关于列表的状态和传递给它的参数,您需要什么是真实的?它的工作是什么?它完成后保证做了什么? start 可以有哪些价值,end 可以有哪些价值?

我希望您能描述一些约束条件,例如 0 &lt;= start &lt;= end &lt; len(lst) 用于调用 merge_sort_40 &lt;= start &lt;= q1 &lt;= q2 &lt;= q3 &lt;= end &lt;= len(lst) 用于调用 merge4 以及 merge4 需要对四个子列表进行排序并保证从list 索引startend 的整个范围都已排序。

现在 - 这些事情真的是真的吗?你能用示例值遍历代码,看看会发生什么吗?你能在算法中添加断言来捕捉其中一个不正确的第一次吗?您能否在小块测试数据上分别测试算法的各个部分,看看它们的行为是否符合您的预期?

试试看你能不能自己弄明白,如果不行,我建议你从这里开始寻找……

...

...

我希望quarter1quarter2quarter3 都应该在startend 的范围内,但我认为您在那里的计算可能不会达到您的预期。尝试一些不同的startend 值,看看你是否对结果感到惊讶。

【讨论】:

    【解决方案2】:

    使用标记值 (float('inf')) 存在问题。考虑多次运行结束的情况,例如当 first_q_list[i] == sec_q_list[j] == float('inf') 时,在这种情况下 float('inf') at first_q_list[i]被复制到 lst[k] 并且 i 在 first_q_list[] 的末尾增加。

    代码需要在每次复制元素时检查是否到达运行结束,如果是,则下拉到剩余运行的 3 路合并。后来下降到 2 路合并,然后最后是剩余运行的其余部分的副本。

    代码可以改进,考虑到 third_q_lst[] 或 last_q_lst[] 具有最小元素的情况,需要 6 次比较才能达到这些情况。通过使用嵌套的 if + else,这可以减少到任何路径上的 3 次比较,以确定哪个运行具有最小的元素。 3 路合并以查找 a、b、c 中的最小值的示例,对于 3 种可能的情况中的任何一种,只进行 2 次比较:

        if(a <= b)
            if(a <= c)
                a is smallest
            else
                c is smallest
        else
            if(b <= c)
                b is smallest
            else
                c is smallest
    

    链接到 4 路自上而下混合合并排序 + 插入排序的 java 示例(用于小型运行)。我没有费心将它移植到 Python,因为 Python 太慢了,而且由于 Python 是一种解释性语言,Python 中的 4 路合并排序可能比 2 路慢(使用编译语言,4 路大约快 15%多于 2 路)。

    How can I implement the Merge Sort algorithm with 4-way partition without the error ArrayIndexOutOfBoundsException?

    【讨论】:

    • 使用float('inf') 作为哨兵的全部意义在于,每个列表在用尽时将自动从最小值的竞争者中删除,而无需对逻辑进行任何更改。这不太可能是问题的全部。
    • @MarkRansom - 比较是 k 的外部循环在达到两个运行的末端时退出。对于 4 路合并,它会失败,因为在合并完成之前会到达两次运行的终点,因为剩余的 2 次运行没有用完。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-28
    • 1970-01-01
    • 2020-05-19
    • 2014-04-17
    • 2013-03-30
    • 2016-11-21
    • 1970-01-01
    相关资源
    最近更新 更多