为什么筛选在堆排序中起作用,但在筛选中不起作用?

时间:2019-06-23 13:27:45

标签: python-3.x data-structures heapsort binary-heap

我的编程任务如下:  您将只需要使用O(n)交换就可以将数组转换为堆,如讲座所述。请注意,在此问题中,您将需要使用最小堆而不是最大堆。输出的第一行应包含单个整数m-交换的总数。 m必须满足0≤m≤4n的条件。接下来的m行应包含用于将数组a转换为堆的交换操作。每次交换都由一对整数i,j(要交换的元素的从0开始的索引)来描述

我已经通过与母体的值进行比较,使用筛选技术实现了一个解决方案,该解决方案为小文本情况提供了解决方案,当数组中的整数数目小于10时,通过手动检查进行验证,但无法通过100000个整数作为输入。 这是该代码


class HeapBuilder:
    def __init__(self):
        self._swaps = [] #array of tuples or arrays
        self._data = []

    def ReadData(self):
        n = int(input())
        self._data = [int(s) for s in input().split()]
        assert n == len(self._data)

    def WriteResponse(self):
        print(len(self._swaps))
        for swap in self._swaps:
            print(swap[0], swap[1])

    def swapup(self,i):
        if i !=0:
            if self._data[int((i-1)/2)]> self._data[i]:
                self._swaps.append(((int((i-1)/2)),i))
                self._data[int((i-1)/2)], self._data[i] = self._data[i],self._data[int((i-1)/2)]
                self.swapup(int((i-1)/2))

    def GenerateSwaps(self):
        for i in range(len(self._data)-1,0,-1):
            self.swapup(i)

    def Solve(self):
        self.ReadData()
        self.GenerateSwaps()
        self.WriteResponse()

if __name__ == '__main__':
    heap_builder = HeapBuilder()
    heap_builder.Solve()

另一方面,我已经使用类似的比较过程的筛选技术实现了堆排序,并且这件事通过了每个测试用例。 以下是此方法的代码

class HeapBuilder:
    def __init__(self):
        self._swaps = [] #array of tuples or arrays
        self._data = []

    def ReadData(self):
        n = int(input())
        self._data = [int(s) for s in input().split()]
        assert n == len(self._data)

    def WriteResponse(self):
        print(len(self._swaps))
        for swap in self._swaps:
            print(swap[0], swap[1])

    def swapdown(self,i):
        n = len(self._data)
        min_index = i
        l = 2*i+1 if (2*i+1<n) else -1 
        r = 2*i+2 if (2*i+2<n) else -1 

        if l != -1 and self._data[l] < self._data[min_index]:
            min_index = l

        if r != - 1 and self._data[r] < self._data[min_index]:
            min_index = r

        if i != min_index:
            self._swaps.append((i, min_index))
            self._data[i], self._data[min_index] = \
                self._data[min_index], self._data[i]
            self.swapdown(min_index)

    def GenerateSwaps(self):
        for i in range(len(self._data)//2 ,-1,-1):
            self.swapdown(i)

    def Solve(self):
        self.ReadData()
        self.GenerateSwaps()
        self.WriteResponse()

if __name__ == '__main__':
    heap_builder = HeapBuilder()
    heap_builder.Solve()

有人可以解释筛选/交换方法的问题吗?

1 个答案:

答案 0 :(得分:2)

尝试从底部“交换”来构建堆并不总是有效。结果数组不一定是有效的堆。例如,考虑以下数组:[3,6,2,4,5,7,1]。以树的形式查看:

       3
    4     2
   6 5   7 1

您的算法从最后一项开始,并朝根交换。因此,您将1与2交换,然后将1与3交换。这将给您:

       1
    4     3
   6 5   7 2

然后您继续其余的项目,无需移动。

结果是无效的堆:最后一项2应该是3的父项。

这里的关键是交换方法假定处理完a[i]后,在该位置结束的项目位于其最终位置。与此相比,向下交换方法允许重复调整堆中较低的项。