樹形結構資料儲存方案(一):鄰接列表模式

發表於2017-08-30

在程式開發中,我們常遇到用樹型結構來表示某些資料間的關係,如企業的組織架構、商品的分類、操作欄目等,目前的關係型資料庫都是以二維表的形式記錄儲存資料,而樹型結構的資料如需存入二維表就必須進行Schema設計。最近對此方面比較感興趣,專門做下梳理,如下為常見的樹型結構的資料:

tree

其中最簡單的方法是:Adjacency List(鄰接列表模式)。簡單的說是根據節點之間的繼承關係,顯現的描述某一節點的父節點,從而建立二位的關係表。表結構通常設計為{Node_id,Parent_id},如下圖:

adjacency-list

使用連線表的大致程式碼:

對整個結構的根節點(Food)使用這個函式就可以列印出整個多級樹結構,由於Food是根節點它的父節點是空的,所以這樣呼叫: display_children(”,0)。將顯示整個樹的內容。如果你只想顯示整個結構中的一部分,比如說水果部分,就可以這樣呼叫:display_children(‘Fruit’,0);

幾乎使用同樣的方法我們可以知道從根節點到任意節點的路徑。比如 Cherry 的路徑是 ”Food >; Fruit >; Red”。 為了得到這樣的一個路徑我們需要從最深的一級”Cherry”開始, 查詢得到它的父節點”Red”把它新增到路徑中, 然後我們再查詢Red的父節點並把它也新增到路徑中,以此類推直到最高層的”Food”

以下是程式碼:

如果對”Cherry”使用這個函式:print_r(get_path(‘Cherry’)),就會得到這樣的一個陣列了:

這種方案的優點很明顯:結構簡單易懂,由於互相之間的關係只由一個parent_id維護,所以增刪改都是非常容易,只需要改動和他直接相關的記錄就可以。缺點當然也是非常的突出:由於直接地記錄了節點之間的繼承關係,因此對Tree的任何CRUD操作都將是低效的,這主要歸根於頻繁的“遞迴”操作,遞迴過程不斷地訪問資料庫,每次資料庫IO都會有時間開銷。舉個例子,如果想要返回所有水果,也就是水果的所有子孫節點,看似很簡單的操作,就需要用到一堆遞迴。當然,這種方案並非沒有用武之地,在樹的層級比較少的時候就非常實用,在鄰接列表模式的基礎上還可以擴充的是平面表,區別是將節點的level和當前節點的順序也放入表中,比較適合類似評論等場景,具體的表結構類似這樣,這裡就不再深入闡述。

flat-table

參考連結:

  • http://salman-w.blogspot.com/2012/08/php-adjacency-list-hierarchy-tree-traversal.html
  • https://packagist.org/search/?tags=adjacency%20list

相關文章