將平板餐桌解析成樹的最有效/最優雅的方法是什麼?

假設您有一個存儲有序樹層次結構的平面表: sql

Id   Name         ParentId   Order
 1   'Node 1'            0      10
 2   'Node 1.1'          1      10
 3   'Node 2'            0      20
 4   'Node 1.1.1'        2      10
 5   'Node 2.1'          3      10
 6   'Node 1.2'          1      20

這是一個圖,咱們有[id] Name 。 根節點0是虛構的。 數據庫

[0] ROOT
                          /    \ 
              [1] Node 1          [3] Node 2
              /       \                   \
    [2] Node 1.1     [6] Node 1.2      [5] Node 2.1
          /          
 [4] Node 1.1.1

您將使用哪一種簡約方法將其做爲正確排序,正確縮進的樹輸出到HTML(就此而言,仍是文本)? 數組

進一步假設您只有基本的數據結構(數組和哈希圖),沒有帶有父/子引用的奇特對象,沒有ORM,沒有框架,只有兩隻手。 該表表示爲結果集,能夠隨機訪問。 數據結構

可使用僞代碼或簡單的英語,這純粹是一個概念性問題。 框架

額外的問題:在RDBMS中是否存在從根本上更好的方法來存儲這樣的樹結構? nosql


編輯和添加 工具

要回答一個評論者( Mark Bessey )的問題:根節點不是必需的,由於它永遠不會顯示。 ParentId = 0是表示「這些是頂級」的約定。 Order列定義如何對具備相同父代的節點進行排序。 spa

我所說的「結果集」能夠圖片爲一個哈希表數組(保留在該術語中)。 對於個人示例,本應已經存在。 一些答案須要付出額外的努力,而後再進行構建,但這不要緊。 code

這棵樹能夠任意深。 每一個節點能夠有N個子節點。 不過,我並無真正想到「成千上萬的條目」樹。 對象

不要將我對節點命名(「節點1.1.1」)的選擇誤認爲是要依賴的東西。 這些節點也能夠稱爲「 Frank」或「 Bob」,沒有暗示命名結構,這僅僅是爲了使其可讀。

我已經發布了本身的解決方案,所以大家能夠將它分解成碎片。


#1樓

考慮將noeo工具(例如neo4j)用於層次結構。 例如,諸如linkedin之類的聯網應用程序使用couchbase(另外一個nosql解決方案)

可是,僅將nosql用於數據集市級別的查詢,而不用於存儲/維護事務


#2樓

假設您知道根元素爲零,這是要輸出到文本的僞代碼:

function PrintLevel (int curr, int level)
    //print the indents
    for (i=1; i<=level; i++)
        print a tab
    print curr \n;
    for each child in the table with a parent of curr
        PrintLevel (child, level+1)


for each elementID where the parentid is zero
    PrintLevel(elementID, 0)

#3樓

若是能夠建立嵌套的哈希圖或數組,那麼我能夠簡單地從表頭開始將表格添加到嵌套數組中。 我必須跟蹤每行到根節點,以便知道要插入嵌套數組中的哪一個級別。 我可使用記憶,這樣我就不須要一遍又一遍地查找同一個父母。

編輯:我將首先將整個表讀入數組,所以不會重複查詢數據庫。 固然,若是您的桌子很大,這將不切實際。

構建完結構後,我必須先遍歷深度並打印出HTML。

沒有更好的基本方法來使用一個表存儲此信息(儘管我可能錯了;),而且但願看到一種更好的解決方案)。 可是,若是您建立一個方案來使用動態建立的db表,那麼您將在犧牲簡單性和SQL地獄的風險的同時開闢了一個全新的世界;)。


#4樓

您可使用哈希圖模擬任何其餘數據結構,所以這不是一個可怕的限制。 從頂部到底部掃描,您將爲數據庫的每一行建立一個哈希圖,併爲每一列建立一個條目。 將每一個哈希表添加到鍵入ID的「主」哈希表。 若是任何節點具備還沒有出現的「父」節點,請在主哈希圖中爲其建立一個佔位符條目,並在看到實際節點時將其填充。

要打印出來,請對數據進行簡單的深度優先傳遞,並始終跟蹤縮進級別。 經過爲每一行保留一個「子項」條目,並在掃描數據時填充它,可使此過程變得更加容易。

至因而否有一種「更好」的方式將樹存儲在數據庫中,這取決於您如何使用數據。 我已經看到了具備已知最大深度的系統,該系統爲層次結構中的每一個級別使用了不一樣的表。 若是樹中的級別畢竟不徹底相等(頂層類別與葉子不一樣),這頗有道理。


#5樓

好的選擇,我會使用對象。 我會爲每一個記錄建立一個對象,其中每一個對象都有一個children對象集合,並將它們所有存儲在ID爲鍵的assoc數組(/ hashtable)中。 並快速瀏覽該收藏集,將子級添加到相關的子級字段中。 簡單。

可是因爲限制某些良好的OOP的使用對您很無聊,所以我可能會根據如下條件進行迭代:

function PrintLine(int pID, int level)
    foreach record where ParentID == pID
        print level*tabs + record-data
        PrintLine(record.ID, level + 1)

PrintLine(0, 0)

編輯:這相似於其餘幾個條目,但我認爲它稍微乾淨一些。 我要添加的一件事:這是很是消耗SQL的。 真討厭 若是能夠選擇,請執行OOP路線。

相關文章
相關標籤/搜索