Linked list, add node to end - c++

I'm working on a project and I was given this function to complete
void addToEnd(node*& head, string newVal)
Effect: adds new node to tail end of list
Precondition: head is a pointer to first node in the list (list MAY be empty)
Postcondition: list contains one more node
My question is what is the string newVal for?
The value_type of this class is of type DOUBLE so I'm confused what string newVal is for. So I can't set the newVal in the node because it is of two different types.
This is what I have so far. I'm not sure if im going in the right direction.
node *temp = new node;
temp = head;
while(temp->link() != NULL){
temp = temp->link();
}
head->set_link(temp);
I'm not even sure where to use the string in this block of code.
link() returns the member variable node* link_field
set_link() sets the new link to the link_field

Well, we're guessing that they somehow expect you to turn a string into a double with a function like std::stod.
As for your list manipulation code, there's a few problems:
node *temp = new node;
temp = head;
This creates a new node, puts its pointer in temp, then immediately overwrites temp with head, losing (leaking) the new node. Don't do that.
while(temp->link() != NULL){
temp = temp->link();
}
This is close, but might not work. The problem is that you need to keep track of the real node pointer, not a copy.
Normally, in a linked list API using pointers instead of references, the "add node" function looks like:
void addToEnd(node** head, string newVal)
{
while(*head)
head = &((*head)->next);
*head = new node;
(*head)->value = newVal;
(*head)->next = 0;
}
Note that if the list is empty, the passed-in head pointer is altered to point to the new node. If the list is not empty, the last next pointer is altered instead.
The API you're given (i.e. the link and set_link methods) doesn't allow this, because the head pointer is not a node and those functions require a node. So you've got to do it a little differently, namely you have to handle the empty list case separately.
void addToEnd(node*& head, string newVal)
{
// Create the node.
node* newNode = new node;
newNode->value = std::stod(newVal);
newNode->set_link(0);
if(!head) // Empty list?
{
head = newNode;
return;
}
// Find last node.
node* item = head;
while(item->link())
item = item->link();
item->set_link(newNode);
}

Related

Copying a SkipList / Linked List

In the programming assignment, I need to clone a linked list (its a copy constructor so not returning anything but cloning). The old linked list will be going through some removing and adding elements but the new cloned linked list should remain untouched. How do I do that? When I remove and add new nodes to the old list, it also does the same for the new linked list. How can I avoid this?
this->head = other.head;
this->head->val = other.head->val;
SNode *curr = other.head->next;
SNode *newCurr = nullptr;
while (curr != nullptr) {
newCurr = curr;
curr = curr->next;
}
}
I have tried the above code, but when I modify the old list, ie, adding and removing nodes, it also adds and removes nodes from the new list. What can I do to avoid the modifications happening on the new list?
Your code is not creating new nodes, so this cannot work. A cloned list should consist of new nodes, so the SNode constructor should be called.
For instance:
this->head = other.head;
This will just make the new list point to the same list: now you have two head pointers pointing to the same head node. And then, by consequence, the following assignment doesn't do anything useful, as it really is assigning a member's own value to itself:
this->head->val = other.head->val;
The loop isn't doing anything useful either, as it is not assigning anything to any member that belongs to the new structure. It only assigns to variables, walking through the original list with two variables, where newCurr follows one step behind curr.
Here is a correction of your snippet:
// Deal with boundary case: empty list
this->head = NULL;
if (other.head == NULL) return; // Nothing more to do.
// Clone the head node
this->head = new SNode(other.head->val);
SNode *curr = other.head->next;
SNode *tail = this->head; // tail is a more descriptive name
while (curr != nullptr) {
tail->next = new SNode(curr->val); // Clone current node and append it
tail = tail->next; // This new node is now the tail
curr = curr->next;
}
This assumes you have an SNode constructor that takes a single argument for the node's value.

I tried to type a function to add a node at the end of a singlylinked list but is doesn't work

I typed the function to add the node at the end of a singly linked list.
But is doesn't work.
I have tried using if else to display 1st node,when list is empty(by condition head=NULL). Somehow it seems to work.
void insert(int x)
{
node* temp=new node;
node* n=head;
temp->data=x;
temp->next=NULL;
while(n!=NULL)
{
n=n->next;
}
n->next=temp;
}
The program is showing segmentation fault.
This just assigns your new node to a local variable n. It doesn't change a thing in your list:
n=temp;
An efficient way to do this would be something like this instead:
void insert(int x)
{
node** pp = &head;
while (*pp)
pp = &(*pp)->next;
*pp = new node;
(*pp)->data = x;
(*pp)->next = nullptr;
}
This simply walks the pointers in the list using a pointer-to-pointer. Upon finding the termination pointer (which may be head if the list is empty and the head value was nullptr in case that wasn't obvious), the new node is allocated and hung in place. This also fixes a problem in your original post (hanging the first node on an empty list with a null head).

Having a little trouble with pointers

The below is meant to reverse a linked list. It seems to work till it gets to the last line. When I debug, both "current" and "result" are of the same type (Node*) and "result" is the list reversed. But when the function completes, current only has the first value of the "result" list. Anyone know why "current" is not the full list when the function completes?
struct Node {
int data;
Node* next;
};
void reverseList(Node** head)
{
Node* current = *head;
Node* result = NULL;
while (current != NULL)
{
Node* temp = current;
current = temp->next;
temp->next = result;
result = temp;
}
current = result;
}
There are multiple problems with the shown logic.
We can start with the obvious observation that the goal of reverseList is, apparently, to reverse a singly-linked list.
The second observation is that the function takes a single parameter, a pointer to the head node, and it returns a void.
From, that we conclude that the function should update the head node, but there's nothing in the code that does that.
Additionally, there's really no reason why this function should take a double pointer like that, a pointer to the head node, and update it. It's much simpler for the function to take an ordinary pointer to the first element of the list, the existing head pointer, and then return the head pointer of the reversed list.
With this simple change, the resulting logic becomes much, much shorter and simpler:
Node *reverseList(Node *head)
{
Node *current=NULL;
while (head)
{
Node *next=head->next;
head->next=current;
current=head;
head=next;
}
return current;
}
That's it.
you need to update the head at the end of your algorithm:
current = result;
*head = current;

The status of head in this linked list

My mind is confused at the moment:
struct Node {
int data;
struct Node *next;
}
void Print(Node *head) {
}
This is a code snippet from HackerRank. While this is easy, I just started wondering something: If I modify the head in the Print function, does it modify the original head in the main as well, or is it just the local variable head that is modified?
You passed in a pointer by value, if you modify that pointer then it will not affect the original.
However if you modify what is pointed to by that pointer then it will affect the original.
For instance head = nullptr; would not, while head->data = 1; would.
Also note that any recursion you do will similarly change the original data, for instance an algorithm to add to the end of the list:
Node* previous = head
Node* current = head->next;
while (current != nullptr)
{
previous = current;
current = previous->next;
}
previous->next = new Node(); //However you create one.
Since it uses head->next and eventually modifies the result it will modify the original list.

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. This function needs to return a pointer to the first node of a copy of original linked list. 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. I need help implementing this function and this is what I have right now.
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:
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.
The first question you need to ask yourself is what the copy semantics are. In particular, you're using a Student* as node contents. 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.
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):
# 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.
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).
2. I want to create a deep copy, and not just a pointer to the old linked list.
The way that I chose to do this is with the following C++ code:
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.
The statement
copy->next = current->next
is wrong. 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.
#pat, I guess you will get a seg_fault, because you create memory only once. 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.
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.
another factor I am running into with this function is the idea of returning a pointer to a local variable.
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).