请允许我用一个例子问这个问题: 假设我们有以下3个列表(为清楚起见,省略了双引号):
L1: (a, c, b, d, f, j)
L2: (b, e, j, k)
L3: (a, d, e, g, h, j, i)
输出列表可能如下所示(还有更多解决方案)
Lanswer1: (a, c, b, d, e, f, g, h, j, i, k)
Lanswer2: (a, c, b, d, f, e, g, h, j, i, k)
Lanswer3: (a, c, b, d, e, f, g, h, j, k, i)
总之,生成的有序集
第4个列表,L4:(b,c,d),当添加到输入时,应该抛出异常(因为c在L1中的b之前)
我通过检查得出了答案。任何人都可以建议一个算法来做到这一点? 谢谢, - M.S。
答案 0 :(得分:5)
可以使用topological sorting完成此操作。
首先从列表中构建有向图。列表的元素成为节点。边缘从第一个元素到第二个元素,从第二个元素到第三个元素,依此类推。
根据您实施算法的方式,您可以获得所有可能的解决方案,或者只获得一个解决方案。此外,如果图形包含一个循环,则算法将以错误停止。
这是您的列表中的图表的样子:
来源:
digraph {
{
edge [color = "red"]
a -> c
c -> b
b -> d
d -> f
f -> j
}
{
edge [color = "blue"]
b -> e
e -> j
j -> k
}
{
edge [color = "green"]
a -> d
d -> e
e -> g
g -> h
h -> j
j -> i
}
}
答案 1 :(得分:0)
这是一次尝试。通常的免责声明适用。
主要逻辑
基本上,这是一个两步过程。
1.将3个列表转换为一个双向链表,每个节点指向下一个元素,并使用第二个指针指向任何兄弟节点(如e / f或i / k)。转换后,它应该看起来像
a->c->b->d->f->g->h->j->k
| |
e i
2.编写一个带有两个元素和上面链接列表的函数,并返回一个标志,指示第一个元素是出现在第二个元素之前,之后还是与第二个元素相同的位置。该方法的一个可能的签名可能是
int getRelativePositionOf(char e1, char e2)
//returns -1 if e1 exists before e2, 0 if e1 and e2 are siblings and 1 if e1 exists after e2.
如果任何两个元素的相对位置与原始数据不同,这将帮助您验证第四个列表并抛出异常。
创建链接列表
可以想象,第一步,即创建双向链表是最具挑战性的部分。我没有想出最优雅的创作方法,但这里只有一个。
将最长的列表L1放入 双重链表。所以,在你的例子中,这是第3个列表,你现在就可以了 有
a->d->e->g->h->j->i
现在迭代其余元素 并为每个元素检查它是否存在于链表中。如果是,请忽略。
如果它不存在,则需要将元素插入到链表中。所以现在我们需要找出应该添加这个元素的位置。我们称这个元素为'X'。
遍历链表的长度,并且对于每个元素说'Y',检查L2和L3是否在X&之间存在位置关系。是的。例如,如果我们试图在上面的链表中插入'c',我会从链表的第一个元素开始,即'a',并在列表中看到'a'和'C'。
如果我们可以确定原始列表中两个元素的相对位置,则定义关系存在。从第一个列表中,我知道'c'在'a'之后。所以'c'应该插在'a'之后的某个地方。所以我们在链表中前进,现在将'd'与'c'进行比较。再次从第一个原始列表中,我们知道'c'在'd'之前。答对了。在'a'和'd'之间插入'c'。所以链表现在变成了
A-> C-> D-> - > E-> G-> H-> J- I标记
如果无法确定两个元素之间的关系,那么它们就是兄弟姐妹。因此,如果您尝试在上面的列表中插入'f',您就会知道它应该在'd'之后和'g'之前,但是没有关于它的相对位置的信息'e'。因此,将'f'存储为'e'的兄弟。
这样做直到插入所有元素。
很明显,第5步是上述算法中最丑陋和最棘手的部分。但我认为它可以进行优化,使其更简单,更快捷。例如,您可以在确定相对位置的同时,在原始列表中创建char->位置的哈希映射,以便更快地进行查找。此外,您还可以维护链接列表中已存在的所有元素的集合,以便在元素已存在时避免遍历链接列表。我相信有很多方法可以进一步优化。