依赖图可视化


22

挑战的目标是编写一个程序,该程序以树的形式可视化依赖图。尽管在这种情况下“依赖关系图”仅意味着有向图,但此处描述的可视化方法最适合描述某些依赖关系的图(作为练习,在阅读了挑战之后,尝试反转其中一个的方向示例图,看看结果是否同样有用。)

程序的输入由一个或多个目标定义组成,这些目标定义是以下形式的行:

Target DirectDependency1 DirectDependency2 ...

,定义目标及其相关的直接依赖项(如果有)。目标及其依赖关系统称为对象。如果对象仅显示为依赖项,而不显示为目标,则它没有依赖项。输入中出现的所有对象的集合称为Γ。(有关输入格式的更多详细信息,请参见“输入和输出”部分。)

对于任意一对对象AB,我们说:

  • 对于某些对象 B',如果 A直接依赖于 B,或者 A直接依赖于 B',而 B'依赖于 B,则 A依赖于B(等效地, BA所必需的);
  • 如果 A依赖于 B,而 B不依赖于 A,则 A适当地依赖于B(等效地, A适当地要求B)。

我们在Γ中定义了一个人为对象oo such,使得ʀooᴛ并不是任何对象都直接需要的,并且对于所有对象A,andooᴛ直接且仅当A在Γ中且A不是时才依赖于A通过在Γ的任意对象正确需要(换句话说,ʀooᴛ直接取决于如果没有其他对象取决于,或如果依赖于所有对象还需要由)。

输出树

我们构造一棵树,其根节点为ʀooᴛ,并且每个节点的子节点都是其直接依赖项。例如,给定输入

Bread Dough Yeast
Dough Flour Water
Butter Milk

,结果树是

输出树示例

,或者以ASCII形式,

ʀooᴛ
+-Bread
| +-Dough
| | +-Flour
| | +-Water
| +-Yeast
+-Butter
  +-Milk

。程序的输出是上面定义的树,没有 oo节点打印。因此,例如,上述输入的相应输出为

Bread
+-Dough
| +-Flour
| +-Water
+-Yeast
Butter
+-Milk

。稍后给出输出树的布局的详细描述。

节点顺序

给定父节点的子节点P,应该分类,使得对所有的子节点P出现之前当且仅当

  • 存在一个子节点ÇP,使得正确由需要Ç,和Ç先于或等于,,根据相同的顺序; 或者
  • 字母顺序先于(更preceisely,先于使用ASCII整理,)存在没有子节点ÇP,以使得正确由需要Ç,和Ç先于或等于,,根据相同的顺序。

(正在寻找数学挑战的人们可能想要证明这种关系定义明确,并且实际上是严格的总阶。不要忘记Γ是有限的!)

例如,给定输入

X D C B A
B D
C A

,输出应为

X
+-A
+-D
+-B
| +-D
+-C
  +-A

。 由于字母顺序,A出现在之前BB出现在之前CD出现在之前B,因为它是正确需要的;出现在之后,因为它是A按字母顺序跟随的; B并且C不会出现在之前D,即使它们按字母顺序排在前面,也因为存在一个节点,即,该节点B正确地需要D,并且等于B(即,本身),并且C根据相同的规则在之前。

重复次数

例如,如果多个对象需要同一个对象A,则在输出中可能会出现多次。如果A没有自己的依赖性,则在这种情况下不需要特殊处理。否则,为了最大程度地减少输出的冗长性,并避免由于循环依赖性而导致的无限递归,仅在第一次出现时列出A的依赖性,而其祖先都不是另一个A节点的兄弟。如A所示,其他任何出现的A都应没有子代,并且应出现一个空格和一个省略号。A...

例如,给定输入

IP Ethernet
TCP IP
UDP IP
WebRTC TCP UDP

,输出应为

WebRTC
+-TCP
| +-IP
|   +-Ethernet
+-UDP
  +-IP ...

