python 動態陣列 list 記憶體對映,leetcode 707,真連結串列能打敗假連結串列嗎?
為什麼寫這個,我在leetcode刷題(leetcode 707 設計連結串列 Design Linked List),有個設計連結串列的題,還特意加了尾指標,也試過雙鏈表,結果時間上還是跑不過別人的直接用list去append和insert的方案,所以隨便測一下動態陣列list的實現機制。只測了個大概,可能有不嚴謹的地方或者瞭解不全面的地方,歡迎指正。
目錄
從頭部刪除一個元素,再從頭部插入一個元素,是維持原來的記憶體佔用嗎?
最騷的操作是,他從來不整體複製,新增的部分確實會開闢新空間,但是原來的元素是不會輕易移動的。
結論:python list高度封裝,你能想到的點他基本都處理掉了,建立了訪問對映機制,記憶體分佈無論多亂都不影響外部訪問。
用時對比圖
python動態陣列list機制探索
如果size不超,難道就不重新分配空間了嗎?
"動態陣列的機制是分配一塊固定capacity的空間,如果size超出capacity就會重新分配一塊更大capacity的空間",死知識是這樣的。實際上呢,肯定不是!!!
下面就是一個size一直不超過2,但是記憶體重新分配的例子。
剛開始應該是分配到棧空間了。加一個元素,刪一個元素,動態陣列的實現機制,肯定是後延的,最後超出了初始指定的範圍以後,直接去堆空間重新劃分了一塊。
l = [0]
for i in range(1,1000):
print(l)
# print(id(l))
print(id(l[0]))
l.append(i)
l.remove(i-1)
所以尾插,刪頭部,size不增長,和正常使用size增長超過capacity是一個效果。
從頭部刪除一個元素,再從頭部插入一個元素,是維持原來的記憶體佔用嗎?
l = [1,2] print(l) print(id(l[0])) print(id(l[1])) l.remove(1) print(l) print(id(l[0])) l.insert(0,5) print(l) print(id(l[0])) print(id(l[1]))
並不是,新的index-0是xxx456,比原來最大的xxx360還大,關鍵是index-1還維持原來地址,並不同步複製到後邊。可以看出,動態陣列的實現為了效能的考量,基本上,能不復制能不移動,都是不復制不移動的。
最騷的操作是,他從來不整體複製,新增的部分確實會開闢新空間,但是原來的元素是不會輕易移動的。
l = [-4,-3,-2,0]
for i in range(1,1000):
print(l)
# print(id(l))
l.append(i)
print(id(l[0]),id(l[1]),id(l[2]),id(l[3]))
l.remove(i-1)
還有刪除操作,就算把地址空出來也不會有額外變動
l = [-4,-3,-2,0]
print(id(l[0]),id(l[1]),id(l[2]),id(l[3]))
l.remove(-2)
print(id(l[0]),id(l[1]),id(l[2]))
==============================================================================================================================================================================================
結論:python list高度封裝,你能想到的點他基本都處理掉了,建立了訪問對映機制,記憶體分佈無論多亂都不影響外部訪問。
假連結串列所有方面都不輸,完全沒有多餘的複製操作,頭尾插入和刪除全是O(1),刪除指定index也是O(1),而真連結串列只能O(n)。
所以真連結串列很難比用動態陣列實現的假連結串列快。不是很難,是不能!吧?