【问题标题】:Coding a function to copy a linked-list in C++编写函数以在 C++ 中复制链表
【发布时间】:2012-04-22 09:06:36
【问题描述】:

我需要实现一个名为 copyList 的辅助函数,它有一个参数,一个指向 ListNode 的指针。该函数需要返回一个指向原始链表副本的第一个节点的指针。因此,换句话说,我需要在 C++ 中编写一个函数,该函数采用链表的头节点并复制整个链表,返回指向新头节点的指针。我需要帮助来实现这个功能,这就是我现在所拥有的。

Listnode *SortedList::copyList(Listnode *L) {

    Listnode *current = L;  //holds the current node

    Listnode *copy = new Listnode;
    copy->next = NULL;

    //traverses the list
    while (current != NULL) {
       *(copy->student) = *(current->student);
       *(copy->next) = *(current->next);

        copy = copy->next;
        current = current->next;
    }
    return copy;
}

另外,这是我正在使用的 Listnode 结构:

struct Listnode {    
  Student *student;
  Listnode *next;
};

注意:我在使用这个函数时遇到的另一个问题是返回一个指向局部变量的指针。

【问题讨论】:

  • +1 提出了一个很好的问题!第一个反问:你能通过分配一个节点来复制整个列表吗?第 2、3、...和第 n 个节点内容的副本将存储在哪里?
  • 谢谢,我不确定我是否完全回答了您的问题,但我会尽力而为:-我应该创建一个全新的列表副本。因此,我无法复制标头节点,因为我复制的列表将包含相同的引用。我只想复制这些值。 - 此外,复制列表中的第一个 listnode 应该与原始列表中的第一个 listnode 具有相同的值。但是复制的列表不应引用/指向原始列表中的任何节点。
  • 新列表不应该指向旧的任何一个节点,但新节点应该指向旧的内容吗?在这种情况下,“内容”是“学生”对象。基本上,你也在抄学生吗?问题中并不清楚。所以这两个列表可以指向同一个学生,但是是不同的列表,或者每个列表也可以“拥有”他们自己的学生副本。
  • 不,链表的新(复制版本)中的任何内容都不应引用旧链表中的任何内容。也就是说,所有新的列表节点和 NO 指针指向内存中完全相同的学生或内存中的下一个。
  • 由于这没有被标记为作业,省点麻烦,使用std::list。它已经过测试,所以你可以在你现在使用调试的时候应用到其他东西,比如聚会。

标签: c++ linked-list


【解决方案1】:

我一直在尝试做同样的事情。我的要求是:

1.每个节点都是一个非常基础和简单的类(我从struct模型中移开)。
2.我想创建一个深拷贝,而不仅仅是一个指向旧链表的指针。

我选择这样做的方式是使用以下 C++ 代码:

template <class T>
Node <T> * copy(Node <T> * rhs)
{
    Node <T> * current = new Node<T>();
    Node <T> * pHead = current;
    for (Node <T> * p = rhs; p; p = p->pNext)
    {
        Node <T> * prev = current;
        prev->data = p->data;
        if (p->pNext != NULL)
        {
            Node <T> * next = new Node<T>();
            prev->pNext = next;
            current = next;
        }
        else
        {
            prev->pNext = NULL;
        }
    }
    return pHead;
}

这很好用,没有错误。因为“头”是一个特例,所以我需要实现一个“当前”指针。

