简体   繁体   English

C ++如何创建链表的副本作为类对象?

[英]C++ How do I create a copy of a Linked List as a class object?

I'm trying to make a copy of a linked List using the duplicate() method of the LinkedList class. 我正在尝试使用LinkedList类的plicate()方法制作一个链表的副本。 I've been scratching my head all day about how to make this method work. 我整天都在摸索如何使这种方法起作用。

The duplicate method needs to make an exact copy of the list, returning a pointer to the new list. 复制方法需要精确复制列表,并返回指向新列表的指针。 I want to be able to call LinkedList methods on the new list. 我希望能够在新列表上调用LinkedList方法。 Should I be returning a LinkedList pointer? 我应该返回LinkedList指针吗? or a Node pointer? 或节点指针? I feel like I'm totally missing something easy here. 我觉得我在这里完全容易错过一些事情。

How would I even store the location of the new head node in the LinkedList pointer? 我什至将如何在LinkedList指针中存储新头节点的位置?

//LinkedList.h
#pragma once

#include<string>

using namespace std;

struct Node {
    string nodeData;
    Node* nextNode;
};

class LinkedList {
public:
    LinkedList();

    ~LinkedList();

    bool insert(string givenData);

    bool remove(string givenData);

    void print() const;

    int count() const;

    int find(string givenData) const;

    bool removeAll();

    LinkedList* duplicate() const;

private:
    Node* head;
};


//LinkedList.cpp duplicate() method
LinkedList* LinkedList::duplicate() const {
    LinkedList* newList;
    Node* newHeadNode = new Node;
    Node* newNode = new Node;

    newHeadNode->nodeData = head->nodeData;
    newHeadNode->nextNode = head->nextNode;

    Node* currentNode = head->nextNode;
    Node* previousNode = head;

    while ((currentNode) && (newNode->nodeData > currentNode->nodeData)) {
        previousNode = currentNode;
        currentNode = currentNode->nextNode;

        newNode->nextNode = previousNode->nextNode;
        previousNode->nextNode = newNode;
    }
}

You are confusing the role of pointers and data, to begin. 首先,您会混淆指针和数据的角色。

All nodes have "links" to the next node. 所有节点都有到下一个节点的“链接”。 If you want to duplicate a list, you want to create copies of each node, and connect them. 如果要复制列表,则要创建每个节点的副本并进行连接。 This means that you should not connect the new nodes to the old ones, but just the new nodes between them. 这意味着您不应将新节点连接到旧节点,而应将它们之间的新节点连接。

newHeadNode->nextNode = head->nextNode; is thus wrong. 因此是错误的。

Also, your class has an insert method, which you can use, and probably already correctly create a node and set the old tail node pointer. 同样,您的类具有一个insert方法,您可以使用该方法,并且可能已经正确创建了一个节点并设置了旧的尾节点指针。

Your function body should look like 您的功能主体应该看起来像

LinkedList* LinkedList::duplicate() const {
    // create a new list
    LinkedList* newList = new LinkedList();
    // start from the first node of the old list
    currnode = this->head;

    // until currnode is valid
    while(currnode){
        // insert the data in the new list (the new list will deal with the pointers)
        newList->insert(currnode->data);
        // go to the next node of the old list
        currnode = currnode->nextNode;
    }

    return newList;

}

Your duplicate() code has several logic issues in it. 您的duplicate()代码中存在几个逻辑问题。

The code can be simplified to the following: 该代码可以简化为以下内容:

LinkedList::LinkedList()
    : head(NULL)
{
}

LinkedList* LinkedList::duplicate() const
{
    LinkedList* newList = new LinkedList;

    Node* currentNode = head;
    Node* previousNode = NULL;

    while (currentNode)
    {
        Node* newNode = new Node;
        newNode->nodeData = currentNode->nodeData;
        newNode->nextNode = NULL;

        if (!newList->head)
            newList->head = newNode;

        if (previousNode)
            previousNode->nextNode = newNode;
        previousNode = newNode;

        currentNode = currentNode->nextNode;
    }

    return newList;
}

That being said, if you add a Node *tail member to LinkedList , then duplicate() can be implemented in terms of insert() , which itself can be greatly simplified: 话虽这么说,如果你添加一个Node *tail成员LinkedList ,然后duplicate()可以在以下方面实现insert()它本身可以大大简化:

LinkedList::LinkedList()
    : head(NULL), tail(NULL)
{
}

