深层复制链表 - O(n)

时间:2011-02-20 14:54:45

标签: c++ c algorithm linked-list

我正在尝试深层复制链表。我需要一个在线性时间O(n)中执行的算法。这就是我现在所拥有的,但我无法弄清楚它出了什么问题。我的应用程序崩溃,我怀疑内存泄漏,我还没有弄清楚。这就是我现在所拥有的

 struct node {
    struct node *next;
    struct node *ref;
 };


struct node *copy(struct node *root) {
    struct node *i, *j, *new_root = NULL;

    for (i = root, j = NULL; i; j = i, i = i->next) {
        struct node *new_node;
        if (!new_node) 
        {
            abort();
        }
        if (j) 
        {
            j->next = new_node;
        }
        else 
        {
            new_root = new_node;
        }

        new_node->ref = i->ref;
        i->ref = new_node;
    }
    if (j) 
    {
            j->next = NULL;
    }
    for (i = root, j = new_root; i; i = i->next, j = j->next)
        j->ref =i->next->ref;

      return new_root;
}

有谁可以指出我哪里出错?

3 个答案:

答案 0 :(得分:4)

这件作品:

    struct node *new_node;
    if (!new_node) 
    {
        abort();
    }

对于随机发生的abort()似乎很有用。 new_node未分配,将包含随机值。 !new_node表达式可能已经致命(在某些系统上)。

作为一般提示,您应该只需要1个for循环。一些代码预先建立new_root

但是,非常深的副本也需要克隆ref指向的任何内容。在我看来,第二个循环将原始内容分配给副本。但我不确定,什么是ref

答案 1 :(得分:2)

我立即注意到的一件事是你永远不会为new_node分配空间。由于不保证自动变量被初始化,因此new_node将被设置为之前该存储器中的任何值。您应该从以下内容开始:

struct node *new_node = (new_node *) malloc(sizeof(struct node));
在C中

,或者如果您正在使用C ++:

node* new_node = new node;

复制列表很简单。但是,ref指针指向新列表中相对于源列表的相同节点的要求将难以以任何有效的方式进行。首先,您需要某种方法来识别相对于它们指向的源列表的节点。您可以在每个节点中放置某种标识符,例如在第一个节点中设置为0的int,在第二个节点中设置为1,等等。然后在复制列表后,您可以再次通过列表进行设置参考指针。这种方法的问题(除了向每个节点添加另一个变量)是因为它会使算法的时间复杂度从O(n)跳到O(n ^ 2)。

答案 2 :(得分:0)

这是可能的,但需要一些工作。我将假设使用C ++,并省略struct中的struct node关键字。

您需要做一些记账以跟踪“参考”指针。在这里,我将它们转换为原始列表中的数字索引,然后返回指向新列表的指针。

node *copy_list(node const *head)
{
    // maps "ref" pointers in old list to indices
    std::map<node const *, size_t> ptr_index;
    // maps indices into new list to pointers
    std::map<size_t, node *>       index_ptr;

    size_t length = 0;
    node       *curn; // ptr into new list
    node const *curo; // ptr into old list

    node       *copy = NULL;

    for (curo = head; curo != NULL; curo = curo->next) {
        ptr_index[curo] = length;
        length++;

        // construct copy, disregarding ref for now
        curn = new node;
        curn->next = copy;
        copy = curn;
    }

    curn = copy;
    for (size_t i=0; i < length; i++, curn = curn->next)
        index_ptr[i] = curn;

    // set ref pointers in copy
    for (curo = head, curn = copy; curo != NULL; ) {
        curn->ref = index_ptr[ptr_index[curo->ref]];

        curo = curo->next;
        curn = curn->next;
    }

    return copy;
}

此算法在O( n lg n )中运行,因为它将所有 n 列表元素存储在std::map中,具有O(lg n )插入和检索复杂性。它可以通过使用哈希表来变为线性。

注意:未经测试,可能包含错误。