【讨论】:

    【解决方案2】:

    您需要问自己的第一个问题是复制语义是什么。特别是,您使用 Student* 作为节点内容。复制节点内容是什么意思?我们应该复制指针以便两个列表指向(共享)相同的学生实例,还是应该执行deep copy

    struct Listnode {    
      Student *student; // a pointer?  shouldn't this be a `Student` object?
      Listnode *next;
    };
    

    您应该问自己的下一个问题是如何为第二个列表分配节点。目前,您只在副本中分配 1 个节点。

    我认为你的代码应该更像:

    Listnode *SortedList::copyList(Listnode *L) {
    
        Listnode *current = L;
    
        // Assume the list contains at least 1 student.
        Listnode *copy = new Listnode;
        copy->student = new Student(*current->student);
        copy->next = NULL;
    
        // Keep track of first element of the copy.
        Listnode *const head = copy;
    
        // 1st element already copied.
        current = current->next;
    
        while (current != NULL) {
           // Allocate the next node and advance `copy` to the element being copied.
           copy = copy->next = new Listnode;
    
           // Copy the node contents; don't share references to students.
           copy->student = new Student(*current->student);
    
           // No next element (yet).
           copy->next = NULL;
    
           // Advance 'current' to the next element
           current = current->next;
        }
    
        // Return pointer to first (not last) element.
        return head;
    }
    

    如果您更喜欢在两个列表之间共享学生实例,您可以使用

    copy->student = current->student;
    

    而不是

    copy->student = new Student(*current->student);
    

    【讨论】:

      【解决方案3】:

      正如其他人指出的那样,您需要为原始列表中的每个节点调用new为副本分配空间,然后将旧节点复制到新节点并更新指针在复制的节点中。

      我在使用这个函数时遇到的另一个问题是返回一个指向局部变量的指针。

      您没有返回指向局部变量的指针;当你调用new 时,你在堆上分配了内存并返回了一个指向它的指针(这当然意味着你需要记住在完成新列表后调用delete 以释放它,来自 在函数之外)。

      【讨论】:

        【解决方案4】:

        这是一个优秀的问题,因为你自己完成了大部分工作,比大多数“请为我做作业”的问题要好得多。

        几点。

        首先,如果你传入一个空列表会发生什么?您可能想提前抓住它,然后将一个空列表返回给调用者。

        其次,你只分配复制列表中的第一个节点,你需要在原始列表中每个节点做一个。

        类似于(用于作业的伪代码(但类似于 C++),抱歉):

        # Detect empty list early.
        
        if current == NULL:
            return NULL;
        
        # Do first node as special case, maintain pointer to last element
        # for appending, and start with second original node.
        
        copy = new node()
        last = copy
        
        copy->payload = current->payload
        current = current->next
        
        # While more nodes to copy.
        
        while current != NULL:
            # Create a new node, tracking last.
        
            last->next = new node()
            last = last->next
        
            # Transfer payload and advance pointer in original list.
        
            last->payload = current->payload
            current = current->next
        
        # Need to terminate new list and return address of its first node
        
        last->next = NULL
        return copy
        

        而且,虽然您不应该返回指向本地堆栈变量的指针是正确的,但 不是 您正在做的事情。您返回的变量指向堆分配的内存,它将在函数退出后继续存在。

        【讨论】:

          【解决方案5】:

          @pat,我猜你会得到一个 seg_fault,因为你只创建一次内存。您需要为每个节点创建内存(基本上称为“新”)。找出需要在哪里使用“new”关键字来为所有节点创建内存。

          完成此操作后,您需要将其链接到前一个节点,因为它是一个单链表,您需要维护指向前一个节点的指针。如果您想学习并且应该能够记住所有生活,请不要看到上面提到的任何代码。尝试考虑上述因素并尝试提出自己的代码。

          【讨论】:

            【解决方案6】:

            由于您需要链表的副本,因此您需要在遍历原始链表时在循环中创建一个新节点。

            Listnode *startCopyNode = copy;
            
            while (current != NULL) {
               *(copy->student) = *(current->student);
                copy->next = new Listnode;
                copy = copy->next;
                current = current->next;
            }
            
            copy->next = NULL;
            return startCopyNode;
            

            记得delete链表的节点。

            【讨论】:

              【解决方案7】:

              声明 copy-&gt;next = current-&gt;next 是错的。你应该这样做

              Create the first node copy here
              copy->student = current->student;
              copy->next = NULL;
              while(current->next!=NULL)
              {
                  Create new node TEMP here
                  copy->next = TEMP;
                  TEMP->student = current->student;
                  TEMP->next = NULL;
                  copy = TEMP;
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-07-10
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多