常見PHP的幾種數據結構

1 數組

數組(Array)是一種線性表的數據結構,它用一段連續的內存空間,來存儲具有相同類型的值。但是由於在PHP的底層定義中,數組是通過散列表實現的,所以這段定義並不適用。PHP的數組可以存儲任意數據類型的數據,所以相對於Java來說效率較高。在Java的數組中,每次定義都要先聲明屬於組的類型,在查找數組時,效率是O(1),但是在插入和刪除時,算法複雜度是O(n),因爲在插入操作時,要先找到插入的位置,然後將該位置及往後的元素都往後移一位。刪除同理。但是PHP卻不受此約束。

2 鏈表

和數組不同,鏈表並不需要一塊連續的內存空間,它通過“指針”將一組零散的內存塊串聯起來使用,一般節點有兩個屬性(data和next)。鏈表有多種類型,最簡單的是單鏈表。

  • 單鏈表是最原始的鏈表。單鏈表有兩個節點比較特殊,頭結點和尾節點。頭結點記錄鏈表的基地址,通過它可以遍歷得到整條鏈表。尾節點的指針不是指向節點,而是指向空地址NUll,表示這是最後一個節點。單向鏈表插入和刪除的時間複雜度是O(1),而查詢的時間複雜度是O(n)
  • 疑問:當進行插入和刪除操作時要先查詢相應節點,查詢的時間複雜度是O(n),爲什麼插入和刪除的的複雜度是O(1)呢?可以將插入刪除看作是單純的插入刪除,不包含查詢在裏面。當做兩個不同的操作來看待。
  • 在單鏈表的基礎上擴展有了循環鏈表,循環鏈表是將尾節點的next指向了頭結點,從而實現了收尾相連。可以解決(約瑟夫環)問題。
  • 雙向鏈表:與單向鏈表的區別是除了有一個指向下一個節點的指針外,還有一個用於指向上一個節點的指針。從而實現通過O(1)複雜度找到上一個節點。使得雙向鏈表在插入刪除是比單向鏈表更高效。以刪除爲例,在刪除節點時,我們還要獲取其前驅節點,讓前驅節點的指針指向被刪除節點的下一個節點。在單向鏈表中,獲取前驅節點的複雜度是O(n),但是雙向鏈表O(1)直接獲取前驅節點。所以雙向鏈表插入和刪除的時間複雜度纔是真正的O(1)。
  • 最後一種就是雙向循環鏈表,就是雙向鏈表和單向鏈表的結合。
  • 時間複雜度是靠更差的空間複雜度換取的,雙向鏈表始終需要單鏈表的兩倍空間在 Web 應用中,時間效率優先級更高,所以我們通常都是空間換時間來提高性能。

3 棧

限定只能在一端進行插入和刪除操作的線性表,並且滿足先進後出的特點。我們把允許插入和刪除的一端叫做棧頂,另一個端叫做棧底,不含任何數據的棧叫做空棧。棧支持通過數組/鏈表實現,通過數組實現的通常叫做順序棧,通過鏈表實現的叫做鏈棧。
使用PHP中array_push()和array_pop()來實現。

4 隊列

和棧類似,隊列也是一種特殊的線性表結構,只不過隊列是在一端插入,另一端刪除,就跟我們平常排隊一樣,從隊尾入隊,在隊頭出去,所以隊列的特性是先入先出,允許插入的一端叫隊尾,允許刪除的一端叫隊頭。隊列也可以通過數組和鏈表實現,通過數組實現的叫順序隊列,通過鏈表實現的叫做鏈式隊列,棧只需要一個棧頂指針就可以了,因爲只允許在棧頂插入刪除,但是隊列需要兩個指針,一個指向隊頭,一個指向隊尾。

使用PHP中array_shift()和array_push()來實現。

5 重要的編程技巧:遞歸

遞歸,簡單來講就是在函數定義中調用函數自身,將一個大的問題拆分成多個小問題,逐一擊破後最後歸併結果。判斷一個問題是否可以通過遞歸來解決,主要看它是否滿足以下三個條件:
1 一個問題的解可以分解爲幾個子問題的解
2 這個問題與分解之後的子問題,除了數據規模不同,求解思路完全一樣
3 存在遞歸終止條件

遞歸一定要有終止條件,否則會導致函數被無限調用最終致使內存溢出
 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章