這篇文章帶給大家的內容是關於組的基礎架構介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
以下為 PHP 陣列的基礎結構,插入,尋找和 rehash 過程。
struct _zend_array { zend_refcounted_h gc; union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar flags, zend_uchar nApplyCount, zend_uchar nIteratorsCount, zend_uchar consistency) } v; uint32_t flags; } u; uint32_t nTableMask; // 哈希值计算掩码,等于nTableSize的负值(nTableMask = -nTableSize) Bucket *arData; // 存储元素数组,指向第一个Bucket uint32_t nNumUsed; // 已用Bucket数 uint32_t nNumOfElements; // 哈希表有效元素数 = nNumUsed - num(is_undef) uint32_t nTableSize; // 哈希表总大小,为2的n次方, 最小为8 uint32_t nInternalPointer; // 怀疑是内部指针 zend_long nNextFreeElement; // 下一个可用的数值索引 arr[] = 1;arr["a"] = 2;arr[] = 3; 则nNextFreeElement = 2; dtor_func_t pDestructor; }; typedef struct _Bucket { zval val; // 存储的具体value zend_ulong h; // hash value (or numeric index) zend_string *key; // string key or NULL for numerics } Bucket;
說明:
#陣列存放的時候先依照順序儲存 value,再儲存 value 的位置。
存放記錄的數組稱做散列表,這個數組用來存儲 value,而 value 按順序保存,其存儲位置會保存在由 key 計算 hash 取模 nTableMask 得到的 idx 中。
陣列初始化的時候最小大小為 8,以此為16,32,64。 。 。
陣列初始化的時候邊做的 idx 區會全部初始化為 -1,rehash 的時候也會初始化為 -1。
數組中刪除一個元素的時候,是把該刪除的元素的 type 標記為 is_undef, 並且 nNumOfEmelment - 1,如果該元素為最後一個元素,那麼 nNumUsed - 1。
插入:
以$arr = ['a'=>1, 'b'=>2] 為例:
先把1 放到數組中,其val.u2.next = -1, 根據其下標a 計算hash, 然後hash 取模nTableMask 得到一個idx, 在該idx 的位置保存前邊保存1 的索引nindex。
再存放2, 其val.u2.next = -1, 如果根據其下標b 計算hash 取模nTableMask 得到的idx 中已經有值,那麼說明出現了哈希碰撞,這個時候把目前idx 中的值取出來儲存到目前val.u2.next,把儲存2 的索引nindex 儲存在目前idx,以此類推。
查找:
根據下標a 計算hash 取模nTableMask 得到一個idx ,拿到該idx 中的值nindex 去arData 中查找,如果找到的位置中的key != a, 那麼找不到;如果找到的位置中的key == a,那麼檢查其u2.next, 如果為-1, 那麼找到了;如果不為-1,說明插入的過程中出現了哈希衝突,那麼根據u2.next 繼續在arData 中查找,直到找到為止。
rehash:
rehash 的時候,先把nindex 區的所有記錄全部重設為-1,然後從第一個元素開始挪動指標*p,如果元素沒有被標記為is_undef,那麼重新計算該元素的key hash 並放到nindex,然後循環, p 。如果元素被標記為is_undef, 那麼繼續挪動指標p ,並設定一個新的指標j 指向該位置,繼續循環,把後邊不為is_undef 的元素一個一個挪到前邊來,p 每次移動,j 遇到is_undef就不移動,直到被賦值。一直挪動到最後的 nNunUsed ,那麼把 j 賦值給 nNunUsed,之後再插入元素的時候就從這個位置開始插入,以前的元素直接被覆蓋就是了。
#以上是php數組的基礎結構介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!