繁体   English   中英

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

[英]Store tree data structure in database

6儿童树

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

运作方式

1) grandValue(node) -应该给出(所有后代的值之和,包括self)

例如。,

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

2) children(node) -应该列出所有子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) -应该将node作为父级的子级插入

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

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

请帮忙。

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

更新: 树的大小将增长。 新节点将作为叶节点的子节点或少于6个节点且不在2个节点之间的节点添加。

您可以使用嵌套集将数据存储在表中。
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值的不错的图形行走算法。 您必须增强此功能以保持对深度的跟踪,但这很容易。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM