順序表的原理與python中的list類型


數據是如何在內存中存儲的?

在32位的計算機上,1個字節有8位,內存尋址的最小單位就是字節。假設我們有一個int類型的值,它從0x10開始,一個int占據4個字節,則其結束於0x13。

那么數據類型有什么意義呢?

它確定了一個特定類型的數據到底要申請多大的內存地址來存儲(大小),並且決定取到的二進制數應該如何解釋(意義)。

地址里存儲的只有二進制數,但對於數字和字符同一二進制數代表的意義是不同的。

同類型的數據在內存中是如何連續存儲的?

假設有一個四個數的集合 24, 299, 10, 4,將它們連續地存儲在一起時,在內存里的表現就像是它們緊挨着擠在一起。如果第一個元素從0x10開始,那整個集合就在0x25結束。每個元素都是內置在地址中的。代表集合的變量指向集合的開始地址0x10,要找到第一個元素就加上4。

因為類型相同,則每個元素的偏移量也相同,就可以有下圖的公式(c就是元素類型的大小)。

這也是為什么集合要從0開始了:元素下標表示的就是一個特定偏移量單位,第0個元素自然是沒有任何偏移的。獲得特定元素,也不需要遍歷整個集合,計算偏移量即可。

不同類型的數據集合在內存中是如何存儲的?

當不同的元素要擠在一個集合里時,用偏移量來定位就靠不住了,畢竟各自大小都不同。但不要忘了,內存地址本身的大小是固定的。

假設集合里有12, 1.24, 'ab' 三種不同的元素,它們的位置各不連續,分散在不同的地方。就申請一塊3個元素大小的連續內存區域,里面每個元素都分別指向集合內的元素。

這時的元素是外置的。

 

順序表在內存中的結構是什么?

要在內存中給集合開辟一塊區域,總得先確定大小(容量),不然如何開辟?另外,確定區域后,還要知道當前已經占用了幾個元素(元素個數),一旦溢出,就需要重新申請空間。

要表達這種結構,有兩種實現方式。一種是把頭信息和元素串到一起,形成一個元素個數+2的表。另一種就是把頭信息和元素分開放,兩者之間用一個元素建立一個鏈接,連在一起。

存儲表信息的單元與元素存儲區以連續的方式安排在一塊存儲區里,兩部分數據的整體形成一個完整的順序表對象。一體式結構整體性強,易於管理。但是由於數據元素存儲區域是表對象的一部分,順序表創建后,元素存儲區就固定了。

分離式結構中表對象里只保存與整個表有關的信息(即容量和元素個數),實際數據元素存放在另一個獨立的元素存儲區里,通過鏈接與基本表對象關聯。

一旦表需要擴充,對於一體式結構來說,就要重新申請一塊更大的空內存區域,將所有元素放入其中,再清空舊的內存區域。

對於分離式結構來說,則需要將鏈接地址更新一下,順序表對象是不變的。

說到擴充,又是如何進行的呢?

采用分離式結構的順序表,若將數據區更換為存儲空間更大的區域,則可以在不改變表對象的前提下對其數據存儲區進行了擴充,所有使用這個表的地方都不必修改。

擴充的策略可以說有兩種。

每次擴充增加固定數目的存儲位置,如每次擴充增加10個元素位置,這種策略可稱為線性增長。特點:節省空間,但是擴充操作頻繁,操作次數多。

(就是以時間換空間,以后每次添加的元素過多就要多花時間重新擴容)

每次擴充容量加倍,如每次擴充增加一倍存儲空間。特點:減少了擴充操作的執行次數,但可能會浪費空間資源。

(以空間換時間,每次擴容占用的空間大了,但擴容就可以少執行些)

 

說了以上這么多,這時我們就可以審視一下python中的list。

list有以下幾個特點:

1.元素有位置下標,以索引就可以直接取到元素  -->  連續的存儲空間,以偏移量計算取得元素,不必遍歷所有元素

2.元素無論如何改變,表對象不變,也就是其id不變  -->  分離式結構,表頭和元素內容分開儲存,這樣在更改list時,表對象始終是同一個,只是其指向的地址不同

3.元素可以是任意類型  -->  既要要求是連續存儲,又可以存儲不同類型的數據,那么其用的就是元素外置的方式,存儲的只是地址的引用

4.可以任意添加新元素  -->  要能不斷地添加新元素,其使用了動態擴充的策略

從實現上來講,在python中創建空ist時,會申請一個8個元素大小的內存區域。以后如果滿了,就擴容4倍,且當元素總數達到50000時,再擴容就改為2倍。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM