【问题标题】:How to sort an array by finding min and max of subarrays?如何通过查找子数组的最小值和最大值对数组进行排序?
【发布时间】:2021-11-30 15:53:54
【问题描述】:

我正在尝试实现一种排序算法,该算法将找到数组中的最大和最小元素,然后将它们分别与数组的最后一个元素和第一个元素交换。然后算法将数组缩小两个元素(第一个和最后一个元素,已放置在排序位置),然后对子数组重复执行相同的操作,直到数组完全排序。

但我似乎无法让它发挥作用,我不知道为什么。没有任何类型的错误,但在运行函数后数组完全保持不变。这是我所拥有的:

def novel_sort(arr, left, right):
    if left < right:
        min_index = left
        max_index = left
        for i in range(left, right+1):
            if arr[i] < arr[min_index]:
                min_index = i
            if arr[i] > arr[max_index]:
                max_index = i
        arr[left], arr[min_index] = arr[min_index], arr[left]
        arr[right], arr[max_index] = arr[max_index], arr[right]
        novel_sort(arr, left + 1, right - 1)

输入

l = [235, 25, 123, 1]
novel_sort(l, 0, len(l) - 1)
print(l)

预期输出

[1, 25, 123, 235]

观察到的输出

[235, 25, 123, 1]

如果我将for 循环更改为for i in range(left, right),那么除了最后一个元素([1, 123, 235, 25])之外,数组的每个元素都将被排序。我已经尝试过迭代,但我似乎仍然无法弄清楚发生了什么。

【问题讨论】:

    标签: python arrays list algorithm sorting


    【解决方案1】:

    因为您在两个单独的步骤中进行交换,所以当您将最低值放在那里时,您可能会交换原始最高值(如果它恰好在索引左侧)。然后,在下一行,最大值的索引(max_index 等于左侧)不再引用最大值(实际上有 3 个类似这样的棘手情况:左侧的最大值,右侧的最小值,两者都在同一时间)。

    当您将循环更改为 for i in range(left, right) 时,左右的相对位置会受到影响,并且您可能不会在同一个列表中遇到这种情况(尽管不同的列表内容可能仍然存在相同的问题)。

    正如don't talk just code 所指出的,补偿索引冲突将比仅在一次操作中执行交换更复杂。

    类似这样的事情(请注意,我没有检查所有边缘情况):

    low,high,swapLow,swapHigh = arr[min_index],arr[max_index],arr[left], arr[right]
    if right == min_index: swapLow,swapHigh = high,swapLow
    if left  == max_index: swapLow,swapHigh = swapHigh,low
    arr[left],arr[right],arr[min_index],arr[max_index] = low,high,swapLow,swapHigh
    

    当最小值在右侧时,交换将希望将位于索引左侧的原始值放入我们实际希望最大值所在的 min_index 位置(也是索引右侧)。所以我们需要把临时变量(swapLow)改成最大值。而 max_index 位置现在需要接收原来在 min_index 的位置。当最大值在左边时,同样的推理也适用。

    另一种避免该问题的方法是,如果左侧值大于右侧值,则通过在循环之前左右交换来确保永远不会发生索引冲突。通过使索引左侧的值小于索引右侧的值,它们都不会在循环结束时成为相反的交换目标。

    def novel_sort(arr, left, right):
        if left < right:
            min_index = left
            max_index = left
            if arr[left]>arr[right]:         # avoid swapping conflicts
                arr[left],arr[right]=arr[right],arr[left]
            for i in range(left+1, right+1): # left+1 saves one comparison
                if arr[i] < arr[min_index]:
                    min_index = i
                if arr[i] >= arr[max_index]: # changed to >=
                    max_index = i
            arr[left], arr[min_index] = arr[min_index], arr[left]
            arr[right], arr[max_index] = arr[max_index], arr[right]
            novel_sort(arr, left + 1, right - 1)
    

    请注意,我还更改了 max_index 的比较,以便排序正确处理包含重复值的列表。这确保交换的最大值是最高索引处的最大值(因此,如果左右相等且最大值,我们不会再次陷入索引冲突)

    【讨论】:

    • 我绝对是个白痴。这解决了这个问题。我不敢相信当我一次又一次地跟踪它时,我没有意识到这一点。非常感谢你,伙计。
    • @dtjc,你是对的,解决方案将涉及更多一点,即仅在一个操作中进行交换或使用临时变量,因为某些交换值的索引相同的情况。
    【解决方案2】:

    您的第一次交换可能涉及最大值,使您的max_index 错误。两次交换之间的简单修复:如果最大值位于 left,那么在第一次交换之后,它现在位于 min_index

            arr[left], arr[min_index] = arr[min_index], arr[left]
            if max_index == left:
                max_index = min_index
            arr[right], arr[max_index] = arr[max_index], arr[right]
    

    您可以忽略max_index 一直是min_index 的情况,因为所有剩余的值都相同,所以没关系。

    【讨论】:

      【解决方案3】:

      如果您尝试对数组进行排序,只需使用 sort()

      例子

      array=[1,20,4,56,78,3,307]
      array.sort()
      print(array)
      # prints [1, 3, 4, 20, 56, 78, 307]
      

      排序方法会将原始变量更改为排序后的版本。

      【讨论】:

      • 我正在尝试实现特定的排序算法。
      • 请输入给定变量的预期输出。
      猜你喜欢
      • 2017-08-01
      • 1970-01-01
      • 1970-01-01
      • 2021-09-15
      • 2016-07-13
      • 2016-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多