我的代码如下所示,其中heap
是list
:
heap[0] = heap.pop()
问题是弹出唯一的项目时不起作用。根据python wiki,弹出最后一个元素是O(1)。 (我也想删除最后一个元素)
到目前为止,我提出了什么:
last_element = heap.pop() # I don't want to catch potential IndexError here
try:
heap[0] = last_element
except IndexError:
heap.append(last_element)
这是更长的
或者
if len(heap) != 1:
heap[0] = heap.pop()
应该更慢。
有更多的pythonic方法吗?内部python可能甚至没有调整数组的大小。
更新: 我需要O(1)访问给定indeces的元素(因此它不能是链表)。
答案 0 :(得分:6)
听起来你正在实现一个堆,这一行是heap-pop操作实现的一部分。在上下文中,它看起来像
def heappop_wrong(heap):
popped_value = heap[0]
heap[0] = heap.pop() # <-- here
sift_down(heap, 0)
return popped_value
在这种情况下,如果列表只有一个元素,则不应该将最后一个元素移到前面。您应该删除并返回唯一的元素:
def heappop(heap):
if len(heap) == 1:
return heap.pop()
popped_value = heap[0]
heap[0] = heap.pop()
sift_down(heap, 0)
return popped_value
至于if
的费用,这笔费用是微不足道的,根本不是你应该担心的事情。
为了将列表的最后一个元素移动到前面而不用替换旧的前面元素,这在O(1)时间内是不可能的。您必须使用不同的数据结构,例如collections.deque
,或者实现您自己的可调整大小的ring buffer。但是,这与堆用例无关。
如果将列表的最后一个元素移到前面,如果有多个元素则踩过旧的第一个元素,如果只有一个元素则保持列表不变,if
检查可能是最清楚的,但是再次,“如果只有一个元素,则保持列表不变”行为对于实现堆弹出实际上没有用。
答案 1 :(得分:3)
一种有效的方法(无例外,只要list
非空)就是分配给list
的切片:
heap[:1] = (heap.pop(),)
弹出最后一个元素并创建一个长度1 tuple
,然后将其分配给heap
,以便它替换第一个元素(如果存在),或者成为{{1的内容如果它是空的(由于list
)。它应该保持pop
,因为它总是用单个元素替换单个元素;更高的指数没有受到影响。
答案 2 :(得分:0)
collections.deque
支持在O(1)中删除和附加正面和背面。
答案 3 :(得分:0)
您可以在尝试弹出之前检查列表是否为空。
Error: package or namespace load failed for ‘sf’ in dyn.load(file, DLLpath = DLLpath, ...):
默认情况下,pop返回列表中的最后一个元素,因此您不必显式传递-1。并且由于如果列表为空它会引发错误,我们可以在尝试弹出之前检查其长度。
但是列表上的插入操作是O(n)。对于O(1),您将需要使用出队。
if len(a) > 0:
a.insert(0,a.pop())