簡體   English   中英

如何從樹中的任何父節點獲取所有葉節點

[英]How to get all leaf nodes from any parent node in a tree

我正在使用Sqlite在android中開發一個應用程序,我有一個樹結構,我在數據庫中表示如下:

        +------+------+-------+------+
        |comp_id nodeId parent| text |
        |------|------|-------|------|
        |  146 |  1   |  -1   | Top  |
        |      |      |       |      |
        | 146  |  2   |  1    | Ch1  |
        |      |      |       |      |
        | 146  |  3   |  2    | Leaf |
        |      |      |       |      |
        |  ... |      |       |      |
        | 152  |  1   |  -1   | Top  |
        +------+------+-------+------+

我在像下面這樣的自包含方法編碼算法時遇到困難,無法在任何節點下返回所有葉子。

Node
{
   public Node[] getAllLeafs()
   {
      // traverse all the way down the tree
      // and get only leafs
   }
}

如果有一種方法可以通過修改我的表結構和/或使用SQL來更容易地實現這一點,請提及我能夠這樣做。

選擇node_id不是某些其他行的父項的所有行,即它們是葉子。

select *
from   tree_table
where  node_id not in (
   select distinct parent from tree_table
);

您可以創建一個遞歸方法,如果一個節點有子節點,則返回其子節點中所有葉子的數組,如果它沒有子Node ,則返回Node本身,因此它本身就是一個葉子。

public Node[] getAllLeafs() {

    ArrayList<Node> allLeafs = new ArrayList<Node>();

    if (getAllChildren().size() == 0) {
        allLeafs.add(this);
        return (Node[]) allLeafs.toArray();
    } else {
        for (Node child : this.getAllChildren()) {
            allLeafs.addAll(child.getAllLeafs());
        }
    }
}

這樣,您可以將邏輯保留在一個方法中,而不必冗余地遍歷不重要的節點。 結構方法的實施取決於您。

我認為這種邏輯可行:

select node_id
from tree_table where node_id not in 
(select a.node_id 
from tree_table as a, tree_table as b
where a.node_id = b.parent); 

內部查詢找出那些也是同一個表中的父節點的節點。 外部查詢找出不是任何節點的父節點的節點,因此必須是葉節點。 希望這可以幫助!

那么,獲取所有節點而不是所有直接節點的原因是什么? 第二種選擇顯然很簡單。

我不認為有一個合理的解決方案,也許是圖形數據庫。 關鍵是你可以:

  1. 使所有父ID(直接和非直接)與每個節點一起保持。 您可以設計具有外鍵的新表。 但這個解決方案似乎是重量級的。 說到這樣的表應該呈指數增長。

  2. 一起取整棵樹。 這是我們在經過四年的數據庫研究后在我們的應用程序中使用的方法。 DB旨在通過緩沖和讀取前面的硬盤博客來獲取彼此相鄰的數據。 您可以使用正確的索引等來改進此解決方案。 我所說的是,有時候從DB獲取連續驅動段比制作復雜查詢更好,而不是在java代碼中搜索所有節點。

    請注意,整個樹的一次提取(通過根索引id)可以在一次DB讀取中執行DB。 另一方面,通常使用嵌套查詢或使用連接的select使用更多讀取,需要id匹配,可能是臨時表等。 (索引處理,鎖定等)

    你絕對應該使用各種NoSQL DB,還要使用RDBMS。

使用SQLite 3.8.3或更高版本,您可以使用如下所示的查詢來計算從特定節點開始的子樹,然后獲取該子樹中的葉子:

WITH RECURSIVE subtree(comp_id, nodeId, parent, text)
AS (SELECT *
    FROM MyTable
    WHERE comp_id = 146 AND nodeId = 1  -- start node
    UNION ALL
    SELECT MyTable.*
    FROM MyTable
    JOIN subtree ON MyTable.comp_id = subtree.comp_id
                AND MyTable.parent  = subtree.nodeid)
SELECT *
FROM subtree
WHERE nodeid NOT IN (SELECT parent
                     FROM subtree)

使用早期的SQLite版本,您必須手動檢索每個級別的節點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM