Reputation: 300
I'm trying to make a copy of a linked List using the duplicate() method of the LinkedList class. 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. Should I be returning a LinkedList pointer? 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.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;
}
}
Upvotes: 0
Views: 3336
Reputation: 33932
Looks like Remy Lebeau got in here before I could get back to this. Only thing I can add is a slightly tighter, and a bit more confusing, way to write 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;
}
Upvotes: 0
Reputation: 596352
Your duplicate()
code has several logic issues in it.
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:
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:
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;
}
Upvotes: 2
Reputation: 281
If you're trying to do a deep copy
(assignment operator) of the linked list, consider using recursion
.
Compare this
against a passed in reference of the second list. If they are not the same, clear
the list. If the passed in list has a head pointer, call the recursive method. This method would take a node* n
. Check if it exits, if it does, call itself with n
's next pointer. Then it should add n
's data to the head of the list. 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.
If you are just doing a copy constructor you can simply set *this
equal to the passed in list. E.g.
LinkedList (const LinkedList& other) {
count = 0;
head = nullptr;
*this = other;
}
Upvotes: 0
Reputation: 794
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.
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;
}
Upvotes: 3