1. 程式人生 > >python 動態陣列 list 記憶體對映,leetcode 707,真連結串列能打敗假連結串列嗎?

python 動態陣列 list 記憶體對映,leetcode 707,真連結串列能打敗假連結串列嗎?

 為什麼寫這個,我在leetcode刷題(leetcode 707 設計連結串列 Design Linked List),有個設計連結串列的題,還特意加了尾指標,也試過雙鏈表,結果時間上還是跑不過別人的直接用list去append和insert的方案,所以隨便測一下動態陣列list的實現機制。只測了個大概,可能有不嚴謹的地方或者瞭解不全面的地方,歡迎指正。

目錄

用時對比圖

python動態陣列list機制探索

如果size不超,難道就不重新分配空間了嗎?

從頭部刪除一個元素,再從頭部插入一個元素,是維持原來的記憶體佔用嗎?

最騷的操作是,他從來不整體複製,新增的部分確實會開闢新空間,但是原來的元素是不會輕易移動的。

還有刪除操作,就算把地址空出來也不會有額外變動

結論: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)。

所以真連結串列很難比用動態陣列實現的假連結串列快。不是很難,是不能!吧?