将树数据结构存储在数据库中

时间:2014-10-16 13:40:57

标签: php mysql database algorithm data-structures

6 Child tree

在上面的树中,每个节点都有一个名称和值。每个节点最多可以有6个孩子。如何将它存储在MySQL数据库中以有效地执行以下操作?

运营

1)grandValue(node) - 应该给(所有后代的总和'值,包括自我)

例如,

  • grandValue(C) = 300
  • grandValue(I) = 950
  • grandValue(A) = 3100

2)children(node) - 应该给出所有孩子的名单(仅限直系后代)

例如,

  • children(C) = null
  • children(I) = L,M,N
  • children(A) = B,C,D,E

3)family(node) - 应该给出后代列表

  • family(C) = null
  • family(I) = L,M,N
  • family(A) = B,C,D,E,F,G,H,I,J,K,L,M,N

4)parent(node) - 应该给出节点的父节点

  • parent(C) = A
  • parent(I) = D
  • parent(A) = null

5)insert(parent, node, value) - 应该将节点作为父

的子节点插入
  • insert(C, X, 500)插入值为500的节点名称X作为C的孩子

我正在考虑使用递归方法来执行这些操作,就像使用二叉树一样。但我不确定这是否是最佳方式。该树可能容纳10到3千万个节点并且可能会偏斜。因此,将数据转储到内存堆栈是我关注的领域。

请帮忙。

  

注意:我在VPS机器上使用PHP,MySQL,Laravel。

     

更新:树的大小会增加。新节点将作为叶子节点或节点的子节点添加,节点少于6个节点而不是2个节点之间。

1 个答案:

答案 0 :(得分:4)

您可以使用嵌套集将数据存储在表中 http://en.wikipedia.org/wiki/Nested_set_model#Example
我担心,如果您打算不断添加新项目,您的数百万个节点可能会让生活变得困难。也许可以通过使用有理数而不是整数作为左右值来减轻这种担忧。添加深度列以加快您要求后代的愿望。我写了一些SQL来创建表和您要求的存储过程。我在SQL Server中做到了这一点,语法可能略有不同,但它是所有正在执行的标准SQL语句。此外,我只是手动决定每个节点的上限和下限。显然,你必须处理编写代码才能在数据库中插入(和维护)这些节点。

CREATE TABLE Tree(
    Node nvarchar(10) NOT NULL,
    Value int NOT NULL,
    L int NOT NULL,
    R int NOT NULL,
    Depth int NOT NULL,
);

INSERT INTO Tree (Node, Value, L, R, Depth) VALUES ('A', 100,  1, 28, 0);
INSERT INTO Tree (Node, Value, L, R, Depth) VALUES ('B', 100,  2,  3, 1);
INSERT INTO Tree (Node, Value, L, R, Depth) VALUES ('C', 300,  4,  5, 1);
INSERT INTO Tree (Node, Value, L, R, Depth) VALUES ('D', 150,  6, 25, 1);
INSERT INTO Tree (Node, Value, L, R, Depth) VALUES ('E', 200, 26, 27, 1);
INSERT INTO Tree (Node, Value, L, R, Depth) VALUES ('F', 400,  7,  8, 2);
INSERT INTO Tree (Node, Value, L, R, Depth) VALUES ('G', 250,  9, 10, 2);
INSERT INTO Tree (Node, Value, L, R, Depth) VALUES ('H', 500, 11, 12, 2);
INSERT INTO Tree (Node, Value, L, R, Depth) VALUES ('I', 350, 13, 21, 2);
INSERT INTO Tree (Node, Value, L, R, Depth) VALUES ('J', 100, 21, 22, 2);
INSERT INTO Tree (Node, Value, L, R, Depth) VALUES ('K',  50, 23, 24, 2);
INSERT INTO Tree (Node, Value, L, R, Depth) VALUES ('L', 100, 14, 15, 3);
INSERT INTO Tree (Node, Value, L, R, Depth) VALUES ('M', 300, 16, 17, 3);
INSERT INTO Tree (Node, Value, L, R, Depth) VALUES ('N', 200, 18, 19, 3);

CREATE PROCEDURE grandValue
    @Node NVARCHAR(10)
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @lbound INT;
    DECLARE @ubound INT;
    SELECT @lbound = L, @ubound = R FROM Tree WHERE Node = @Node
    SELECT SUM(Value) AS Total FROM TREE WHERE L >= @lbound AND R <= @ubound
    RETURN
END;

EXECUTE grandValue 'C';
EXECUTE grandValue 'I';
EXECUTE grandValue 'A';

CREATE PROCEDURE children
    @Node NVARCHAR(10)
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @lbound INT;
    DECLARE @ubound INT;
    DECLARE @depth INT;
    SELECT @lbound = L, @ubound = R, @depth=Depth FROM Tree WHERE Node = @Node
    SELECT Node FROM TREE WHERE L > @lbound AND R < @ubound AND Depth = (@depth + 1)
    RETURN
END;

EXECUTE children 'C';
EXECUTE children 'I';
EXECUTE children 'A';

CREATE PROCEDURE family
    @Node NVARCHAR(10)
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @lbound INT;
    DECLARE @ubound INT;
    SELECT @lbound = L, @ubound = R FROM Tree WHERE Node = @Node
    SELECT Node FROM TREE WHERE L > @lbound AND R < @ubound
    RETURN
END;

EXECUTE family 'C';
EXECUTE family 'I';
EXECUTE family 'A';

CREATE PROCEDURE parent
    @Node NVARCHAR(10)
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @lbound INT;
    DECLARE @ubound INT;
    DECLARE @depth INT;
    SELECT @lbound = L, @ubound = R, @depth = Depth FROM Tree WHERE Node = @Node
    SELECT Node FROM TREE WHERE L < @lbound AND R > @ubound AND Depth = (@depth - 1)
    RETURN
END;

EXECUTE parent 'C';
EXECUTE parent 'I';
EXECUTE parent 'A';

CREATE PROCEDURE ancestor
    @Node NVARCHAR(10)
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @lbound INT;
    DECLARE @ubound INT;
    SELECT @lbound = L, @ubound = R FROM Tree WHERE Node = @Node
    SELECT Node FROM TREE WHERE L < @lbound AND R > @ubound
    RETURN
END;

EXECUTE ancestor 'C';
EXECUTE ancestor 'I';
EXECUTE ancestor 'A';

为了首先在表中创建嵌套集,您可以运行一些代码来生成插入或从第一个节点开始,然后连续添加每个附加节点 - 尽管每个添加可能会修改其中的许多节点设置当你构建它时,可能会有很多数据库颠簸。

这是一个存储过程,用于将节点添加为另一个节点的子节点:

CREATE PROCEDURE insertNode
    @ParentNode NVARCHAR(10), @NewNodeName NVARCHAR(10), @NewNodeValue INT
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @ubound INT;
    DECLARE @depth INT;
    SELECT @ubound = R, @depth = Depth FROM Tree WHERE Node = @ParentNode
    UPDATE Tree SET L = L + 2 WHERE L >= @ubound
    UPDATE Tree SET R = R + 2 WHERE R >= @ubound
    INSERT INTO Tree (Node, Value, L, R, Depth) VALUES (@NewNodeName, @NewNodeValue,  @ubound, @ubound + 1, @depth + 1);
    RETURN
END;

我从http://www.evanpetersen.com/item/nested-sets.html得到了这个,他还展示了一个很好的图形行走算法来创建初始的L和R值。你必须加强这一点以跟踪深度,但这很容易。