bool LinkedList::insert(string givenData)
{
    Node* newNode = new Node;
    newNode->nodeData = givenData;
    newNode->nextNode = NULL;

    if (!head)
        head = newNode;

    if (tail)
        tail->nextNode = newNode;
    tail = newNode;

    return true;
}

LinkedList* LinkedList::duplicate() const
{
    LinkedList* newList = new LinkedList;

    Node* currentNode = head;
    while (currentNode)
    {
        newList->insert(currentNode->nodeData);
        currentNode = currentNode->nextNode;
    }

    return newList;
}

If adding tail is not an option, then at least consider adding an optional Node* parameter to insert() instead: 如果不添加tail ,则至少考虑将一个可选的Node*参数添加到insert()

Node* LinkedList::insert(string givenData, Node *after)
{
    Node* newNode = new Node;
    newNode->nodeData = givenData;
    newNode->nextNode = NULL;

    if (!head) {
        head = newNode;
    }
    else {
        if (!after) {
            after = head;
            while (after->nextNode) {
                after = after->nextNode;
            }
        }
        newNode->nextNode = after->nextNode;
        after->nextNode = newNode;
    }

    return newNode;
}

LinkedList* LinkedList::duplicate() const
{
    LinkedList* newList = new LinkedList;

    Node* currentNode = head;
    Node *newNode = NULL;

    while (currentNode)
    {
        newNode = newList->insert(currentNode->nodeData, newNode);
        currentNode = currentNode->nextNode;
    }

    return newList;
}

If you're trying to do a deep copy (assignment operator) of the linked list, consider using recursion . 如果您要对链表进行deep copy (赋值运算符),请考虑使用recursion

Compare this against a passed in reference of the second list. this与第二个列表的传入引用进行比较。 If they are not the same, clear the list. 如果它们不相同,请clear列表。 If the passed in list has a head pointer, call the recursive method. 如果传入的列表具有头指针,则调用递归方法。 This method would take a node* n . 此方法将采用node* n Check if it exits, if it does, call itself with n 's next pointer. 检查是否退出,如果退出,则使用n的下一个指针进行调用。 Then it should add n 's data to the head of the list. 然后,应将n的数据添加到列表的开头。 Because this is recursive, the AddHead calls would wait on the stack until the recursion is done, and then get called in a reversed order, resulting in the correct ordering of the list. 因为这是递归的,所以AddHead调用将在堆栈上等待,直到完成递归为止,然后以相反的顺序进行调用,从而导致列表的正确顺序。

If you are just doing a copy constructor you can simply set *this equal to the passed in list. 如果您只是在执行复制构造函数,则可以简单地将*this设置为等于传入列表。 Eg 例如

LinkedList (const LinkedList& other) {
    count = 0;
    head = nullptr;
    *this = other;
}

Looks like Remy Lebeau got in here before I could get back to this. 好像雷米·勒博(Remy Lebeau)在回到这里之前就已经进入了这里。 Only thing I can add is a slightly tighter, and a bit more confusing, way to write duplicate . 我只能添加的一点是,写出duplicate方式会更严格一些,也有些混乱。 It's a good example of how an extra level of indirection can save a bit of work, so I'll drop it here anyway. 这是一个很好的例子,说明了额外的间接级别如何可以节省一些工作,因此无论如何我都会将其放在这里。

//LinkedList.cpp duplicate() method
LinkedList* LinkedList::duplicate() const {
    // make a new empty list
    LinkedList* newList = new LinkedList;

    //get the first node from the list to be duplicated
    Node * getp = head;

    //Here be where we get a bit weird. Rather than getting a pointer to the
    //head node like we did with the source list, we are going to get a pointer
    //to the head itself! Crazy, right?
    //But if you think about it, it means we can use head just like any other
    //pointer to a node (which it is) without having to write any special code
    //specifically to handle the head or having to carry around previousNode
    //pointers and other overhead
    Node ** putpp = &newList->head;

    //Loop through the source list
    while (getp != NULL)
    {
        *putpp = new Node; //make a new node and insert it into the list
                           //wherever putpp is currently pointing, head or
                           //any node's next
        (*putpp)->nodeData = getp->nodeData; // copy the source node's data
        putpp = &(*putpp)->nextNode; // point at the new node's next so we can
                                      // add the next new node
        getp = getp->nextNode; // point at the next source node
    }
    *putpp = NULL; // null the last next pointer to end the list
   return newList;
}

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

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