PHP7.2 Data Structures 使用

PHP7.2 Data Structures 使用

1. 安裝

pecl install ds
brew install homebrew/php/php71-ds

目前PHP7.2不支持使用 brew 安裝。php

2. PHP 原始的數據結構Array

PHP5.x 的時代,Array是惟一的表示集合的數據類型,在 PHP 中,他既是 List 也是 Map, 他就是一切。前端

<?php
$a = array(1,2,3,4);
$b = array('a'=>1,'b'=>2,'c'=>3);

這種數據類型的確是給開發者帶來了便捷性,但讓PHPer 會主鍵的忽略掉數據結構帶來的好處,特別是在學習其餘的語言時,給PHPer 帶來困擾。git

在 PHP 升級到7後,Array也同時獲得了優化,可是他的結構並無發生變化, 「optimised for everything; optimised for nothing」 with room for improvement。那若是咱們能夠經過引入更便利的數據結構優化性能,同時寫代碼反而更方便了,那何樂而不爲呢?github

「SPL數據結構怎麼樣?」
Unfortunately they are terrible. They did offer some benefits prior to PHP 7, but have since been neglected to the point of having no practical value.

「咱們爲何不能修正和改進它們?」
We could, but I believe their design and implementation is so poor that it would be better to replace them with something brand new.shell

「SPL數據結構的設計很是可怕。」 - 安東尼 費拉拉json

Array 缺點

  • PHP 的 Array 訪問不存在的 key 能夠獲得 null,不會產生 fatal error,但會有一個 E_NOTICE。這個 E_NOTICE 會被 set_error_handler 註冊的函數截獲。顯然,這種代碼上的不乾淨和性能上的無謂開銷徹底是能夠避免的。
<?php
$a = [];
$a['a']; // PHP Notice:  Undefined offset

通常的 PHPer 都不會用array_key_exists 和 if else 來處理,這樣作會顯得有些麻煩。vim

  • 有時候Array 的使用,性能會變得不好。Array 本質上是一個 Map,unshift 一個元素進來,將會改變每一個元素的 key,這是一個 O(n)操做。另外,PHP 的 Array 將其 value(包括 key 和 它的 hash) 保存在一個 bucket 中,因此咱們須要查看每個 bucket 並更新 hash。

PHP 內部實際上是經過建立新的 array 來完成 array_unshift 操做的,其性能問題可想可知。數組

DataStructures,PHP7的一個擴展,數組(Array)的一個替代品。php7

Github: https://github.com/php-ds數據結構

Namespace: Ds\

接口類: Collection, Sequence, Hashable

實現類(final class): Vector, Deque, Map, Set, Stack, Queue, PriorityQueue, Pair

php7 data structure

接口類

  • Collection 是一個基礎接口,定義了一個數據集合(這裏的集合指的是 Collection,不是 Set) 的基本操做,好比 foreach, echo, count, print_r, var_dump, serialize, json_encode, and clone.等。
  • Sequence 是類數組數據結構的基礎接口,定義了不少重要且方便的方法,好比 contains, map, filter, reduce, find, first, last 等。從圖中可知,Vector, Deque, Stack, Queue 都直接或者間接的實現了這個接口。它的特色以下:

    • 值始終會被索引 [0, 1, 2, …, size - 1]
    • 刪除或插入更新全部連續值的位置。
    • 只容許訪問索引在 [0, size-1]的值。
  • Hashable 在圖中看起來比較孤立,但對於 Map 和 Set 很重要。一個 Object 若是實現了 Hashable,就能夠做爲 Map 的 key,能夠做爲 Set 的元素。這樣 Map 和 Set 就能像 Java 同樣方便的使用了。

實現類

  • Vector 應該是最爲經常使用的數據結構之一了,能夠把它當成 Ruby 的 Array 或者 Python 的 List。其元素的值的 index 就是它在 buffer 中的 index,因此效率很高。只要有使用數組的需求且不須要 insert, remove, shift 和 unshift 的均可以用它。

視頻說明

    • 優勢:

      • 低內存使用量
      • get, set, push and pop的複雜度爲 O(1)
    • 缺點:

      • insert, remove, shift, and unshift 的複雜度爲 O(n)
    PhotoShop中使用主要的數據結構就是 Vector ---- Sean Parent
    • Deque(發音[dek] ) 是一種雙端隊列「double-ended queue」。在 queue 的基礎上增長了一個頭指針,所以 shift 和 unshift 也是 O(1) 複雜度了。但帶來的性能損耗並很少。

    兩個指針用於跟蹤頭部和尾部, 指針能夠「wrap around」緩衝區的末尾,這避免了須要移動其餘值來騰出空間。 這使得移位和移位很是快 - Vector沒法與之競爭。視頻說明

    • 優勢:

      • 低內存使用量。
      • get,set, push, pop, shift, and unshift 的複雜度爲 O(1)。
    • 缺點:

      • inser,remove 的複雜度爲 O(n)。
      • 緩衝區容量必須是2的n次方。
    • Stack 是一種「LIFO」 結構,按照「後進先出」的原則容許訪問、遍歷、銷燬結構頂部的值。DsStack 的內部使用的是 DsVector 的實現。
    • Queue 是一種「FIFO」結構,按照「先進先出」的原則容許訪問、遍歷、銷燬結構頂部的值。DsQueue 內部使用的是 DsDeque 的實現。
    • PriorityQueue(優先級隊列) 與 Queue 很是的類似,按照分配的優先級將值推入隊列,優先級最高的值始終位於隊列的前端。遍歷 PriorityQueue 具備破壞性,至關於連續的彈出操做,直到隊列爲空。使用最大堆實現
    • Hashable , 一個容許用對象做鍵的接口。注意:並非hashTable。Hashable只引入了兩種方法:hash和equals。支持Hashable接口的數據結構是Map和Set。
    • Map , 一種連續的鍵值對集合。同 array 的使用是一致的,key 但是是任意的類型,可是必須惟一。若是相同的 key 添加到 Map 中,那麼會替換掉原有的。同array 同樣,插入的順序會被保留。

      • 優勢:

        • 效率和內存使用幾乎和 Array 一致
        • 當Map 的大小降低到足夠小時,會自動釋放已分配的內存。
        • key 和 value 能夠是任意類型,甚至是對象。
        • put, get, remove, 和 hasKey 的複雜度爲 O(1)
      • 缺點:

        • 當key 爲對象時,不能轉成 Array 。
    • Set,是一個無序惟一值的集合。Map 內部使用了 set 的實現,他們都是基於Array 相同的內部結構,這意味這Set 的排序具備 O(n*log n) 的複雜度。

      • 優勢:

        • 添加、刪除、引用都是 O(1)的複雜度
        • 使用 Hashable 的接口
        • 支持任何類型的值。
      • 缺點:

        • 不支持 push, pop, insert, shift, unshift
        • 若是在索引以前刪除了值,那麼複雜度會從 O(1) 降到 O(n)

    這裏在說明一點,Array中的值自己是沒有索引的,所以在使用 in_array()的時候呈線性搜索,複雜度爲 O(n)。
    若是想要建立一個惟一值數組,可使用 array_unique(),因爲array_unique()針對的是 value 而不是 key,因此每一個數組成員都會被限行搜索,複雜度會變爲 O(n²)。

    相關文章
    相關標籤/搜索