【问题标题】:Graph Paths Abstraction Algorithm Needed需要图形路径抽象算法
【发布时间】:2013-04-26 21:26:01
【问题描述】:

我有一个数据结构,其中包含如下图所示的图表:

在这棵树中,一个节点可以有任意数量的来自其下层的唯一子节点。 图中的树表示一组路径。 其中每条路径都应以级别 1 的节点开始,并以“*”标记的节点结束。 所以图中树的路径是:

A then C then G

A then C then G then J

A then D then G

A then D then G the J

A then D then K, and so on...

实际上我的原始树很大(大约 200 万个序列),每个级别的最大节点数是 61 个(共 11 个级别)。因此,它会在我的应用程序(SAMSUNG 的计算机视觉应用程序)中导致许多内存消耗问题。

我的目标是有一个迭代算法,以更紧凑的字符串格式表示这些路径。所以我认为我们把问题分为以下三个步骤。我已经构建了树数据结构(第 2 步),但仍然无法派生迭代算法从树中获取第 3 步中的输出字符串/序列

1- 输入字符串:

(A C G) | (A C G J) | (A D G) | (A D G J ) | (A D K) | ....,

其中“|”代表替代品。

2- 构建这些路径的树形数据结构。

3- 必需的输出字符串:

(A (C G [J]) | (D (G [J]) | K)) | (B ....).

哪里哪里“|”表示备选方案,“[]”包含选项。目标输出字符串应该被优化,因为没有更多的共同因素可以用来更简化它。

【问题讨论】:

  • 那是一个 DAG,不是吗?
  • 我认为您可以将其视为 DAG。此外,一个节点可以有任意数量的来自其下层的唯一子节点。
  • 你的输入字符串排序了吗? IE。所有以A 开头的路径都是连续的吗?
  • @HeshamERAQI 我认为魏子尧的意思是,您的图不是任何标准定义的树。您应该编辑您的问题以避免混淆。
  • @mitchus 嗯,谢谢。我做到了:)

标签: c regex algorithm optimization graph


【解决方案1】:

请注意,这不是一个完整的答案 - 我无法将图片和所有内容都放在评论中。

鉴于此图:

解决方案 1

(A (B | C) E*) | (A B D*) | (A C F*)

解决方案 2

(A B (D* | E*)) | (A C (E* | F*))

解决方案 3

(A (B (D* | E*) | C (E* | F*)))

问题

您想如何解决这种歧义?您必须将您要寻找的准确定义为“答案”。

【讨论】:

  • 还有一个:(A (B (D* | E*) | C (E* | F*)))
  • @HeshamERAQI 正如 m.beuttner 刚刚指出的,还有第三种解决方案。您仍然确定解决方案 2 是您想要的吗?如果是这样,为什么?是什么属性让你喜欢它?
  • 对不起,我没有注意到 S2 也不像 S1 那样正确。他们都缺少一个 |每行之间。通过那些 | 更正 S1 和 S2 之后。我们有三个有效的解决方案,而 S3 是需要的一个。与 S3 中一样,您不能再使用任何常见条目来进一步简化它。
【解决方案2】:

您可以使用迭代 DFS 的修改,它利用堆栈来跟踪未处理的节点。该算法在堆栈上存储的任何一个节点*的字符永远不会超过6个,并且堆栈上的节点总是少于N个(其中N是图中的节点数)。您已经指出 N 最多为 61*11=671,因此堆栈上最多可能有大约 4000 个元素。

在下面的伪代码中,“目标”节点是上面示例中的星号节点,例如G*.

初始化:

从 Φ 到每个“根”节点的边引入了一个虚拟节点 Φ,例如上面的节点 A 和 B。 Φ 的标记被假定为非打印字符,或者您可以在将其添加到输出字符串之前显式检查。在调用函数之前,节点 Φ 被压入堆栈。

outString := ""
while stack not empty
   pop token
   if token is node
      outString := outString + node(token)  // Line 5 - explanation below
      if node(token) has children
         if node(token) is destination
            outString := outString + "["
            push "]"
         end
         if node(token) has multiple children
            for each child of node(token), from right to left
               push ")"
               push child
               push "("
               push "|"
            end
            pop // remove last "|"
         else
            push child
         end
      end

   else // token is ()[]|
      outString := outString + token
   end
end

此算法对图形第一部分(A 及其子项)的输出是(为清楚起见添加了额外的空格;可以轻松地将空格添加到代码中):

A (C G [J]) | (D (G [J]) | (K))

您会注意到您的结果与我的结果之间存在偏差:在我的解决方案中,最终节点 K 括在括号中。如果这是不可取的(它可能导致像A[(B)|(C)] 这样的丑陋),您可以通过在将节点令牌从堆栈中弹出时执行额外的检查来消除它,但代价是一些额外的开销。只需将上面的第 5 行替换为:

if (node(token) has no children
    AND last character of outString is "("
    AND next token on stack is ")")
      remove trailing "(" from outString
      concatenate token to outString
      pop ")" from stack and ignore
else
   outString := outString + node(token) // as above
end

如果您有任何问题或我遗漏了什么,请告诉我。

* 这将发生在(可能极不可能的)节点被写为|[(A)] 的情况下。大多数节点将在堆栈中占用 4 个或更少的字符。

【讨论】:

  • 你是个传奇 :) 非常感谢。您的算法是直接的、非常创新的,并且完全可以完成工作。再次感谢! :)
  • 添加一个简单的事情:您需要在for each child of... 之前添加stack.Push(" ) "); 并在其末尾添加另一个左括号。
  • 当然,如果这就是你想要的。我只是想匹配你的例子。通过您的修改,我得到A ( (C G [J]) | (D ( (G [J]) | (K) ) ) )
猜你喜欢
  • 1970-01-01
  • 2011-06-21
  • 2011-08-26
  • 2013-09-27
  • 1970-01-01
  • 1970-01-01
  • 2012-05-25
  • 2011-04-05
  • 1970-01-01
相关资源
最近更新 更多