家谱软件中的循环

发布于 2024-11-10 10:03:14 字数 208 浏览 7 评论 0原文

我是一些家谱软件(用 C++ 和 Qt 编写)的开发人员。在我的一位客户向我邮寄错误报告之前,我没有遇到任何问题。问题是,客户有两个孩子,还有他们自己的女儿,因此,他因为错误而无法使用我的软件。

这些错误是我对正在处理的家庭图的各种断言和不变量的结果(例如,在走了一个周期后,程序指出 X 不能既是 Y 的父亲又是祖父)。

如何在不删除所有数据断言的情况下解决这些错误?

I am the developer of some family tree software (written in C++ and Qt). I had no problems until one of my customers mailed me a bug report. The problem is that the customer has two children with their own daughter, and, as a result, he can't use my software because of errors.

Those errors are the result of my various assertions and invariants about the family graph being processed (for example, after walking a cycle, the program states that X can't be both father and grandfather of Y).

How can I resolve those errors without removing all data assertions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

慈悲佛祖 2024-11-17 10:03:14

看来您(和/或您的公司)对家谱应该是什么有一个根本性的误解。

让我澄清一下,我也为一家公司工作,该公司的产品组合中有一个家谱(作为其产品之一),我们一直在努力解决类似的问题。

在我们的例子中,我假设你的例子也是如此,问题来自 GEDCOM 格式对于家庭应该是什么样子有着非常固执的看法。然而,这种格式对于家谱的真实面貌存在一些严重的误解。

GEDCOM 存在许多问题,例如同性关系不兼容、乱伦等……这在现实生活中发生的频率比您想象的要高(特别是当时间回到 1700-1800 年时)。

我们将家谱建模为现实世界中发生的事件:事件(例如出生、婚礼、订婚、结合、死亡、收养等)。我们不对这些施加任何限制,除了逻辑上不可能的限制(例如,一个人不能是自己的父母,关系需要两个人,等等......)

缺乏验证给了我们一个更“真实的世界”,更简单、更灵活的解决方案。

对于这个具体案例,我建议删除这些断言,因为它们并不普遍成立。

为了显示问题(将会出现),我建议根据需要多次绘制相同的节点,通过在选择其中一个副本时点亮所有副本来暗示重复。

It seems you (and/or your company) have a fundamental misunderstanding of what a family tree is supposed to be.

Let me clarify, I also work for a company that has (as one of its products) a family tree in its portfolio, and we have been struggling with similar problems.

The problem, in our case, and I assume your case as well, comes from the GEDCOM format that is extremely opinionated about what a family should be. However this format contains some severe misconceptions about what a family tree really looks like.

GEDCOM has many issues, such as incompatibility with same sex relations, incest, etc... Which in real life happens more often than you'd imagine (especially when going back in time to the 1700-1800).

We have modeled our family tree to what happens in the real world: Events (for example, births, weddings, engagement, unions, deaths, adoptions, etc.). We do not put any restrictions on these, except for logically impossible ones (for example, one can't be one's own parent, relations need two individuals, etc...)

The lack of validations gives us a more "real world", simpler and more flexible solution.

As for this specific case, I would suggest removing the assertions as they do not hold universally.

For displaying issues (that will arise) I would suggest drawing the same node as many times as needed, hinting at the duplication by lighting up all the copies on selecting one of them.

笑叹一世浮沉 2024-11-17 10:03:14

放松你的断言。

不是通过更改规则,这很可能对 99.9% 的客户发现输入数据时的错误非常有帮助。

相反,将其从错误“无法添加关系”更改为带有“无论如何添加”的警告。

Relax your assertions.

Not by changing the rules, which are mostly likely very helpful to 99.9% of your customers in catching mistakes in entering their data.

Instead, change it from an error "can't add relationship" to a warning with an "add anyway".

傲影 2024-11-17 10:03:14

这是家谱的问题:它们不是树。它们是有向无环图或 DAG。如果我正确理解了人类生殖的生物学原理,就不会有任何循环。

据我所知,即使是基督徒也接受表兄弟之间的婚姻(因此也接受孩子),这会将家谱变成家庭 DAG。

这个故事的寓意是:选择正确的数据结构。

Here's the problem with family trees: they are not trees. They are directed acyclic graphs or DAGs. If I understand the principles of the biology of human reproduction correctly, there will not be any cycles.

As far as I know, even the Christians accept marriages (and thus children) between cousins, which will turn the family tree into a family DAG.

The moral of the story is: choose the right data structures.

我的影子我的梦 2024-11-17 10:03:14

我猜你有一些值可以唯一地识别一个人,你可以根据这个值进行检查。

这是一个棘手的问题。假设您想保持结构为树,我建议这样做:

假设:A 有自己的女儿和孩子。

A 将自己作为 AB 添加到程序中。一旦扮演了父亲的角色,我们就称其为男朋友吧。

添加一个 is_same_for_out() 函数,它告诉程序的输出生成部分,所有在内部转到 B 的链接都应该在演示时转到 A的数据。

这会给用户带来一些额外的工作,但我想 IT 会相对容易实施和维护。

在此基础上,您可以对 AB 进行代码同步,以避免不一致。

这个解决方案当然并不完美,但它是第一种方法。

I guess that you have some value that uniquely identifies a person on which you can base your checks.

This is a tricky one. Assuming you want to keep the structure a tree, I suggest this:

Assume this: A has kids with his own daughter.

A adds himself to the program as A and as B. Once in the role of father, let's call it boyfriend.

Add a is_same_for_out() function which tells the output generating part of your program that all links going to B internally should be going to A on presentation of data.

This will make some extra work for the user, but I guess IT would be relatively easy to implement and maintain.

Building from that, you could work on code synching A and B to avoid inconsistencies.

This solution is surely not perfect, but is a first approach.

牵强ㄟ 2024-11-17 10:03:14

您应该关注真正为您的软件带来价值的因素。使其为一名消费者工作所花费的时间值得许可证的价格吗?可能不会。

我建议您向该客户道歉,告诉他他的情况超出了您的软件的范围,并向他退款。

You should focus on what really makes value for your software. Is the time spent on making it work for ONE consumer worth the price of the license ? Likely not.

I advise you to apologize to this customer, tell him that his situation is out of scope for your software and issue him a refund.

动听の歌 2024-11-17 10:03:14

您应该已经设置了 Atreides 系列(现代的,沙丘,或古代俄狄浦斯王)作为测试用例。使用清理后的数据作为测试用例不会发现错误。

You should have set up the Atreides family (either modern, Dune, or ancient, Oedipus Rex) as a testing case. You don't find bugs by using sanitized data as a test case.

夜吻♂芭芘 2024-11-17 10:03:14

这就是像“Go”这样的语言没有断言的原因之一。它们常常用来处理您可能没有想到的情况。 你应该只断言不可能的事情,而不仅仅是不可能的事情。后者会给断言带来坏名声。每次你输入 assert(,走开十分钟,真正思考一下。

在你特别令人不安的情况下,这样的断言是可以想象的,也是令人震惊的因此,在你的应用程序中处理它,如果只是说“这个软件不是为了处理你提出的场景”而

断言你的曾曾祖父是你的父亲是不可能的 。

。如果我在一家受雇测试您的软件的测试公司工作,我当然会提出这种情况,为什么每个年轻但聪明的“用户”都会做同样的事情 并享受由此产生的“错误报告”。

This is one of the reasons why languages like "Go" do not have assertions. They are used to handle cases that you probably didn't think about, all too often. You should only assert the impossible, not simply the unlikely. Doing the latter is what gives assertions a bad reputation. Every time you type assert(, walk away for ten minutes and really think about it.

In your particularly disturbing case, it is both conceivable and appalling that such an assertion would be bogus under rare but possible circumstances. Hence, handle it in your app, if only to say "This software was not designed to handle the scenario that you presented".

Asserting that your great, great, great grandfather being your father as impossible is a reasonable thing to do.

If I was working for a testing company that was hired to test your software, of course I would have presented that scenario. Why? Every juvenile yet intelligent 'user' is going to do the exact same thing and relish in the resulting 'bug report'.

弄潮 2024-11-17 10:03:14

我讨厌评论这种搞砸的情况,但不重新调整所有不变量的最简单方法是在图表中创建一个虚拟顶点,充当乱伦父亲的代理。

I hate commenting on such a screwed up situation, but the easiest way to not rejigger all of your invariants is to create a phantom vertex in your graph that acts as a proxy back to the incestuous dad.

鹿港小镇 2024-11-17 10:03:14

因此,我在家谱软件方面做了一些工作。我认为你想要解决的问题是你需要能够在不陷入无限循环的情况下遍历树 - 换句话说,树需要是非循环的。

然而,您似乎断言一个人与其祖先之一之间只有一条路径。这将保证没有循环,但过于严格。从生物学上来说,后代是一个有向无环图 (DAG)。你遇到的情况肯定是一个退化的情况,但这种情况在较大的树上经常发生。

例如,如果您查看第 n 代的 2^n 个祖先,如果没有重叠,那么您在公元 1000 年拥有的祖先比活着的人还要多。所以,一定有重叠。

然而,您也往往会得到无效的周期,只是错误的数据。如果要遍历树,则必须处理循环。您可以在每个单独的算法中或在加载时执行此操作。我是在负载上做的。

可以通过多种方式找到树中的真实循环。错误的方法是标记给定个体的每个祖先,并且在遍历时,如果您要进入的下一个人已经被标记,则切断链接。这将切断潜在的准确关系。正确的方法是从每个个体开始,并用通往该个体的路径标记每个祖先。如果新路径包含当前路径作为子路径,那么它是一个循环,应该被打破。您可以将路径存储为矢量(MFMF、MFFFMF 等)这使得比较和存储非常快。

还有其他一些方法可以检测循环,例如发送两个迭代器并查看它们是否与子集测试发生冲突,但我最终使用了本地存储方法。

另请注意,您不需要实际切断链接,您只需将其从正常链接更改为“弱”链接,某些算法不会遵循该链接。在选择将哪个链接标记为弱链接时,您还需要小心;有时,您可以通过查看出生日期信息来找出应该在哪里打破循环,但通常您无法找出任何信息,因为丢失了太多数据。

So, I've done some work on family tree software. I think the problem you're trying to solve is that you need to be able to walk the tree without getting in infinite loops - in other words, the tree needs to be acyclical.

However, it looks like you're asserting that there is only one path between a person and one of their ancestors. That will guarantee that there are no cycles, but is too strict. Biologically speaking, descendancy is a directed acyclic graph (DAG). The case you have is certainly a degenerate case, but that type of thing happens all the time on larger trees.

For example, if you look at the 2^n ancestors you have at generation n, if there was no overlap, then you'd have more ancestors in 1000 AD than there were people alive. So, there's got to be overlap.

However, you also do tend to get cycles that are invalid, just bad data. If you're traversing the tree, then cycles must be dealt with. You can do this in each individual algorithm, or on load. I did it on load.

Finding true cycles in a tree can be done in a few ways. The wrong way is to mark every ancestor from a given individual, and when traversing, if the person you're going to step to next is already marked, then cut the link. This will sever potentially accurate relationships. The correct way to do it is to start from each individual, and mark each ancestor with the path to that individual. If the new path contains the current path as a subpath, then it's a cycle, and should be broken. You can store paths as vector<bool> (MFMF, MFFFMF, etc.) which makes the comparison and storage very fast.

There are a few other ways to detect cycles, such as sending out two iterators and seeing if they ever collide with the subset test, but I ended up using the local storage method.

Also note that you don't need to actually sever the link, you can just change it from a normal link to a 'weak' link, which isn't followed by some of your algorithms. You will also want to take care when choosing which link to mark as weak; sometimes you can figure out where the cycle should be broken by looking at birthdate information, but often you can't figure out anything because so much data is missing.

鸩远一方 2024-11-17 10:03:14

对于一个愚蠢问题的另一个模拟严肃答案:

真正的答案是,使用适当的数据结构。人类的谱系不能用没有循环的纯树来完全表达。您应该使用某种图表。另外,在进一步讨论之前,请先咨询一下人类学家,因为在尝试建立家谱模型时,还有很多其他地方可能会犯类似的错误,即使是在最简单的“西方父权制一夫一妻制婚姻”的情况下。

即使我们想忽略此处讨论的当地禁忌关系,也有很多完全合法且完全出乎意料的方法可以将循环引入家谱中。

例如: http://en.wikipedia.org/wiki/Cousin_marriage

基本上,表兄弟婚姻是这不仅是普遍现象和预期,也是人类从数千个小家庭群体发展到全球 60 亿人口的原因。它不能以任何其他方式工作。

当涉及到家谱、家庭和血统时,确实很少有共性。几乎任何关于姨妈可以是谁、谁可以嫁给谁、或者孩子如何为了继承而合法化的规范的严格假设,都可能会因世界或历史上某个地方的某些例外而被推翻。

Another mock serious answer for a silly question:

The real answer is, use an appropriate data structure. Human genealogy cannot fully be expressed using a pure tree with no cycles. You should use some sort of graph. Also, talk to an anthropologist before going any further with this, because there are plenty of other places similar errors could be made trying to model genealogy, even in the most simple case of "Western patriarchal monogamous marriage."

Even if we want to ignore locally taboo relationships as discussed here, there are plenty of perfectly legal and completely unexpected ways to introduce cycles into a family tree.

For example: http://en.wikipedia.org/wiki/Cousin_marriage

Basically, cousin marriage is not only common and expected, it is the reason humans have gone from thousands of small family groups to a worldwide population of 6 billion. It can't work any other way.

There really are very few universals when it comes to genealogy, family and lineage. Almost any strict assumption about norms suggesting who an aunt can be, or who can marry who, or how children are legitimized for the purpose of inheritance, can be upset by some exception somewhere in the world or history.

窗影残 2024-11-17 10:03:14

除了潜在的法律影响之外,您似乎确实需要将家谱上的“节点”视为前辈,而不是假设该节点可以是唯一的人。

让树节点包含一个人和后继者 - 然后您可以在树的更深处拥有另一个节点,其中包含同一个人和不同的后继者。

Potential legal implications aside, it certainly seems that you need to treat a 'node' on a family tree as a predecessor-person rather than assuming that the node can be the-one-and-only person.

Have the tree node include a person as well as the successors - and then you can have another node deeper down the tree that includes the same person with different successors.

我乃一代侩神 2024-11-17 10:03:14

一些答案已经展示了保留断言/不变量的方法,但这似乎是对断言/不变量的滥用。断言是为了确保应该为真的东西是真的,不变量是为了确保不应该改变的东西不会改变。

你在这里断言的是乱伦关系不存在。显然它们确实存在,所以你的断言是无效的。您可以解决此断言,但真正的错误在于断言本身。应删除该断言。

A few answers have shown ways to keep the assertions/invariants, but this seems like a misuse of assertions/invariant. Assertions are to make sure something that should be true is true, and invariants are to make sure something that shouldn't change doesn't change.

What you're asserting here is that incestuous relationships don't exist. Clearly they do exist, so your assertion is invalid. You can work around this assertion, but the real bug is in the assertion itself. The assertion should be removed.

吃颗糖壮壮胆 2024-11-17 10:03:14

你的家谱应该使用有向关系。这样就不会出现循环了。

Your family tree should use directed relations. This way you won't have a cycle.

魄砕の薆 2024-11-17 10:03:14

谱系数据是循环的,不适合非循环图,因此,如果您有反对循环的断言,则应将其删除。

在视图中处理此问题而不创建自定义视图的方法是将循环父级视为“幽灵”父级。换句话说,当一个人既是同一个人的父亲又是祖父时,祖父节点会正常显示,但父亲节点会呈现为“幽灵”节点,具有简单的标签,如(“参见祖父”) )并指向祖父。

为了进行计算,您可能需要改进处理循环图的逻辑,以便在存在循环时不会多次访问节点。

Genealogical data is cyclic and does not fit into an acyclic graph, so if you have assertions against cycles you should remove them.

The way to handle this in a view without creating a custom view is to treat the cyclic parent as a "ghost" parent. In other words, when a person is both a father and a grandfather to the same person, then the grandfather node is shown normally, but the father node is rendered as a "ghost" node that has a simple label like ("see grandfather") and points to the grandfather.

In order to do calculations you may need to improve your logic to handle cyclic graphs so that a node is not visited more than once if there is a cycle.

影子是时光的心 2024-11-17 10:03:14

最重要的是避免产生问题,因此我认为您应该使用直接关系来避免出现循环。

正如 @markmywords 所说,#include "fritzl.h"。

最后我不得不说重新检查您的数据结构。也许那里出了问题(也许双向链表可以解决您的问题)。

The most important thing is to avoid creating a problem, so I believe that you should use a direct relation to avoid having a cycle.

As @markmywords said, #include "fritzl.h".

Finally I have to say recheck your data structure. Maybe something is going wrong over there (maybe a bidirectional linked list solves your problem).

奶茶白久 2024-11-17 10:03:14

断言无法在现实中幸存下来

通常断言在与现实世界数据接触后就无法幸存。这是软件工程过程的一部分,需要决定要处理哪些数据以及哪些数据超出范围。

循环家庭图

关于家庭“树”(实际上它是完整的图,包括循环),有一个很好的轶事:

我娶了一位寡妇,她有一个已经成年的女儿。我的父亲经常来看望我们,他爱上了我的继女并娶了她。结果,我的父亲成了我的儿子,我的女儿成了我的母亲。一段时间后,我给妻子生了一个儿子,他是我父亲的兄弟,也是我的叔叔。我父亲的妻子(也是我的女儿和我的母亲)有一个儿子。结果,我在同一个人身上有了一个兄弟和一个孙子。我的妻子现在是我的祖母,因为她是我母亲的母亲。所以我是我妻子的丈夫,同时也是我妻子的继孙。换句话说,我是我自己的爷爷。

当你考虑到代理人或“模糊的父亲身份”时,事情会变得更加奇怪。

如何处理这种情况

将周期定义为超出范围

您可以决定您的软件不应处理此类罕见情况。如果发生这种情况,用户应该使用不同的产品。这使得处理更常见的情况更加稳健,因为您可以保留更多断言和更简单的数据模型。

在这种情况下,请向您的软件添加一些良好的导入和导出功能,以便用户可以在必要时轻松迁移到不同的产品。

允许手动关系

您可以允许用户添加手动关系。这些关系不是“一等公民”,即软件按原样接受它们,不检查它们,也不在主数据模型中处理它们。

然后,用户可以手动处理罕见的情况。您的数据模型仍然非常简单,您的断言也将继续存在。

小心手动关系。人们很想使它们完全可配置,从而创建一个完全可配置的数据模型。这是行不通的:你的软件将无法扩展,你会遇到奇怪的错误,最后用户界面将变得无法使用。这种反模式称为“软编码”,并且"The daily WTF" 充满了这方面的例子。

让你的数据模型更加灵活,跳过断言,测试不变量

最后的手段是让你的数据模型更加灵活。您必须跳过几乎所有断言,并将数据模型建立在完整的图表上。正如上面的例子所示,你很容易成为自己的祖父,所以你甚至可以拥有自行车。

在这种情况下,您应该广泛测试您的软件。您必须跳过几乎所有断言,因此很有可能出现其他错误。

使用测试数据生成器检查异常测试用例。有 HaskellErlangC 。对于 Java / Scala 有 ScalaCheck尼亚亚。一个测试想法是模拟随机群体,让它随机杂交,然后让您的软件首先导入然后导出结果。期望的是,输出中的所有连接也在输入中,反之亦然。

属性保持不变的情况称为不变量。在这种情况下,不变量是模拟群体中个体之间的“浪漫关系”集合。尝试找到尽可能多的不变量并使用随机生成的数据对其进行测试。不变量可以是功能性的,例如:

  • 即使添加更多“浪漫关系”,叔叔仍然是叔叔
  • 每个孩子都有父母
  • 一个两代人的人口至少有一个祖父母

或者它们可以是技术性的:

  • 您的软件不会崩溃在多达 100 亿个成员的图表上(无论有多少互连)
  • 您的软件可通过 O(节点数)和 O(边数 ^ 2)进行扩展
  • 您的软件可以保存并重新加载每个家庭图100亿会员

通过运行模拟测试,你会发现很多奇怪的极端情况。修复它们将花费大量时间。而且你会失去很多优化,你的软件运行速度会慢很多。您必须决定是否值得以及这是否在您的软件范围内。

Assertions don't survive reality

Usually assertions don't survive the contact with real world data. It's a part of the process of software engineering to decide, with which data you want to deal and which are out of scope.

Cyclic family graphs

Regarding family "trees" (in fact it are full blown graphs, including cycles), there is a nice anecdote:

I married a widow who had a grown daughter. My father, who often visited us, fell in love with my step-daughter and married her. As a result, my father became my son, and my daughter became my mother. Some time later, I gave my wife a son, who was the brother of my father, and my uncle. My father's wife (who is also my daughter and my mother) got a son. As a result, I got a brother and a grandson in the same person. My wife is now my grandmother, because she is my mother's mother. So I am the husband of my wife, and at the same time the step-grandson of my wife. In other words, I'm my own grandpa.

Things get even more strange, when you take surrogates or "fuzzy fatherhood" into account.

How to deal with that

Define cycles as out-of-scope

You could decide that your software should not deal with such rare cases. If such a case occurs, the user should use a different product. This makes dealing with the more common cases much more robust, because you can keep more assertions and a simpler data model.

In this case, add some good import and export features to your software, so the user can easily migrate to a different product when necessary.

Allow manual relations

You could allow the user to add manual relations. These relations are not "first-class citizens", i.e. the software takes them as-is, doesn't check them and doesn't handle them in the main data model.

The user can then handle rare cases by hand. Your data model will still stay quite simple and your assertions will survive.

Be careful with manual relations. There is a temptation to make them completely configurable and hence create a fully configurable data model. This will not work: Your software will not scale, you will get strange bugs and finally the user interface will become unusable. This anti-pattern is called "soft coding", and "The daily WTF" is full of examples for that.

Make your data model more flexible, skip assertions, test invariants

The last resort would be making your data model more flexible. You would have to skip nearly all assertions and base your data model on a full blown graph. As the above example shows, it is easily possible to be your own grandfather, so you can even have cycles.

In this case, you should extensively test your software. You had to skip nearly all assertions, so there is a good chance for additional bugs.

Use a test data generator to check unusual test cases. There are quick check libraries for Haskell, Erlang or C. For Java / Scala there are ScalaCheck and Nyaya. One test idea would be to simulate a random population, let it interbreed at random, then let your software first import and then export the result. The expectation would be, that all connections in the output are also in the input and vice verse.

A case, where a property stays the same is called an invariant. In this case, the invariant is the set of "romantic relations" between the individuals in the simulated population. Try to find as much invariants as possible and test them with randomly generated data. Invariants can be functional, e.g.:

  • an uncle stays an uncle, even when you add more "romantic relations"
  • every child has a parent
  • a population with two generations has at least one grand-parent

Or they can be technical:

  • Your software will not crash on a graph up to 10 billion members (no matter how many interconnections)
  • Your software scales with O(number-of-nodes) and O(number-of-edges^2)
  • Your software can save and re-load every family graph up to 10 billion members

By running the simulated tests, you will find lots of strange corner cases. Fixing them will take a lot of time. Also you will lose a lot of optimizations, your software will run much slower. You have to decide, if it is worth it and if this is in the scope of your software.

芸娘子的小脾气 2024-11-17 10:03:14

您仍然应该检查诸如一个人是他/她自己的父母或其他不可能的情况并提出错误,而不是删除所有断言。如果不太可能,可能会发出警告,以便用户仍然可以检测到常见的输入错误,但如果一切正确,它就会起作用。

我将数据存储在一个向量中,每个人都有一个永久整数,并将父母和孩子存储在个人对象中,其中所述 int 是向量的索引。这在几代人之间进行起来会非常快(但对于姓名搜索之类的事情来说会很慢)。这些对象将按照它们创建的时间顺序排列。

Instead of removing all assertions, you should still check for things like a person being his/her own parent or other impossible situations and present an error. Maybe issue a warning if it is unlikely so the user can still detect common input errors, but it will work if everything is correct.

I would store the data in a vector with a permanent integer for each person and store the parents and children in person objects where the said int is the index of the vector. This would be pretty fast to go between generations (but slow for things like name searches). The objects would be in order of when they were created.

桃气十足 2024-11-17 10:03:14

复制父亲(或使用符号链接/引用)。

例如,如果您使用分层数据库:

$ #each person node has two nodes representing its parents.
$ mkdir Family
$ mkdir Family/Son
$ mkdir Family/Son/Daughter
$ mkdir Family/Son/Father
$ mkdir Family/Son/Daughter/Father
$ ln -s Family/Son/Daughter/Father Family/Son/Father
$ mkdir Family/Son/Daughter/Wife
$ tree Family
Family
└── Son
    ├── Daughter
    │   ├── Father
    │   └── Wife
    └── Father -> Family/Son/Daughter/Father

4 directories, 1 file

Duplicate the father (or use symlink/reference).

For example, if you are using hierarchical database:

$ #each person node has two nodes representing its parents.
$ mkdir Family
$ mkdir Family/Son
$ mkdir Family/Son/Daughter
$ mkdir Family/Son/Father
$ mkdir Family/Son/Daughter/Father
$ ln -s Family/Son/Daughter/Father Family/Son/Father
$ mkdir Family/Son/Daughter/Wife
$ tree Family
Family
└── Son
    ├── Daughter
    │   ├── Father
    │   └── Wife
    └── Father -> Family/Son/Daughter/Father

4 directories, 1 file
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文