在c語言中,我們可以自定義各種各樣的資料結構,用來把很多資料儲存在乙個變數裡面,但是每種資料結構都有自己的優缺點,php核心規模如此龐大,是否已經找到了一些非常棒的解決方法呢?
我們在選擇各種資料結構時,往往會考慮我們需要處理的資料規模以及需要的效能。下面讓我們簡要的看一下看c語言中陣列和鍊錶的一些事情。
作者這裡用的不是array,而是vector,可能指的是c++裡的vector,它與陣列幾乎是完全一樣的,唯一的不同便是可以實現動態儲存。本節下文都是用陣列一詞代替之,請各位注意。陣列是記憶體中一塊連續的區域,其每乙個元素都具有乙個唯一的下標值。
int a[3];
a[0]=1;
a[2]=3;
不僅是整數,其它型別的變數也可以儲存在陣列中,比如我們前面用到的zend_get_parameters_array_ex(),便把很多zval**型別的變數儲存到乙個陣列裡,為了使其正常工作,我們提前向系統申請了相應大小的記憶體空間。
zval ***args = safe_emalloc(zend_num_args(), sizeof(zval**), 0);
這裡我們仍然可以用乙個整數來當作下標去陣列中取出我們想要的資料,就像var_dump()的實現中通過args[i]來獲取引數並把它傳遞給php_var_dump()函式那樣。
使用陣列最大的好處便是速度!讀寫都可以在o(1)內完成,因為它每個元素的大小都是一致的,只要知道下標,便可以瞬間計算出其對應的元素在記憶體中的位置,從而直接取出或者寫入。
typedef struct _namelist namelist;
struct
_namelist;
我們可以宣告乙個其型別的元素:
static namelist *people;
假設每乙個元素都代表乙個人,元素中的name屬性便是這個人的名字,我們通過這樣的語句來得到它:people->name; 第二個屬性指向後面的乙個元素,那我們便可以這樣來訪問下乙個人的名字:people->next->name, 或者下乙個人的下乙個人的名字:people->next->next->name,一次類推,直到next的值是null,代表結束。
//通過乙個迴圈來遍歷這個鍊錶中的所有人~
void name_show(namelist *p)
}
鍊錶可以被用來實現fifo模式,達到先進者先出的目的!
static namelist *people = null, *last_person = null;
void name_add(namelist *person)
last_person->next = person;
/* update the list tail */
last_person = person;
}namelist *name_pop(void)
return first_person;
}
這樣,我們便可以隨意的向這個鍊錶中新增或者刪除資料,而不向陣列那樣,謹慎的考慮是否越界等問題。
上面實現的結構的學名叫做單向鍊錶,也有地方叫單鏈表,反正是比較簡單的意思~。它有乙個致命的缺點,就是我們在插入或者讀取某條資料的時候,都需要從這個鍊錶的開始,乙個個元素的向下尋找,直到找到這個元素為止。如果鍊錶中的元素比較多,那它很容易成為我們程式中的cpu消耗大戶,進而引起效能問題。為了解決這個問題,先人們發明了雙向鍊錶:
typedef struct _namelist namelist;
struct
_namelist;
改動其實不大,就是在每個元素中都新增了乙個prev屬性,用來指向它的上乙個元素。
void name_add(namelist *person)
last_person ->next = person;
person->prev = last_person;
/* update the list tail */
last_person = person;
}
void name_remove(namelist *person)
return;
}/* search for prior person */
p = people;
while (p)
return;
}p = p->next;
}/* not found in list */
}
現在讓我們來看看雙向鍊錶是怎樣來處理這個問題的:
void name_remove(namelist *person)
if (last_person == person)
if (person->prev)
if (person->next)
}
對元素的遍歷查詢不見了,取而代之的是乙個o(1)的運算,這將極大的提公升我們程式的效能。
也許你已經非常喜歡使用陣列或者鍊錶了,但我還是要向你推薦一種威力極大的資料結構,有了它之後,你可能會立即拋棄前兩者,它就是hashtable.
hashtable即具有雙向鍊錶的優點,同時具有能與資料匹敵的操作效能,這個資料結構幾乎是php核心實現的基礎,我們在核心**的任何地方都發現它的痕跡。
前面我們接觸過,所有的使用者端定義的變數儲存在乙個符號表裡,而這個符號表其實就是乙個hashtable,它的每乙個元素都是乙個zval*型別的變數。不僅如此,儲存使用者定義的函式、類、資源等的容器都是以hashtable的形式在核心中實現的。
zend engine中hashtable的元素其實是指標,對其的這個改進使得hashtable能夠包容各種型別的資料,從小小的標量,到複雜的php5中實現的類等復合資料。本章接下來的內容,我們將詳細的研究如何使用zend內建的api來操作hashtable這個資料結構。
陣列與鍊錶
陣列和鍊錶簡介 在計算機中要對給定的資料集進行若干處理,首要任務是把資料集的一部分 當資料量非常大時,可能只能一部 分一部分地讀取資料到記憶體中來處理 或全部儲存到記憶體中,然後再對記憶體中的資料進行各種處理。例如,對於資料集 s,要求 s 中元素的和,首先要把資料儲存到記憶體中,然後再將記憶體中的...
陣列與鍊錶
陣列,在記憶體上給出了連續的空間.鍊錶,記憶體位址上可以是不連續的,每個鍊錶的節點包括原來的記憶體和下乙個節點的資訊 單向的乙個,雙向鍊錶的話,會有兩個 優點 使用方便 查詢效率 比煉表高,記憶體為一連續的區域 缺點 大小固定,不適合動態儲存,不方便動態新增 優點 可動態新增刪除 大小可變 缺點 只...
陣列與鍊錶
使用陣列意味著所有待辦事項在記憶體中都是相連的 緊靠在一起的 所以在陣列中新增新元素也可能很麻煩。如果沒有了空間,就得移到記憶體的其他地方,因此新增新元素的速度會很慢。一種解決之道是 預留座位 即便當前只有3個待辦事項,也請計算機提供10個位置,以防需要新增待辦事項。這樣,只要待辦事項不超過10個,...