。再举一个例子,兼具循环依赖和祖先考虑,

Rock Scissors
Paper Rock
Scissors Paper

,应导致

Paper
+-Rock ...
Rock
+-Scissors ...
Scissors
+-Paper ...

。请注意,例如,第一次出现Rock不会列出其依赖项,因为其父项Paper是另一个Rock节点的同级项。第二个Rock节点的父级ʀooᴛ(未出现在输出中)没有Rock作为同级,因此的依赖项Rock在此节点上列出。

输出树布局

我确定您掌握了如何将树表示为ASCII艺术(如果可以的话,可以随时跳过此部分),但出于完整性考虑...

ʀooᴛ的子节点按顺序打印在单独的行上,没有任何缩进。每个节点后面紧跟着其子节点(如果有的话),以相同的方式递归打印,并在右边缩进两个字符。对于每个有子节点的节点,由|(竖线)字符组成的垂直线从该节点的第一个字符正下方的字符向下延伸,直到其最后一个子节点的行,不包括最后一个子节点的子节点。如果节点的缩进不为零,则+-在其缩进之前(在与父节点相同的缩进级别),覆盖上述垂直线。

输入输出

您可以通过STDIN等效方法读取输入。您可以假定没有空行,并且您可能要求最后一行以换行符结束或不结束。您可以假定对象名称由可打印的ASCII字符(不包括空格)组成。您可以假定目标定义中的对象由单个空格字符分隔,并且没有前导或尾随空格。您可以假定每个目标最多定义一次,并且其依赖项列表中没有重复项

您可以将输出写入STDOUT,或使用等效方法。除最长的输出线外,所有输出线都可以包含尾随空格。最后的输出行可以或可以不以换行符结尾。

得分

这是代码高尔夫球。在简短的回答,以字节为单位,胜。

测试用例

您的程序应在合理的时间内处理以下每个测试用例。


输入项

Depender Dependee
Independent

输出量

Depender
+-Dependee
Independent

输入项

Earth Turtle
Turtle Turtle

输出量

Earth
+-Turtle
  +-Turtle ...

输入项

F A C B D I
A B
B A C
D E H
C
G F
J H G C E I
E D
H D
I G

输出量

J
+-C
+-E
| +-D
|   +-E ...
|   +-H ...
+-H
| +-D ...
+-G
| +-F
|   +-C
|   +-A
|   | +-B ...
|   +-B
|   | +-C
|   | +-A ...
|   +-D ...
|   +-I ...
+-I
  +-G ...

文明V技术树

输入项

输出量


Cygwin syslog-ng软件包依赖关系图

输入项

输出量


GNU grep regex.c调用图

输入项

输出(糟糕!对于SE来说太长了。)


5
规格齐全!
并非查尔斯(Charles)

“节点顺序”部分中的自引用使我很头疼。
递归

Answers:


5

Haskell,512字节

import Data.List
r=reverse
n j|let(w,s)#p|let a?b=or[q!b<GT|(q,r)<-i,a==r,elem q(h p)>elem(a,q)i];a!b|a==b=EQ|a?b||(a<b)>b?a=LT;_!_=GT;l=nub.sortBy(!)$h p;m(v,s)q|h q==[]=(v,[q]:s)|elem q w=(v,[q++" ..."]:s)|(w,x:y)<-(v,[])#q=(w,(q:(u"| "=<<r y)++u"  "x):s)=foldl m(l++w,[])l;c(p,q)=z$p:q:h q;y=z=<<j;i=iterate(nub.sort.(c=<<))y!!length j;h""=[p|p<-id=<<j,and[elem(p,r)i|(r,q)<-i,p==q]];h p=[r|(q,r)<-y,p==q]=unlines=<<r(snd$mempty#"")
u s(x:y)=("+-"++x):map(s++)y
z(x:y)=(,)x<$>y
main=interact$n.map words.lines

在Ideone在线运行


恭喜。非常好!
2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.