1、PHP動態(tài)語言執(zhí)行過程:拿到一段代碼后,經(jīng)過詞法解析、語法解析等階段后,源程序會被翻譯成一個個指令(opcodes),然后ZEND虛擬機順次執(zhí)行這些指令完成操作。PHP本身是用C實現(xiàn)的,因此最終調(diào)用的也是C的函數(shù),實際上,我們可以把PHP看做一個C開發(fā)的軟件。
創(chuàng)新互聯(lián)主要從事成都網(wǎng)站制作、成都網(wǎng)站設計、網(wǎng)頁設計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務。立足成都服務武威,十年網(wǎng)站建設經(jīng)驗,價格優(yōu)惠、服務專業(yè),歡迎來電咨詢建站服務:18980820575
2、PHP的4層運行體系:
(1)Zend引擎:Zend整體用純C實現(xiàn),是PHP的內(nèi)核部分,他將PHP代碼翻譯(詞法、語法解析等一系列編譯過程)為可執(zhí)行opcode的處理并實現(xiàn)相應的處理方法、實現(xiàn)了基本的數(shù)據(jù)結構(如:hashtable、OO)、內(nèi)存分配機制及管理、提供了相應的api方法供外部調(diào)用,是一切的核心,所有的外圍功能均圍繞Zend實現(xiàn)。
(2)Extensions:圍繞著Zend引擎,extensions通過組件式的方式提供各種基礎服務,我們常見的各種內(nèi)置函數(shù)(array系列)、標準庫等都是通過extension來實現(xiàn),用戶也可以根據(jù)需要實現(xiàn)自己的extension的典型應用)。
(3)Sapi:Sapi全稱ServerApplicationProgrammingInterface,也就是服務端應用編程接口,Sapi通過一系列鉤子函數(shù),使得PHP可以和外圍交互數(shù)據(jù),這是PHP非常優(yōu)雅和成功的設計,通過sapi成功的將PHP本身和上層應用解耦隔離,PHP可以不再考慮如何針對不同應用進行兼容,而應用本身也可以針對自己的特點實現(xiàn)不同的處理方式。
(4)上層應用:這就是我們平時編寫的PHP程序,通過不同的spai方式得到各種各樣的應用模式,如何通過webserver實現(xiàn)web應用、在命令行下已腳本方式運行等等。
hashtable 中文應該是翻譯為:哈希表。散列表(Hash table,也叫哈希表),是根據(jù)關鍵碼值(Key value)而直接進行訪問的數(shù)據(jù)結構。也就是說,它通過把關鍵碼值映射到表中一個位置來訪問記錄,以加快查找的速度。這個映射函數(shù)叫做散列函數(shù),存放記錄的數(shù)組叫做散列表。
具體進一步的了解,建議你看計算機專業(yè)的數(shù)據(jù)結構方面的教程。
PHP 使用HashTable來保存數(shù)組信息,md5/sha1都是哈希表的算法,具體的應用比如:文件校驗、數(shù)字簽名等。
先看一下hash表的結構圖:
哈希表(Hash table,也叫散列表),是根據(jù)鍵(Key)而直接訪問在內(nèi)存存儲位置的數(shù)據(jù)結構。也就是說,它通過計算一個關于鍵值的函數(shù),將所需查詢的數(shù)據(jù)映射到表中一個位置來訪問記錄,這加快了查找速度。這個映射函數(shù)叫做散列函數(shù),存放記錄的數(shù)組叫做散列表
白話一點的說就是通過把Key通過一個固定的算法函數(shù)(hash函數(shù))轉換成一個整型數(shù)字,然后就對該數(shù)字對數(shù)組的長度進行取余,取余結果就當作數(shù)組的下標,將value存儲在以該數(shù)字為下標的數(shù)組空間里。
先了解一下下面幾個常說的幾個關鍵字是什么:
key :我們輸入待查找的值
value :我們想要獲取的內(nèi)容
hash值 :key通過hash函數(shù)算出的值(對數(shù)組長度取模,便可得到數(shù)組下標)
hash函數(shù)(散列函數(shù)) :存在一種函數(shù)F,根據(jù)這個函數(shù)和查找關鍵字key,可以直接確定查找值所在位置,而不需要一個個遍歷比較。這樣就預先知道key在的位置,直接找到數(shù)據(jù),提升效率。
即
地址index=F(key)
hash函數(shù)就是根據(jù)key計算出該存儲地址的位置,hash表就是基于hash函數(shù)建立的一種查找表。
方法有很多種,比如直接定址法、數(shù)字分析法、平方取中法、折疊法、隨機數(shù)法、除留余數(shù)法等,網(wǎng)上相關介紹有很多,這里就不重點說這個了
對不同的關鍵字可能得到同一散列地址, 即k1≠k2,而f(k1)=f(k2),或f(k1) MOD 容量 =f(k2) MOD 容量 ,這種現(xiàn)象稱為 碰撞 ,亦稱 沖突 。
通過構造性能良好的hash函數(shù),可以減少沖突,但一般不可能完全避免沖突,因此解決沖突是hash表的另一個關鍵問題。
創(chuàng)建和查找hash表都會遇到?jīng)_突,兩種情況下解決沖突的方法應該一致。
這里要提到兩個參數(shù): 初始容量 , 加載因子 ,這兩個參數(shù)是影響hash表性能的重要參數(shù)。
容量 : 表示hash表中數(shù)組的長度,初始容量是創(chuàng)建hash表時的容量。
加載因子 : 是hash表在其容量自動增加之前可以達到多滿的一種尺度(存儲元素的個數(shù)),它衡量的是一個散列表的空間的使用程度。
loadFactor = 加載因子 / 容量
一般情況下,當loadFactor = 1時,hash表查找的期望復雜度為O(1).
對使用鏈表法的散列表來說, 負載因子越大,對空間的利用更充分,然后后果是查找效率的降低;如果負載因子太小,那么散列表的數(shù)據(jù)將過于稀疏,對空間造成嚴重浪費 。系統(tǒng)默認負載因子為0.75。
當hash表中元素越來越多的時候,碰撞的幾率也就越來越高(因為數(shù)組的長度是固定的),所以為了提高查詢的效率,就要對數(shù)組進行擴容。而在數(shù)組擴容之后,最消耗性能的點就出現(xiàn)了,原數(shù)組中的數(shù)據(jù)必須重新計算其在新數(shù)組中的位置,并放進去,這就是 擴容 。
什么時候進行擴容呢?當表中 元素個數(shù)超過了容量 * loadFactor 時,就會進行數(shù)組擴容。
Foundation框架下提供了很多高級數(shù)據(jù)結構,很多都是和Core Foundation下的相對應,例如NSSet就是和_CFSet相對應,NSDictionary就是和_CFDictionary相對應。 源碼
這里說的hash并不是之前說的hash表,而是一個方法。為什么要有hash方法?
這個問題需要從hash表數(shù)據(jù)結構說起,首先看下如何在數(shù)組中查找某個成員
在數(shù)組未排序的情況下,查找的時間復雜度是O(n)(n為數(shù)組長度)。hash表的出現(xiàn),提高了查找速度,當成員被加入到hash表中時,會計算出一個hash值,hash值對數(shù)組長度取模,會得到該成員在數(shù)組中的位置。
通過這個位置可以將查找的時間復雜度優(yōu)化到O(1),前提是在不發(fā)生沖突的情況下。
這里的hash值是通過hash方法計算出來的,且hash方法返回的hash值最好唯一
和數(shù)組相比,基于hash值索引的hash表查找某個成員的過程:
可以看出優(yōu)勢比較明顯,最壞的情況和數(shù)組也相差無幾。
重寫person的hash方法和copyWithZone方法,方便查看hash方法是否被調(diào)用:
打印結果:
可以了解到: hash方法只在對象被添加到NSSet和設置為NSDictionary的key時被調(diào)用
NSSet添加新成員時,需要根據(jù)hash值來快速查找成員,以保證集合中是否已經(jīng)存在該成員。
NSDictionary在查找key時,也是利用了key的hash值來提高查找的效率。
這里可以得到這個結論:
相等變量的hash結果總是相同的,不相等變量的hash結果有可能相同
根據(jù)數(shù)據(jù)結構可以發(fā)現(xiàn)set內(nèi)部使用了指針數(shù)組來保存keys,可以從 源碼 中了解到采用的是連續(xù)存儲的方式存儲。
NSSet添加key,key值會根據(jù)特定的hash函數(shù)算出hash值,然后存儲數(shù)據(jù)的時候,會根據(jù)hash函數(shù)算出來的值,找到對應的下標,如果該下標下已有數(shù)據(jù),開放定址法后移動插入,如果數(shù)組到達閾值,這個時候就會進行擴容,然后重新hash插入。查詢速度就可以和連續(xù)性存儲的數(shù)據(jù)一樣接近O(1)了。
和上面的集合NSSet相比較,多了一個指針數(shù)組values。
通過比較集合NSSet和字典NSDictionary的 源碼 可以知道兩者實現(xiàn)的原理差不多,而字典則用了兩個數(shù)組keys和values,說明這兩個數(shù)據(jù)是被分開存儲的。
通過源碼可以看到,當有重復的key插入到字典NSDictionary時,會覆蓋舊值,而集合NSSet則什么都不做,保證了里面的元素不會重復。
大家都知道,字典里的鍵值對key-value是一一對應的關系,從數(shù)據(jù)結構可以看出,key和value是分別存儲在兩個不同的數(shù)組里,這里面是如何對key、value進行綁定的呢?
首先 key利用hash函數(shù)算出hash值,然后對數(shù)組的長度取模,得到數(shù)組下標的位置,同樣將這個地址對應到values數(shù)組的下標,就匹配到相應的value。 注意到上面的這句話,要保證一點, 就是keys和values這兩個數(shù)組的長度要一致 。所以擴容的時候,需要對keys和values兩個數(shù)組一起擴容。
對于字典NSDictionary設置的key和value,key值會根據(jù)特定的hash函數(shù)算出hash值,keys和values同樣多,利用hash值對數(shù)組長度取模,得到其對應的下標index,如果下標已有數(shù)據(jù),開放定址法后移插入,如果數(shù)組達到閾值,就擴容,然后重新hash插入。這樣的機制就把一些不連續(xù)的key-value值插入到能建立起關系的hash表中。
查找的時候,key根據(jù)hash函數(shù)以及數(shù)組長度,得到下標,然后根據(jù)下標直接訪問hash表的keys和values,這樣查詢速度就可以和連續(xù)線性存儲的數(shù)據(jù)一樣接近O(1)了。
參考文章: 筆記-數(shù)據(jù)結構之 Hash(OC的粗略實現(xiàn))
哈希表的存儲結構為散列函數(shù)。
散列技術是在記錄的存儲位置和它的關鍵字之間建立一個確定的對應關系f,使得每個關鍵字key對應一個存儲位置f(key)。
這里把這種對應關系f稱為散列函數(shù),又稱為哈希(Hash)函數(shù)。按這個思想,采用散列技術將記錄存在在一塊連續(xù)的存儲空間中,這塊連續(xù)存儲空間稱為散列表或哈希表。那么,關鍵字對應的記錄存儲位置稱為散列地址。
散列技術最適合的求解問題是查找與給定值相等的記錄。對于查找來說,簡化了比較過程,效率會大大 提高。但是,散列技術部具備很多常規(guī)數(shù)據(jù)結構的能力,如比較同樣的關鍵字,對應很多記錄的情況,不適合用散列技術;散列表也不適合范圍查找等等。
在理想的情況下,每一個關鍵字,通過散列函數(shù)計算出來的地址都是不一樣的,可現(xiàn)實中,這只是一個理想。市場會碰到兩個關鍵字key1 != key2,但是卻有f(key1) = f(key2),這種現(xiàn)象稱為沖突。出現(xiàn)沖突將會造成查找錯誤,因此可以通過精心設計散列函數(shù)讓沖突盡可能的少,但是不能完全避免。
本文標題:php數(shù)據(jù)結構哈希結構 數(shù)據(jù)結構 哈希表
標題URL:http://www.chinadenli.net/article2/ddohjic.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站策劃、動態(tài)網(wǎng)站、網(wǎng)頁設計公司、網(wǎng)站設計、微信小程序、云服務器
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉載內(nèi)容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)