检查多父树中的节点重复

时间:2012-04-02 15:58:37

标签: sql-server tree

我在SQL中有一个非常简单的树实现:

CREATE TABLE [dbo].[Nodes] (
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](max) NULL
);

CREATE TABLE [dbo].[NodeNodes] (
    [ParentNodeId] [int] NOT NULL,
    [ChildNodeId] [int] NOT NULL
);

我的树实现是这样的,节点可以有多个父节点。这样,用户就可以创建将常用节点组合在一起的自定义树。例如:

      1              8         9
    /   \           / \       / \
   2     3         4   7     2   6
  / \   / \                 / \
 4   5 6   7               4   5

Node | Parents | Children
---------------------------
  1  |    -    |   2,3
  2  |   1,9   |   4,5
  3  |    1    |   6,7
  4  |   2,8   |    -
  5  |    2    |    -
  6  |   3,9   |    -
  7  |   3,8   |    -
  8  |    -    |   4,7
  9  |    -    |   2,6

因此有三个树由三个节点指示,没有父节点。当用户将节点添加为另一个节点的子节点时,我的问题是验证潜在的关系。我希望没有节点在同一棵树中出现两次。例如,将节点2添加为节点6的子节点应该会失败,因为这会导致节点2在1的树和9的树中出现两次。我在编写一个有效的算法时遇到了麻烦。

我的第一个想法是找到预期父母的所有根,平整根的树以获得每个树的一个节点列表,然后将这些列表与预期子项相交,并且最后仅在所有结果相交的列表为空。继续这个例子,我将采取以下步骤:

1) Trace prospective parent through all parents to roots:
6->3->1
6->9

2) Flatten trees of the roots
1: {1,2,3,4,5,6,7}
9: {2,4,5,6,9}

3) Intersect lists with the prospective child
1: {1,2,3,4,5,6,7}^{2} = {2}
9: {2,4,5,6,9}^{2} = {2}

4) Only pass if all result lists are empty
1: {2} != {} ; fail
9: {2} != {} ; fail

此过程有效,但需要将整个树放入内存中。我有一些拥有20,000多个节点的树,这需要差不多一分钟才能运行。这种表现不是100%的交易破坏者,但它非常令人沮丧。有没有更有效的算法来做到这一点?

编辑4/2 2pm

上述算法实际上并不起作用。 deroby指出,将7作为子项添加到7将由算法传递,但不应该。问题是只要不重复节点,将子节点添加到另一个节点就会成功 - 它不会验证子节点。

1 个答案:

答案 0 :(得分:0)

一年后,我偶然发现了自己的问题,我决定加入我的解决方案。事实证明我忘记了我的基本数据结构。 我最初认为的是一棵简单的树实际上是一张有向图,而我正在测试的是一个循环。看到循环检测是一种非常常见的事情,互联网上应该有很多解决方案和讨论。有关示例,请参阅Best algorithm for detecting cycles in a directed graph