如何从树中的任何父节点获取所有叶节点

时间:2014-02-12 10:19:46

标签: java android database sqlite 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来更轻松地完成此操作,请提及我能够这样做。

5 个答案:

答案 0 :(得分:0)

选择node_id不是某些其他行的父级的所有行,即它们是叶子。

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

答案 1 :(得分:0)

你可以创建一个递归方法,如果一个节点有子节点,它将返回子节点中所有叶子的数组,如果它没有子节点,则返回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());
        }
    }
}

这样,您可以将逻辑保留在一个方法中,而不必冗余地遍历不重要的节点。结构方法的实施取决于你。

答案 2 :(得分:0)

我认为这种逻辑可行:

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); 

内部查询找出同一个表中也是父节点的那些节点。外部查询找出不是任何节点的父节点的节点,因此必须是叶节点。希望这有帮助!

答案 3 :(得分:0)

那么,获取所有节点而不是所有直接节点的原因是什么?第二种选择显然很简单。

我认为没有合理的解决方案,也许图形数据库。关键是你可以:

  1. 让所有父ID(直接和非直接)与每个节点一起保持。您可以设计具有外键的新表。但这个解决方案似乎是重量级的。说到这样的表应该呈指数级增长。

  2. 要一起获取整个树 。这是我们在经过四年的数据库研究后在我们的应用程序中使用的方法。 DB旨在通过缓冲和读取前面的硬盘博客来获取彼此相邻的数据。您可以使用正确的索引等来改进此解决方案。我所说的是,有时候从DB获取连续驱动段比制作复杂查询更好,而不是在java代码中搜索所有节点。

    请注意,整个树的一次提取(通过根索引id)可以在一次DB读取中执行DB。另一方面,通常使用嵌套查询或使用连接的选择使用更多读取,需要ID匹配,可能是临时表等。 (索引处理,锁定等)

    你绝对应该使用各种NoSQL DB,还要使用RDBMS。

答案 4 :(得分:0)

使用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版本,您必须手动检索每个级别的节点。