为什么我对麻省理工学院的算法导论PSet 2编码练习的答案不适用于他们提供的测试?

时间:2016-03-21 21:59:17

标签: python algorithm

我正在自学麻省理工学院的算法导论:http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-006-introduction-to-algorithms-fall-2011/index.htm

我怀疑不是概念性的。更多的是为什么技术上正确且从CSLR中取出的解决方案无法使用问题集2中提供的特定测试代码。我相信这将有助于将来尝试自学该课程的任何人。

在问题集2中,有一个编码练习,其中需要将基于数组的优先级队列实现(Python类)重写为基于堆的优先级队列实现。可以在此处获取问题集和解决方案:http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-006-introduction-to-algorithms-fall-2011/assignments/

所以这是麻省理工学院提供的解决方案:

class PriorityQueue:
    """Heap-based priority queue implementation."""

    def __init__(self):
        """Initially empty priority queue."""
        self.heap = [None]

    def __len__(self):
        # Number of elements in the queue.
        return len(self.heap) - 1

    def append(self, key):
        """Inserts an element in the priority queue."""
        if key is None:
            raise ValueError('Cannot insert None in the queue')

        i = len(self.heap)
        self.heap.append(key)
        while i > 1:
            parent = i // 2
            if key < self.heap[parent]:
                self.heap[i], self.heap[parent] = self.heap[parent], key
                i = parent
            else:
                break

    def min(self):
        """Returns the smallest element in the queue."""
        return self.heap[1]

    def pop(self):
        """Removes the minimum element in the queue.

        Returns:
            The value of the removed element.
        """
        heap = self.heap
        popped_key = heap[1]
        if len(heap) == 2:
            return heap.pop()
        heap[1] = key = heap.pop()

        i = 1
        while True:
            left = i * 2
            if len(heap) <= left:
                break
            left_key = heap[left]
            right = i * 2 + 1
            right_key = right < len(heap) and heap[right]
            if right_key and right_key < left_key:
                child_key = right_key
                child = right
            else:
                child_key = left_key
                child = left
            if key <= child_key:
                break
            self.heap[i], self.heap[child] = child_key, key
            i = child
        return popped_key

根据我从CSLR学习的内容,这是我的解决方案:

class PriorityQueue:
    """binary min-heap implementation of priority-queue"""
    def __init__(self):
     """Initially empty priority queue."""
     self.heap = []

    def __len__(self):
        # Number of elements in the heap.
        return len(self.heap)

    def parent(self, i):
        return i // 2

    def left(self, i):
        return 2*i

    def right(self, i):
        return 2*i + 1

    def decreaseKey(self, i, key):
        currentKey = self.heap[i]

        if key > currentKey:
            raise ValueError("New key is larger than current key")

        currentKey = key
        parentKey = self.heap[self.parent(i)]
        while i > 1 and parentKey > currentKey:
            currentKey, parentKey = parentKey, currentKey
            i = self.parent(i)

    def append(self, key):
        """Inserts an element in the priority heap."""
        if key is None:
            raise ValueError('Cannot insert None in the heap')
        self.heap.append(float("inf"))

        self.decreaseKey(len(self.heap) - 1, key)

    def min(self):
        """The smallest element in the heap."""
        if len(self.heap) == 0:
            return None

        return self.heap[0]

    def pop(self):
        """Removes the minimum element in the heap.

        Returns:
            The value of the removed element.
        """

        if len(self.heap) == 0:
            return None

        min = self.min()
        self.heap[0] = self.heap[-1]
        self.minHeapify(0)
        return min

    def minHeapify(self, i):
        l = self.left(i)
        r = self.right(i)
        leftKey = self.heap[l]
        rightKey = self.heap[r]
        currentKey = self.heap[i]
        heapSize = len(self.heap)
        if l < heapSize and leftKey < currentKey:
            smallest = l
        else:
            smallest = i
        if r <= heapSize and rightKey < smallest:
            smallest = r
        if smallest != i:
            currentKey, self.heap[smallest] = self.heap[smallest], currentKey
            self.minHeapify(smallest)

我得到的错误是:

Traceback (most recent call last):
  File "circuit.py", line 659, in <module>
    sim.run()
  File "circuit.py", line 541, in run
    in_transition[0]))
  File "circuit.py", line 382, in append
    self.decreaseKey(len(self.heap) - 1, key)
  File "circuit.py", line 367, in decreaseKey
    if key > currentKey:
  File "circuit.py", line 300, in __gt__
    return (self.time > other.time or
AttributeError: 'float' object has no attribute 'time'

我认为这意味着当我在类PriorityQueue(我创建的)的属性之间进行比较时,它是出于某种原因使用先前定义的类的__gt__方法,称为Transition。

除此之外,当我将提供的解决方案与我自己的解决方案(基于CSLR)进行比较时,他们基本上都在做同样的事情。

2 个答案:

答案 0 :(得分:1)

self.heap应包含Transition个对象(具有time属性)。 在PriorityQueue.append中,您插入float,而Transition对象应该是time对象,其def append(self, key): """Inserts an element in the priority heap.""" if key is None: raise ValueError('Cannot insert None in the heap') self.heap.append(Transition(gate, new_output, float("inf"))) self.decreaseKey(len(self.heap) - 1, key) 属性设置为无穷大。

gate

编辑:也许我需要准确一点,虽然这应该可以解决问题,但我认为不应该这样做。官方修正仍然更好。

Edit2:当然,您需要将new_output[2,3,-2,4]替换为合理的值。

答案 1 :(得分:0)

问题可能与您i > 1中的比较decreaseKey有关。鉴于根位于索引0,比较1而不是0是非常奇怪的。当1处的子节点低于根时,代码将无法交换它们。

麻省理工学院提供的解决方案具有相同的奇怪比较,但他们通过在索引0(注意self.heap = [None]return len(self.heap) - 1)放置一个死元素来证明它的合理性,因此它们的根确实是1。