当前位置: 首页 > 知识库问答 >
问题:

Python-为什么我的合并排序版本对输入数组进行破坏性排序?

常子濯
2023-03-14

我正在学习Python和一些基本的数据结构和算法。我实现了自己版本的合并排序,但我不明白为什么它会改变输入数组的顺序。它的行为就像我在mergesort()函数中将输入数组作为全局引用一样,但我没有这样做。从我实现代码的方式来看,我认为应该在函数的本地范围内对输入数组的副本进行排序,然后返回该副本的排序版本,保持输入数组不变。然而,事实并非如此。它正确地对数组排序;我只是被一个似乎是范围问题的问题弄糊涂了。我将包括代码和示例输出:

arr1 = [38,27,43,3,9,82,10,14] #this will be the input array

def mergesort2(array):
    #print("splitting", array)
    if len(array) > 1:
        middle = len(array)//2
        l = array[:middle]
        r = array[middle:]
        
        mergesort2(l)
        mergesort2(r)
        
        i = j = k = 0
        
        while len(l) > 0 and len(r) > 0:
            if l[0] < r[0]:
                array[k] = l.pop(0)
            else:
                array[k] = r.pop(0)
            k = k + 1
        
        while len(l) > 0:
            array[k] = l.pop(0)
            k = k + 1
        
        while len(r) > 0:
            array[k] = r.pop(0)
            k = k + 1
            
    #print("merging",array)
    return array
    
print("input array before mergesort: ", arr1)
s2 = mergesort2(arr1)
print("input array after mergesort: ", arr1)
print("returned array from mergesort: ", s2)

当我运行上述代码时,我得到以下输出:

input array before mergesort:  [38, 27, 43, 3, 9, 82, 10, 14]
input array after mergesort:  [3, 9, 10, 14, 27, 38, 43, 82]
returned array from mergesort:  [3, 9, 10, 14, 27, 38, 43, 82]

我希望看到输入数组保持不变,并为“s2”分配一个新列表,该列表是输入数组的排序副本。我很感激你能帮助我了解这里发生的一切!

共有2个答案

陶寒
2023-03-14

这不是范围问题,而是Python的工作方式。Python通过引用传递列表等对象。也就是说,当您将其作为参数传递给函数时,列表不会被复制。我建议在将其作为参数传递之前复制输入数组

武琛
2023-03-14

函数mersort2array[k]=l.pop(0)和其他类似指令的合并阶段修改其参数数组。如果要创建排序副本,必须分配一个新数组并合并到该数组中,包括参数数组少于2个元素时:

def mergesort2(array):
    res = array[:]
    if len(array) > 1:
        middle = len(array) // 2
        l = mergesort2(array[:middle])
        r = mergesort2(array[middle:])
        i = j = k = 0
        while i < len(l) and j < len(r):
            if l[i] < r[j]:
                res[k] = l[i]
                i = i + 1
            else:
                res[k] = r[j]
                j = j + 1
            k = k + 1
        
        while i < len(l):
            res[k] = l[i]
            i = i + 1
            k = k + 1
        
        # no need to copy remaining elements from r
    return res
    
arr1 = [38,27,43,3,9,82,10,14] #this will be the input array
print("input array before mergesort: ", arr1)
s2 = mergesort2(arr1)
print("input array after mergesort: ", arr1)
print("returned array from mergesort: ", s2)

输出:

input array before mergesort:  [38, 27, 43, 3, 9, 82, 10, 14]
input array after mergesort:  [38, 27, 43, 3, 9, 82, 10, 14]
returned array from mergesort:  [3, 9, 10, 14, 27, 38, 3, 14]
 类似资料:
  • 对于这个项目,我得到了一个字符串数组和一个整数数组。int[1]是字符串[1]的排名。我需要使用mergesort按1到n的顺序对int数组进行排序,我在下面已经完成了这项工作。但是当int数组被移动时,我还需要切换字符串数组的位置,以便它们都被排序,如果这有意义的话?我不知道我的编码有什么问题,甚至我的想法是否真的有效,但我一直在stringSorted[k]=stringRight[j]上得到

  • Leetcode#167几乎与#1相同,但为什么我不能只添加一个if条件? 函数twoSum应该返回两个数字的索引,使它们相加为目标,其中index1必须小于index2。 注: 返回的答案(index1和index2)不是从零开始的。您可以假设每个输入都有一个解决方案,并且不能两次使用同一个元素。

  • 我想使用功能 对一个int数组进行排序,但我不确定如何进行,这样我就可以确定它使用的是合并排序,而不是任何其他排序。 以下是Java文档:https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html 下面是我认为正确的函数实现,以便使用合并排序。 这是正确的吗?此外,我想指定一个索引,从哪里开始排序等 如何确保编写代码,使其使用合并

  • 问题内容: 是否可以使用排序数组,然后再将另一个相关数组定位为与排序数组相同,例如: 从这一点出发,我想对数组进行排序,这样,如果“人”有一个cellNo“ x”,则在对数组进行排序后,他将具有相同的“ cellNo”“ x” 问题答案: 我会采用另一种方法: 创建一个新对象: 创建一个比较器: 打电话一对阵列

  • 问题内容: 我在Swift Beta中实现一种算法,发现性能非常差。深入研究后,我意识到瓶颈之一就是对数组进行排序一样简单。相关部分在这里: 在C ++中,类似的操作在我的计算机上花费 0.06s 。 在Python中,它花费 0.6秒 ( 绝招 ,仅y =整数列表的sorted(x))。 在Swift中,如果使用以下命令进行编译,则需要 6s : 如果使用以下命令进行编译,则 最多 需要 88s

  • 我试图实现一个递归合并排序算法来排序一个简单的整数数组,但我得到奇怪的值为索引在我的数组的后半部分。前半部分似乎排序精细,这是令人困惑的,因为它是递归实现的。随机整数数组在我的main方法中初始化。 } 这会产生以下输出: 未排序数组={15,9,12,19,49,43,57,70,78,87}对于第1轮:第一个=0中间=4最后=9第1轮中的数组={15,9、12,19、49,43、57,70、7