简体   繁体   English

编码 function 以复制链表 C++

[英]Coding a function to copy a linked-list in C++

I need to implement an auxilliary function, named copyList, having one parameter, a pointer to a ListNode.我需要实现一个名为 copyList 的辅助 function,它有一个参数,一个指向 ListNode 的指针。 This function needs to return a pointer to the first node of a copy of original linked list.这个function需要返回一个指向原链表副本首节点的指针。 So, in other words, I need to code a function in C++ that takes a header node of a linked list and copies that entire linked list, returning a pointer to the new header node.因此,换句话说,我需要在 C++ 中编写一个 function,它采用链表的 header 节点并复制整个链表,返回指向新 header 节点的指针。 I need help implementing this function and this is what I have right now.我需要帮助来实现这个 function,这就是我现在所拥有的。

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;
}

Also, this is the Listnode structure I am working with:此外,这是我正在使用的 Listnode 结构:

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

Note: another factor I am running into with this function is the idea of returning a pointer to a local variable.注意:我遇到这个 function 的另一个因素是返回指向局部变量的指针的想法。

The first question you need to ask yourself is what the copy semantics are.您需要问自己的第一个问题是复制语义是什么。 In particular, you're using a Student* as node contents.特别是,您使用Student*作为节点内容。 What does copying node contents mean?复制节点内容是什么意思? Should we copy the pointer so that the two lists will point to (share) the same student instances, or should you perform a deep copy ?我们应该复制指针以便两个列表指向(共享)相同的学生实例,还是应该执行深复制

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

The next question you should ask yourself is how you will allocate the nodes for the second list.您应该问自己的下一个问题是如何为第二个列表分配节点。 Currently, you only allocate 1 node in the copy.目前,您只在副本中分配 1 个节点。

I think you code should look more like:我认为你的代码应该更像:

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;
}

If you prefer sharing student instances between the two lists, you can use如果您更喜欢在两个列表之间共享学生实例,您可以使用

copy->student = current->student;

instead of代替

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

This is an excellent question since you've done the bulk of the work yourself, far better than most "please do my homework for me" questions.这是一个很好的问题,因为你自己完成了大部分工作,比大多数“请帮我做作业”的问题要好得多。

A couple of points.几点。

First, what happens if you pass in an empty list?首先,如果传入一个空列表会怎样? You probably want to catch that up front and just return an empty list to the caller.您可能希望预先捕捉到它并只向调用者返回一个空列表。

Second, you only allocate the first node in the copy list, you need to do one per node in the original list.其次,您只分配副本列表中的第一个节点,您需要为原始列表中的每个节点分配一个。

Something like (pseudo-code (but C++-like) for homework, sorry):类似于(伪代码(但类似于 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

And, while you're correct that you shouldn't return a pointer to a local stack variable, that's not what you're doing.而且,虽然您不应该返回指向本地堆栈变量的指针是正确的,但这不是您正在做的。 The variable you're returning points to heap-allocated memory, which will survive function exit.您要返回的变量指向堆分配的memory,它将在 function 退出后继续存在。

I have been trying to do the same thing.我一直在尝试做同样的事情。 My requirements were:我的要求是:

1. Each node is a very basic and simple class (I moved away from the struct model). 1.每个节点都是一个很基础很简单的class(我搬离了struct模型)。
2. I want to create a deep copy, and not just a pointer to the old linked list. 2. 我想创建一个深拷贝,而不仅仅是指向旧链表的指针。

The way that I chose to do this is with the following C++ code:我选择的方法是使用以下 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;
}

This works well, with no errors.这很好用,没有错误。 Because the "head" is a special case, there is a need for my implementation of a "current" pointer.因为“head”是一个特例,所以需要我实现一个“current”指针。

The statement copy->next = current->next is wrong.语句copy->next = current->next是错误的。 You should do你应该做

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;
}

Since you need a copy of the linked list, you need to create a new node in the loop while traversing through the original list.由于需要链表的副本,因此需要在遍历原始链表的同时在循环中创建一个新节点。

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;

Remember to delete the nodes of linked list.记得delete链表的节点。

@pat, I guess you will get a seg_fault, because you create memory only once. @pat,我猜你会得到一个 seg_fault,因为你只创建了一次 memory。 You need to create memory(basically call 'new') for each and every node.您需要为每个节点创建内存(基本上称为“新”)。 Find out, where you need to use the 'new' keyword, to create memory for all the nodes.找出需要使用“new”关键字的地方,为所有节点创建 memory。

Once you are done with this, you need to link it to the previous node, since its a singly linked list, you need to maintain a pointer to the previous node.一旦你完成了这个,你需要将它链接到前一个节点,因为它是一个单链表,你需要维护一个指向前一个节点的指针。 If you want to learn and should be able to remember all life, don't see any of the code mentioned above.如果你想学习并且应该能够记住所有的生活,请不要看到上面提到的任何代码。 Try to think the above mentioned factors and try to come up with your own code.尝试考虑上述因素并尝试提出自己的代码。

As others have pointed out, you need to call new for each node in the original list to allocate space for a copy, then copy the old node to the new one and update the pointer in the copied node.正如其他人指出的那样,您需要为原始列表中的每个节点调用new来为副本分配空间,然后将旧节点复制到新节点并更新复制节点中的指针。

another factor I am running into with this function is the idea of returning a pointer to a local variable.我遇到这个 function 的另一个因素是返回指向局部变量的指针的想法。

You are not returning a pointer to a local variable;您没有返回指向局部变量的指针; when you called new , you allocated memory on the heap and are returning a pointer to that (which of course means that you need to remember to call delete to free it when you are done with the new list, from outside the function).当您调用new时,您在堆上分配了 memory 并返回指向它的指针(这当然意味着您需要记住在完成新列表时从函数外部调用delete以释放它)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM