合并有序列表

时间:2011-04-30 02:43:17

标签: java

请允许我用一个例子问这个问题: 假设我们有以下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。

2 个答案:

答案 0 :(得分:5)

可以使用topological sorting完成此操作。

首先从列表中构建有向图。列表的元素成为节点。边缘从第一个元素到第二个元素,从第二个元素到第三个元素,依此类推。

根据您实施算法的方式,您可以获得所有可能的解决方案,或者只获得一个解决方案。此外,如果图形包含一个循环,则算法将以错误停止。

这是您的列表中的图表的样子:

graph

来源:

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.

如果任何两个元素的相对位置与原始数据不同,这将帮助您验证第四个列表并抛出异常。

创建链接列表

可以想象,第一步,即创建双向链表是最具挑战性的部分。我没有想出最优雅的创作方法,但这里只有一个。

  1. 将最长的列表L1放入 双重链表。所以,在你的例子中,这是第3个列表,你现在就可以了 有

    a->d->e->g->h->j->i
    
  2. 现在迭代其余元素 并为每个元素检查它是否存在于链表中。如果是,请忽略。

  3. 如果它不存在,则需要将元素插入到链表中。所以现在我们需要找出应该添加这个元素的位置。我们称这个元素为'X'。

  4. 遍历链表的长度,并且对于每个元素说'Y',检查L2和L3是否在X&之间存在位置关系。是的。例如,如果我们试图在上面的链表中插入'c',我会从链表的第一个元素开始,即'a',并在列表中看到'a'和'C'。

  5. 如果我们可以确定原始列表中两个元素的相对位置,则定义关系存在。从第一个列表中,我知道'c'在'a'之后。所以'c'应该插在'a'之后的某个地方。所以我们在链表中前进,现在将'd'与'c'进行比较。再次从第一个原始列表中,我们知道'c'在'd'之前。答对了。在'a'和'd'之间插入'c'。所以链表现在变成了

    A-> C-> D-> - > E-> G-> H-> J- I标记

  6. 如果无法确定两个元素之间的关系,那么它们就是兄弟姐妹。因此,如果您尝试在上面的列表中插入'f',您就会知道它应该在'd'之后和'g'之前,但是没有关于它的相对位置的信息'e'。因此,将'f'存储为'e'的兄弟。

  7. 这样做直到插入所有元素。

  8. 很明显,第5步是上述算法中最丑陋和最棘手的部分。但我认为它可以进行优化,使其更简单,更快捷。例如,您可以在确定相对位置的同时,在原始列表中创建char->位置的哈希映射,以便更快地进行查找。此外,您还可以维护链接列表中已存在的所有元素的集合,以便在元素已存在时避免遍历链接列表。我相信有很多方法可以进一步优化。