恢复链接列表

时间:2017-11-23 02:15:59

标签: python algorithm

我有一个链接列表,它已经在一个数组中按顺序存储,并且通过在每个元素中存储下一个元素的索引来保留有关原始顺序的信息。

例如,

[c;3][b;0][a;1][d;4]

此处[c;3]表示c后跟d(存储在3); [b;0]表示b后跟c(存储在0),依此类推。 4中的出界索引[d;4]表示d是最后一个元素。

我正在寻找一种算法来从这样的数组中提取示例中的原始链表顺序abcd

最后一个元素总是排在最后(已经在正确的位置),算法可能会使用这个事实。

为了澄清这个问题,让我根据Python数据结构重新制定它。

我有一个2元组列表,其中每个元组中的第二个元素是一个整数,用于定义列表中的遍历顺序。整数的值是要遍历的下一个元组的索引。例如,给出一个列表

[('c', 3), ('b', 0), ('a', 1), ('d', 4)]

遍历顺序是

[2, 1, 0, 3]

('a', 1) - > ('b', 0) - > ('c', 3) - > ('d', 4)。如何编写一个函数,给出上面描述的2元组列表会找到遍历顺序。

这是一个可能的Python解决方案:

def order(x):
    nexts = [n for _, n in x]
    prevs = [-1] * (len(a) + 1)
    for i, n in enumerate(nexts):
        prevs[n] = i
    trav = []
    i = prevs[-1]
    for _ in x:
        trav.append(i)
        i = prevs[i]
    return trav[::-1]

给出示例数据

>>> a = [('c', 3), ('b', 0), ('a', 1), ('d', 4)]

此函数产生预期结果

>>> order(a)
[2, 1, 0, 3]
>>> [a[i] for i in order(a)]
[('a', 1), ('b', 0), ('c', 3), ('d', 4)]

有更好的解决方案吗?

4 个答案:

答案 0 :(得分:0)

头部是没有任何指向它的元素。你可以走过一次并跟踪没有任何指向它的东西,然后再次走过去以线性时间打印出来。

答案 1 :(得分:0)

通过查找未指向的任何元素,在O(n)时间和空间中查找链表头部的索引。

或者,按索引按升序排序,使NULL大于任何索引。这绝对可以在O(n log n)时间和O(1)空间中完成;你也可以使用线性排序算法,因为指数的界限相当好。可能存在线性排序的就地变体;要检查的东西。

答案 2 :(得分:0)

所以你有这个[c;3][b;0][a;1][d;NULL],你想重新安排到[a][b][c][d]

给定数组中的最后一项包含列表的尾部。因此,您可以使用与选择排序类似的O(n ^ 2)算法向后构建列表。

伪代码中的一般想法是:

new_list = new array[a.length];
int pass = a.length-1;
new_list[pass] = a[a.length-1];

while (pass > 0)
{
    for (j = 0; j < a.length-1; j++)
    {
        if (a[j].index == pass)
        {
            new_list[pass] = a[j];
            break;
        }
    }
    --pass;
}

这应该有效,尽管效率不高。但是,如果你不经常打电话,它对于小清单来说没问题。

使用字典的速度更快,编码起来稍微困难一些。我们的想法是将项目的位置存储为密钥,将其前身存储为值。如果您还没有该项目的前任,则存储-1。因此,对于此示例,您将查看第一个项[c;3]。你不了解它的前身,所以你将{0,-1}存储在字典中。然后查看词典,看看你是否已经有了&#39; 3&#39;的条目。你没有,所以你跳到数组索引3处的项目,[d,NULL]。它的前身是0,所以你将{3,0}添加到字典中。

此时,您没有继任者,因此您将返回到顺序扫描中的最后一个位置并转到下一个项目:[b;0]。你不了解它的前身,所以你将{1,-1}存储在字典中。这个项目的后继是0,你已经在字典里了。因此,您将条目更新为{0,1},然后继续进行正向扫描。您不知道[a;1]的前身,因此您将{2,-1}添加到词典中。您的字典中已有1的条目,因此您将其更新为{1,2}。您前进到最后一个条目,看到您的字典中已有4,并且您已完成。

您的词典包含:

{0,1},{3,0}{1,2}{2,-1}

由于您知道3是列表的结尾,因此您可以从字典中开始,然后按照前导链接向后构建有序序列。当您到达前缀为-1的条目时,您就知道已经完成了。

最坏的情况是,这会使3 * n遍历每个项目:在数组扫描中两次,在跟踪字典中的链接时一次。

答案 3 :(得分:-1)

为了拥有一个链表,你必须有一个指向其头部的指针(开头)。要在这种情况下找到头部,请迭代整个数组一次,直到知道任何其他节点未指向哪个节点。然后,您需要做的就是按照每个节点上的指针,直到达到NULL。