php 數組的結構和定義

來源:互聯網
上載者:User

標籤:osi   index   ade   nbsp   div   如何   沒有   php 數組   情況下   

數組是PHP中非常強大、靈活的一種資料類型,它的底層實現為散列表(HashTable,也稱作:雜湊表)

散列表是根據關鍵碼值(Key value)而直接進行訪問的資料結構,它的key - value之間存在一個映射函數,可以根據key通過映射函數直接索引到對應的value值,它不以關鍵字的比較為基本操作,採用直接定址技術(就是說,它是直接通過key映射到記憶體位址上去的),從而加快尋找速度,在理想情況下,無須任何比較就可以找到待查關鍵字,尋找的期望時間為O(1)。

存放記錄的數組稱做散列表,這個數組用來儲存value,而value具體在數組中的儲存位置由映射函數根據key計算確定,映射函數可以採用模數的方式,key可以通過一些譬如“times 33”的演算法得到一個整形值,然後與數組總大小模數得到在散列表中的儲存位置。這是一個普通散列表的實現,PHP散列表的實現整體也是這個思路,只是有幾個特殊的地方,下面就是PHP中HashTable的資料結構:

 1 struct _zend_array { 2     zend_refcounted_h gc; //引用計數 3     union { 4         struct { 5             ZEND_ENDIAN_LOHI_4( 6                 zend_uchar    flags, 7                 zend_uchar    nApplyCount, 8                 zend_uchar    nIteratorsCount, 9                 zend_uchar    consistency)10         } v;11         uint32_t flags;12     } u;13     uint32_t          nTableMask; //雜湊值計算掩碼,等於nTableSize的負值(nTableMask = -nTableSize)14     Bucket           *arData;     //儲存元素數組,指向第一個Bucket15     uint32_t          nNumUsed;   //已用Bucket數16     uint32_t          nNumOfElements; //雜湊表有效元素數17     uint32_t          nTableSize;     //雜湊表總大小,為2的n次方18     uint32_t          nInternalPointer;19     zend_long         nNextFreeElement; //下一個可用的數值索引,如:arr[] = 1;arr["a"] = 2;arr[] = 3;  則nNextFreeElement = 2;20     dtor_func_t       pDestructor;21 };

HashTable中有兩個非常相近的值:nNumUsednNumOfElementsnNumOfElements表示雜湊表已有元素數,那這個值不跟nNumUsed一樣嗎?為什麼要定義兩個呢?實際上它們有不同的含義,當將一個元素從雜湊表刪除時並不會將對應的Bucket移除,而是將Bucket儲存的zval修改為IS_UNDEF,只有擴容時發現nNumOfElements與nNumUsed相差達到一定數量(這個數量是:ht->nNumUsed - ht->nNumOfElements > (ht->nNumOfElements >> 5))時才會將已刪除的元素全部移除,重新構建雜湊表。所以nNumUsed>=nNumOfElements

HashTable中另外一個非常重要的值arData,這個值指向儲存元素數組的第一個Bucket,插入元素時按順序 依次插入 數組,比如第一個元素在arData[0]、第二個在arData[1]...arData[nNumUsed]。PHP數組的有序性正是通過arData保證的,這是第一個與普通散列表實現不同的地方。

既然arData並不是按key映射的散列表,那麼映射函數是如何將key與arData中的value建立映射關係的呢?

實際上這個散列表也在arData中,比較特別的是散列表在ht->arData記憶體之前,分配記憶體時這個散列表與Bucket數組一起分配,arData向後移動到了Bucket數組的起始位置,並不是申請記憶體的起始位置,這樣散列表可以由arData指標向前移動訪問到,即arData[-1]、arData[-2]、arData[-3]......散列表的結構是uint32_t,它儲存的是value在Bucket數組中的位置。

所以,整體來看HashTable主要依賴arData實現元素的儲存、索引。插入一個元素時先將元素按先後順序插入Bucket數組,位置是idx,再根據key的雜湊值對應到散列表中的某個位置nIndex,將idx存入這個位置;尋找時先在散列表中映射到nIndex,得到value在Bucket數組的位置idx,再從Bucket數組中取出元素。

 

映射函數(即:散列函數)是散列表的關鍵區段,它將key與value建立映射關係,一般映射函數可以根據key的雜湊值與Bucket數組大小模數得到,即key->h % ht->nTableSize,但是PHP卻不是這麼做的:

nIndex = key->h | ht->nTableMask;

顯然位元運算要比模數更快。

nTableMasknTableSize的負數,即:nTableMask = -nTableSize,因為nTableSize等於2^n,所以nTableMask二進位位右側全部為0,也就保證了nIndex落在數組索引的範圍之內(|nIndex| <= nTableSize):

 

雜湊碰撞是指不同的key可能計算得到相同的雜湊值(數值索引的雜湊值直接就是數值本身),但是這些值又需要插入同一個散列表。一般解決方案是將Bucket串成鏈表,尋找時遍曆鏈表比較key。

PHP的實現也是如此,只是將鏈表的指標指向轉化為了數值指向,即:指向衝突元素的指標並沒有直接存在Bucket中,而是儲存到了value的zval中:

 1 struct _zval_struct { 2     zend_value        value;            /* value */ 3     ... 4     union { 5         uint32_t     var_flags; 6         uint32_t     next;                 /* hash collision chain(雜湊碰撞鏈) */ 7         uint32_t     cache_slot;           /* literal cache slot */ 8         uint32_t     lineno;               /* line number (for ast nodes) */ 9         uint32_t     num_args;             /* arguments number for EX(This) */10         uint32_t     fe_pos;               /* foreach position */11         uint32_t     fe_iter_idx;          /* foreach iterator index */12     } u2;13 };

當出現衝突時將原value的位置儲存到新value的zval.u2.next中,然後將新插入的value的位置更新到散列表,也就是後面衝突的value始終插入header

數組中儲存元素的結構

1 typedef struct _Bucket {2     zval              val; //儲存的具體value,這裡嵌入了一個zval,而不是一個指標3     zend_ulong        h;   //key根據times 33計算得到的雜湊值,或者是數值索引編號4     zend_string      *key; //儲存元素的key5 } Bucket;

 

php 數組的結構和定義

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.