从优先级队列中删除任意元素

时间:2017-10-26 13:35:39

标签: python heap priority-queue

我正在研究以下内容 - “对于此任务,您将实现EditablePatientHeapQueue,它可以使用新的删除方法在O(log n)时间内删除任意患者(按名称)。与大多数效率改进一样,我们将时间交换空间:我们将每个患者的索引存储在一个Python字典self.indices中,用他们的名字键入。这样,找到一个病人是O(1)时间,所以占主导地位的操作是随后的筛选计划中的皱纹是我们需要跟踪患者的存储位置,即使在筛选时也是如此。因此,您应该提供一个新版本的enqueue,dequeue和_swap方法来接受新的自我。 .indices字典考虑在内。“

我的实施

class EditablePatientHeapQueue(PatientHeapQueue):
    """ Implement a queue structure using a 0-indexed heap. This particular type of queue holds patient information. Additionally, we can remove patients not at the top of the heap in O(log n) time. """

    def __init__(self, start_data=None, fast=False):
        self.indices = {}  # name -> index;
                           # Keep track of where patients are stored
        for (i, person) in enumerate(start_data):
            self.indices[person.name] = i
        super().__init__(start_data, fast)


    def _swap(self, i, j):
        """ Swap patients at index i and j. Don't forget to change
            their position in self.indices as well!
        """   

        self.indices[self.data[i].name] = j
        self.indices[self.data[j].name] = i    
        self.data[i], self.data[j] = self.data[j], self.data[i]        


    def remove(self, patient_name):
        """ Remove the particular patient from the heap. Remember,
            the index will tell you where the patient is in the heap
            and every sub-heap below an index forms a valid heap.
        """

        #Dictionary self.indices- key (patient name) : value (index)
        #Heap self.data- patient name, priority 

        #Step 1: Find the patient in O(1) time and remove from the heap and dictionary

        #Retrieve the index for the patient name in O(1) time 
        patient_index = self.indices[patient_name] 
        end = len(self.data)-1

        #Swap patients 
        self._swap(patient_index, end)

        #Remove the patient from the heap and dictionary
        del self.data[end]  
        del self.indices[patient_name]

        #Step 2: Reheapify

        #Parent is greater than patient index then sift down 
        if patient_index != 0 and self.data[patient_index].priority < self.data[super()._parent_index(patient_index)].priority:
            super()._sift_down(patient_index)

        #Patient index is greater than parent then sift up 
        else:
            super()._sift_up(patient_index) 


    def enqueue(self, patient):
        """ Add a patient to the queue. 
        """
        assert isinstance(patient, Patient)
        self.data.append(patient)
        self.indices[patient.name] = len(self.data)-1
        super()._sift_up(len(self.data)-1)


    def dequeue(self):
        """ Remove a patient from the front of the queue and return them.
        """

        if len(self.data) == 0:
           return None
        elif len(self.data) == 1:
           del self.indices[self.data[0].name]
           return self.data.pop(0)
        else:
           patient = self.data[0]
           self.data[0] = self.data[len(self.data)-1] 
           self.indices[patient.name] = 0
           del self.indices[patient.name]
           del self.data[len(self.data)-1]  
           super()._sift_down(0)
           return patient 

我收到以下错误 - 1 builtins.AssertionError:违反了堆不变量!/ AssertionError:'remove'后坏堆不变量:     父母:病人(Elizabeth Battles,2676)     孩子:病人(Jonathan Bianchi,63801)

非常感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

我在你的代码中看到了一些问题。

首先,当您将项目排入队列时,您并未向self.indices添加条目。因此,当您尝试在字典中查找患者姓名时,它不存在。

dequeue方法中,您有以下代码:

    elif len(self.data) == 1:
        return self.data.pop()
    else:
        patient = self.data[0]
        self.data[0] = self.data[len(self.data)-1] 
        del self.indices[patient]
        del self.data[len(self.data)-1]  
        super()._sift_down(0)
        return patient 

elif案例中,您必须从self.indices删除该项目。

else案例中,我看到两个问题。在第二行,您将项目从堆的末尾移动到堆的顶部。没关系,但是你必须在字典中改变它的索引。我想你想添加这一行:

self.indicies[self.data[0].patientName] = 0

否则,当您尝试筛选该项目时,您的代码将会失败。

对于删除错误,我认为您的问题是您试图通过患者而不是患者姓名对indices进行索引。我建议更换这一行:

del self.indices[patient]

del self.indices[patient.name]

remove方法中,您有:

    #Remove the patient from the heap and dictionary
    del self.data[end]  
    del self.indices[patient_name]

    #Step 2: Reheapify

如果您要删除的项目是堆上的最后一项,您可能需要考虑接下来会发生什么。 patient_index将在self.data的结尾处编入索引。

将来,您可以考虑学习如何使用调试器添加断点并单步执行代码。这允许您观察所有数据结构的状态。例如,如果您单步执行dequeue方法,您就可以看到您正在传递patient而不是患者的姓名作为索引。字典。一个很好的资源是Eric Lippert的How to debug small programs