簡體   English   中英

在Python中從列表開頭刪除元素便宜嗎?

[英]Is removing an element from the front of a list cheap in Python?

我正在編寫一個程序,該程序在數據列表的前面或后面進行了大量刪除操作,而不是在中間進行刪除。

我知道刪除最后一個元素很便宜,但是刪除第一個元素又如何呢? 例如,假設列表A的地址為4000 ,因此元素04000 ,元素14001

刪除元素0然后只是使編譯器將列表A的地址放在4001 ,還是將4001元素1移到4000的位置,並將所有其他元素下移1

不,它並不便宜。 從列表的list.pop(0)刪除元素list.pop(0)例如,使用list.pop(0) )是O(N)操作, 應避免 同樣,在開頭插入元素(使用list.insert(0, <value>) )同樣效率低下。

這是因為在調整列表大小之后,必須更改其元素。 對於CPython,在l.pop(0)情況下, 這是通過memmove完成的,而對於l.insert(0, <value>)則通過循環存儲的項來實現移位

列表是專為快速隨機訪問O(1)對他們的最終操作。


但是,由於通常是執行此操作,因此應考慮使用collections模塊中deque (如@ayhan在評論中建議的那樣)。 deque上的文檔還強調了list對象不適合這些操作的方式:

盡管列表對象支持類似的操作,但它們針對快速定長操作進行了優化,並且會為pop(0)insert(0, v)操作產生O(n)內存移動成本,這會改變基礎數據表示的大小和位置。

(強調我的)

deque數據結構為兩側(開頭和結尾)提供O(1)復雜性,分別為appendleft和end使用appendleft / popleftappend / pop方法。

當然,對於較小的列表,這會導致一些額外的空間需求(由於deque的結構),通常不需要考慮(並且正如@juanpa在評論中指出的那樣,並不總是如此),因為列表的大小增長。 最后,正如@ShadowRanger富有洞察力的評論所指出的那樣,由於序列大小非常小,因此從前面彈出或插入的問題變得無關緊要,以至於實際上變得無關緊要。

簡而言之,對於包含很多項目的列表,如果需要從兩側快速添加/彈出,請使用deque ;否則,如果您要隨機訪問並追加到末尾,請使用list

從Python中的列表開頭刪除元素是O(n),而從collections的結尾刪除元素。deque僅為O(1)。 因此,雙端隊列對您的目的非常有用,但是應該注意,從雙端隊列的中間進行訪問或添加/刪除比列表的開銷更大。

刪除的O(n)成本是因為CPython中的列表只是實現為一個指針數組,因此您對每個元素的轉換成本的直覺是正確的。

這可以在Wiki上的Python TimeComplexity頁面中看到。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM