【问题标题】:Python implementation of the mergeSort algorithm归并排序算法的 Python 实现
【发布时间】:2019-12-17 10:29:16
【问题描述】:

我遇到了以下mergeSort算法的实现:

def merge_sort(x):
    merge_sort2(x,0,len(x)-1)


def merge_sort2(x,first,last):
    if first < last:
        middle = (first + last) // 2
        merge_sort2(x,first,middle)
        merge_sort2(x,middle+1,last)
        merge(x,first,middle,last)


def merge(x,first,middle,last):
    L = x[first:middle+1]
    R = x[middle+1:last+1]
    L.append(999999999)
    R.append(999999999)
    i=j=0
    for k in range(first,last+1):
        if L[i] <= R[j]:
            x[k] = L[i]
            i += 1
        else:
            x[k] = R[j]
            j += 1


x = [17, 87, 6, 22, 41, 3, 13, 54]
x_sorted = merge_sort(x)
print(x)

我得到了大部分。但是,我不明白的是合并函数的以下四行:

 L = x[first:middle+1]
    R = x[middle+1:last+1]
    L.append(999999999)
    R.append(999999999)

首先:为什么切片以 middle+1 结尾?在 Python 中对数组进行切片包括最后一个元素,对吗?那么,从 first:middle 切片不应该足够吗?那么,+1 有什么用呢? 其次:为什么我必须将巨大的数字附加到列表中?为什么没有它就行不通?没有,我查过了但我就是不知道为什么。

【问题讨论】:

  • 在 Python 中对数组进行切片包括最后一个元素,对吗? – 否:'asdf'[:2] → 'as'; 'asdf'[2] → 'd'.
  • 也许这个algo 更清楚
  • 我猜这个巨大的数字应该是“比任何其他数字都大”,这当然不是真的。
  • 我至少可以帮助你解决你的一个问题......最后的大数字是让算法知道已经到达一侧的末端。这意味着在那之后只有来自另一侧的元素被插入到 x 中。为了使算法尽可能简单,插入这些大数字。另请注意,您现在不需要进行一次比较,因为您无需检查是否已到达列表末尾
  • @Cedced_Bro:索引为 k 的 for 循环怎么样?这不应该确保我只根据需要频繁地遍历循环吗?另外:大数字实际上是 L 和 R 的一部分。因此,对于该条目,R[i]

标签: python mergesort


【解决方案1】:

Q1:在 Python 中对数组进行切片包括最后一个元素,对吗?

不,像范围函数 Python 切片不包括最后一个元素。

> a=[1,2,3,4,5]
> a[1:4]
[2, 3, 4]

Q2:关于下面的sn-p。

 L = x[first:middle+1]
    R = x[middle+1:last+1]
    L.append(999999999)
    R.append(999999999)

如果不将这些大数字附加到列表中,您的合并代码可能会与下面的代码有所不同。

   # Copy data to temp arrays L[] and R[] 
    while i < len(L) and j < len(R):
        if L[i] <= R[j]:
            x[k] = L[i]
            i += 1
        else:
            x[k] = R[j]
            j += 1
    # Checking if any element was left 
    while i < len(L): 
        x[k] = L[i] 
        i+=1
        k+=1
    while j < len(R): 
        x[k] = R[j] 
        j+=1
        k+=1

正如@Cedced_Bro 在评论部分指出的那样,那些最大的数字用于知道已经到达一侧的末端。 如果您观察上面的代码 sn-p,如果我们用完一个列表中的数字,我们理想地退出 for 循环并将其他列表的剩余元素插入临时数组(如果有)。

附加这些大数字是避免这两个 for 循环的明智方法。但是它将 999999999 与另一个列表中的剩余元素进行不必要的比较会带来一些成本。

【讨论】:

  • 啊哈,好的。非常感谢!
【解决方案2】:

你真的不需要意大利面条式的嵌套函数,只需 recur 就可以了,来自https://rosettacode.org/wiki/Sorting_algorithms/Merge_sort#Python

from heapq import merge

def merge_sort(m):
    if len(m) <= 1:
        return m

    middle = len(m) // 2
    left = m[:middle]
    right = m[middle:]

    left = merge_sort(left)
    right = merge_sort(right)
    return list(merge(left, right))

索引不应该有 +1,因为如果它们是相同的索引,即 Python 切片不会重叠,即

>>> x = [1,2,3,4,5,6]
>>> middle = 4
>>> x[:middle]
[1, 2, 3, 4]
>>> x[middle:]
[5, 6]

此外,heapq 的合并实现会比您编写的更优化 =)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-03-24
    • 1970-01-01
    • 1970-01-01
    • 2012-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多