how last->next = temp works? - c++

This is the code for displaying a linked list from a udemy tutorial here we will take an array and store those values in a linked list. I didn't understand how the code works. in the below code where we are storing the address of the next node how last->next=temp; works where I didn't create a last node like last=new node; I only created the last pointer. I didn't get it can someone explain to me how it's working
#include <iostream>
using namespace std;
class Node{
public:
int data;
Node* next;
};
int main() {
int A[] = {3, 5, 7, 10, 15};
Node* head = new Node;
Node* temp;
Node* last;
head->data = A[0];
head->next = nullptr;
last = head;
// Create a Linked List
for (int i=1; i<sizeof(A)/sizeof(A[0]); i++){
// Create a temporary Node
temp = new Node;
// Populate temporary Node
temp->data = A[i];
temp->next = nullptr;
// last's next is pointing to temp
last->next = temp;
last = temp;
}
// Display Linked List
Node* p = head;
while (p != nullptr){
cout << p->data << " -> " << flush;
p = p->next;
}
return 0;
}

The best way to figure out pointers is to draw boxes and arrows with pen(cil) and paper.
Here is a (sad) ASCII rendition of what happens:
head->data = A[0];
head->next = nullptr;
last = head;
head points to a newly created node, and last points to the same place as head:
head
|
v
+------+------+
| data | next |
| |(null)|
| | |
+------+------+
^
|
last
Next,
// Create a temporary Node
temp = new Node;
// Populate temporary Node
temp->data = A[i];
temp->next = nullptr;
looks like this:
head temp
| |
v v
+------+------+ +------+------+
| data | next | | data | next |
| |(null)| | |(null)|
| | | | | |
+------+------+ +------+------+
^
|
last
Then
last->next = temp;
changes the next member of the node last points to (in the first iteration, this is the same node as head points to):
head temp
| |
v v
+------+------+ +------+------+
| data | next | | data | next |
| | ---------->| |(null)|
| | | | | |
+------+------+ +------+------+
^
|
last
And, lastly, you make last point to the most recently created node:
last = temp;
which gives
head temp
| |
v v
+------+------+ +------+------+
| data | next | | data | next |
| | ---------->| |(null)|
| | | | | |
+------+------+ +------+------+
^
|
last
and then you repeat the loop from there.

You have already initialized the variable last as head using last = head just before the for loop. This is done to ensure the original head does not get modified while adding other nodes to the list. In each iteration, the last node is used to keep track of the last node in the linked list so that every new node gets added to the end of the linked list.

in the below code where we are storing the address of the next node how last->next=temp; works where I didn't create a last node like last=new node; I only created the last pointer.
last is always just a pointer. It starts out equal to head, which is a pointer to the first node. In your loop, you create a new node that temp points to, and then you set the next field of the node to which last currently points to temp, and then you change last so that it now points to that same node, which is the new last node.

Related

Pointers and Pointers to pointers in a singly linked list, help me understand in C++

I'm still trying to understand pointers, drawing nodes and everything but I can't seem to understand some things.
For example here is a function that should delete nodes with even values from a list
void delete_even()
{
node* ptr = head;
while (ptr)
{
if (ptr->data % 2 == 0)
{
nod* aux = ptr;
ptr = ptr->next;
delete aux;
}
else
{
ptr = ptr->next;
}
}
}
As I understand it the pointer named ptr points to head which is the first node in the linked list.
1 What my logic looks like
So while ptr=!null check if the data in the head is even. It's not it's 1 so ptr = ptr->next;
that means (Ok, so make ptr point to whatever ptr's next elemt is pointing to) and that makes the pointer ptr point to the second node in the list, right?
2 as such
Now that ptr is pointing to the second node and the data element is even, make a new pointer named aux and make point to the same node ptr is currently pointing at!
Now make ptr point to the next node, that would be the 3rd node in the list and delete aux that contains the address of the second node;3 like this
Now that I look again it probably doesn't work because the link is broken between the first node and the 3rd node... right?
Some cool guy came and told me to use pointers to pointers as it's much easier. and helped me with this code:
void delete_even()
{
node **p= &head;
while (*p)
{
if ((*p)->data % 2 == 0)
{
node *nextptr=*p;
*p=(*p)->next;
delete nextptr;
}
else
{
p= &(*p)->next;
}
}
}
So as I understand it. p is pointing to the pointer named head that is pointing to the first node.4 like this.
p means look at the thing p is pointing at, in this case it should be the pointer head
*p means look at the thing p is pointing at, in this, the pointer head and then look again to the thing head is pointing at, so this should be the first node, right?
I think I got that right.
Now while *p!=NULL (while the first node is pointing at anything other than NULL)
Verify if the first's node data is even. It's not, it's 1. So make p (the head pointer) have the address of the second node.
5 like that
Now we see that the data is 2 and it's even so we make a pointer named nextptr and we make this pointer point to the same thing *p is pointing at, which is the second node, correct?
After that we look at the thing *p is pointing (the second node) and we make it move to the next node and we delete the nextptr pointer.
6 last one
On paper it looks the same to me, maybe my drawings and understanding is not right. but I'm spend days trying to make sense to it and it just doesn't...
I mean the second code works fine but I just don't understand why when the logic seems the same as the first one. Anyone that knows how to explain better?
So make p (the head pointer) have the address of the second node.
There are two problems with this statement.
First, p is not the head pointer. Rather p points to the head pointer (at this point in the process). When p changes, head is left unchanged. (On the other hand, if *p were to change, that would affect head.)
Second, the new value is not the address of the second node ((*p)->next). Rather, it is the address of the next pointer in the first node (&(*p)->next). Note the &.
So image five should look like the following:
head p
| |
V |
--------+---- ------------ ------------ ------------
| V | | | | | | |
| -------| | -------| | -------| | -------|
| 1 | next-+-->| 2 | next-+-->| 3 | next-+-->| 4 | NULL |
| -------| | -------| | -------| | -------|
------------- ------------ ------------ ------------
See if you can take it from here. (You were doing well until this step, so I think you can.) In case you—or someone else—gets stuck or just wants to check what image six should be, here is the situation just before deleting node 2:
head p
| |
V |
--------+---- ------------ ------------
| V | | | | |
| -------| | -------| | -------|
| 1 | next-+----------------->| 3 | next-+-->| 4 | NULL |
| -------| ------------ | -------| | -------|
------------- | | ------------ ------------
| -------| ^
nextptr--->| 2 | next-+-----|
| -------|
------------
It might also be helpful to check your result against another iteration of the loop. So here is what would be image seven:
head p
| |
V |
------------- -------+---- ------------
| | | V | | |
| -------| | -------| | -------|
| 1 | next-+----------------->| 3 | next-+-->| 4 | NULL |
| -------| | -------| | -------|
------------- ------------ ------------
Commentary: a trailing pointer can be easier to understand than this pointer-to-pointer approach.
Both implementations are actually wrong. There are several issues with them.
There is an edge case that is not being taken care of. It is when the first element, the one pointed by head is deleted - the head pointer needs to be updated with the next value. And obviously, this logic needs to be recursive such that it works with the new head after the previous head was deleted as well.
There is also logic missing to link up the last pointer over the current pointer. For that you need to maintain a last pointer and update the last->next pointer with ptr->next to keep the list connected. If the last pointer is null, you know that head needs to be updated.
There is also the mixing of too many decisions being made at the same time, which makes the algorithm unnecessarily complex. I like the idiom where the algorithm saves the next pointer before any action be taken. This frees up mental logic to think about what needs to be actually done with the data rather than trying to juggle the two streams at the same time in your head.
A minor rhetorical fix while checking for the validity of the pointer. Better check against nullptr than assuming that the null pointer is zero.
I would rewrite it like this:
void delete_even()
{
// Initialize the iterator
node* ptr = head;
node* last = nullptr;
// loop while the current pointer is not null
while (ptr!=nullptr)
{
// Save the pointer to next node
node* next = ptr->next;
// If the data is even, delete and reconnect everything
if (ptr->data % 2 == 0) {
// Delete the data
delete ptr;
// Reconnect the previous pointer so the list is intact
// This is the head node
if ( last==nullptr ) head = next;
// There is a previous valid node
else last->next = next;
} else {
// Update last to the last valid node
last = ptr;
}
// Proceed to the next node
ptr = next;
}
}

Swapping last node of the linked list is going into a infinte -- C++

Below is the code,
#include<bits/stdc++.h>
using namespace std;
class node{
public:
int data;
node * next;
node(){
this->next = NULL;
}
node(int data){
this->data = data;
this->next = NULL;
}
};
class linkedList{
public:
node * head;
node * tail;
linkedList(){
this->head = NULL;
}
void getTail(node *& t){
t = head;
while(t->next != NULL){
t = t->next;
}
}
void insertAtEnd(int data){
node * newNode = new node(data);
if(head == NULL){
head = newNode;
return;
}
node * temp = head;
while(temp->next != NULL){
temp = temp->next;
}
temp->next = newNode;
}
void print(){
node * temp = head;
while(temp != NULL){
printf("%d->", temp->data);
temp = temp->next;
}
printf("NULL\n");
}
void swap(node *& a, node *& b){
node * temp = a;
a = b;
b = temp;
}
void swapNode(node ** start, node ** end){
swap(*start, *end);
swap(((*start)->next), (*end)->next);
}
};
int main(){
///////////////////////////////////////
linkedList * ll1 = new linkedList(); //
ll1->insertAtEnd(6); //
ll1->insertAtEnd(2); //
ll1->insertAtEnd(1); //
ll1->insertAtEnd(3); //
ll1->print(); /////////////////////
ll1->swapNode(&ll1->head, &ll1->head->next->next->next);// ----> This is working
//////////////////////////////////////////////////////////
linkedList * ll2 = new linkedList();
ll2->insertAtEnd(6);
ll2->insertAtEnd(2);
ll2->insertAtEnd(1);
ll2->insertAtEnd(3);
ll2->print();
node * tail;
ll2->getTail(tail);
ll2->swapNode(&ll2->head, &tail); // This is not working // Going into a infinte loop
ll2->print();
}
When the tail node is stored in some other variable there seems be a forever loop.
While the code is working when the tail node is given by traversing to last using next pointer.
So, below is the output for the first example of the linked list, that is,
6->2->1->3->NULL
1->2->6->3->NULL
For the linked list #2, the output goes like this
6->2->1->3->NULL
3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2->1->3->2-> there's no ending
When you swap two nodes a and b you must also fix the pointers reaching a and reaching b. For example
x1 -> x2 -> a -> x3 -> x4 -> b -> x5 -> x6 -> NULL
to swap nodes a and b to don't need to fix only a.next and b.next but also x2.next and x4.next.
That part of code is missing from your implementation.
Pictures often help when dealing with linked lists. Here is the starting list.
head
|
V
------------ ------------ ------------ ------------
| 6 | next | -> | 2 | next | -> | 1 | next | -> | 3 | NULL |
------------ ------------ ------------ ------------
Now we'll call ll1->swapNode(&ll1->head, &ll1->head->next->next->next), which adds two variables to the picture.
start
|
V
head end
| |
V V
------------ ------------ ------------ ------------
| 6 | next | -> | 2 | next | -> | 1 | next | -> | 3 | NULL |
------------ ------------ ------------ ------------
Next is the call to swap(*start, *end), which swaps the head pointer and the next pointer in the node whose data is 1. So the head pointer will point to the 3 node, while the 1 node will point to the 6 node.
start
|
V
end head
| |
V V
------------ ------------ ------------ ------------
| 6 | next | -> | 2 | next | -> | 1 | next | | 3 | NULL |
------------ ------------ ------------ ------------
^ |
| |
L---------------------------------------
Finally, the call to swap(((*start)->next), (*end)->next), which swaps the next pointers in the nodes whose data is 3 and 6. So the 3 node will point to the 2 node, while the 6 node's pointer will become null.
start
|
V
head
|
V
------------
| 3 | next |
------------ end
| |
V V
------------ ------------ ------------
| 6 | NULL | | 2 | next | -> | 1 | next |
------------ ------------ ------------
^ |
| |
L---------------------------------------
Hooray! The nodes were swapped.
Now look at the call ll2->swapNode(&ll2->head, &tail);, which adds three variables to the initial picture.
start end
| |
V V
head tail
| |
V V
------------ ------------ ------------ ------------
| 6 | next | -> | 2 | next | -> | 1 | next | -> | 3 | NULL |
------------ ------------ ------------ ------------
Next is the call to swap(*start, *end), which swaps the head pointer and tail (not the tail pointer of the list, but the variable local to main()).
end start
| |
V V
tail head
| |
V V
------------ ------------ ------------ ------------
| 6 | next | -> | 2 | next | -> | 1 | next | -> | 3 | NULL |
------------ ------------ ------------ ------------
There's already a noticeable difference from the first case in that the nodes of the list are unchanged. Hmm... well, let's keep going and call swap(((*start)->next), (*end)->next), which swaps the next pointers in the nodes whose data is 3 and 6. So the 3 node will point to the 2 node, while the 6 node's pointer will become null. This is what happened in the first case, so will it work out?
end start
| |
V V
tail head
| |
V V
------------ ------------ ------------ ------------
| 6 | NULL | | 2 | next | -> | 1 | next | -> | 3 | next |
------------ ------------ ------------ ------------
^ |
| |
L---------------------------------------
PROBLEM! We are left with a cycle! What happened to the step where the 1 node was changed to point to the 6 node? That's right, we changed tail instead, and the result was disaster.
I would recommend three main things to move your code to more robust ground. (That is, don't try to fix your current error yet. Do these first as they'll change the playing field.)
Get rid of #include<bits/stdc++.h>; instead include the headers you need. For this example, you need just #include <cstdio>.
Make node a private implementation detail of linkedList. Robustness tends to increase along with encapsulation. If no one knows the data structures used by linkedList, you limit what other code can do. With fewer possibilities to account for, it's easier to make sure you accounted for all of them.
Don't declare a field (linkedList::tail) that is never used. Someone will want to use that field at some point without realizing it contains garbage.
(There are other improvements to be made. These three are the most important in my view.)

Recursive function to reverse linked list(Code Snippet Explanation) [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Can someone please explain the code below:
void reverseList(node **href){
node *first;
node *rest;
if(*href == NULL){
return;
}
first = *href;
rest = first->next;
if(rest == NULL){
return;
}
reverseList(&rest);
first->next->next = first;
first->next = NULL;
*href = rest;
}
Note : href is the head reference of the linked list.
What i don't understand is the last statement => *href = rest
as this step will happen when the recursion is unfolding wouldn't this make the second node from the start head ref but we want the last node as our head ref.
How will this make the last node as our head_ref?
reverseList will update *href so it points to the new head of the list it's given; this is the node that used to be last.
I think what could be confusing you is that all calls update *href to the same value; when the recursive call returns, it will point to the last node of the input, which is the first node of the result.
This value is only set when the recursion terminates.
I'm going to rename first and rest in an attempt to clarify this.
The first condition,
if(*href == NULL){
return;
}
is there to handle the case when you start with the empty list.
The following handles the common base case, where you eventually reach a one-element list:
old_head = *href;
/* "If the list has exactly one element, do nothing." */
if(old_head->next == NULL){
return;
}
Then, you recurse (keep in mind that the parameter is both an "in" and an "out" parameter)
new_head = old_head->next;
reverseList(&new_head);
and now, through the power of recursion, new_head points to the head of the reversed "rest of the list".
This is also the pointer that's going to be our result.
(The last node of the tail is also the last node of the entire list, right?)
What we need now is to set up the end of the new list (the initial part of it has already been reversed during the recursion).
Since we saved old_head before, we can reverse the next pointer of the node that used to follow it:
old_head->next->next = old_head;
old_head->next = NULL;
that is, this
old_head new_head
| |
v v
+---+ +---+ +-----------------------------+
| ------>| | <----- | reversed |
| | | -----> | former continuation of list |
+---+ +---+ +-----------------------------+
becomes this (old_head->next->next = old_head;)
old_head new_head
| |
v v
+---+ +---+ +-----------------------------+
| ------>| | <----- | reversed |
| |<----- | | former continuation of list |
+---+ +---+ +-----------------------------+
and then (old_head->next = NULL;)
old_head new_head
| |
v v
+---+ +---+ +-----------------------------+
| X | | | <----- | reversed |
| X |<----- | | former continuation of list |
+---+ +---+ +-----------------------------+
Then, we update the parameter so our caller also gets a pointer to the new head:
*href = new_head;

How does this linklist flow?

The structure of the node is as followed:
struct Node {
int value;
Node *next;
};
// construct a new node
Node * cons( int x, Node* p) {
return new Node{x, p};
}
Now if I were to type in my main body:
Node *p;
p = cons(3,nullptr);
p = cons(2,p);
p = cons(1,p);
p = cons(4,p);
Is there a better value to start off with for my first node instead of nullptr?From what I understand this is 4 Nodes in order. Is that correct? Node value 3 is the first on the list. So this function would search my linklist in order as in goes to view node value 3, 2,1,4,then empty node.
//search linklist in order for value x
bool searchInOrder(int x, Node *p){
while(p->next != nullptr){
if(x == p->value)
return true;
p = p->next;
}
return false;
}
Question:
Is there a better value to start off with for my first node instead of nullptr?
Answer:
That is the best way to create the first node of a linked list.
Question:
From what I understand this is 4 Nodes in order. Is that correct? Node value 3 is the first on the list. So this function would search my linklist in order as in goes to view node value 3, 2,1,4,then empty node.
Answer:
Yes there are 4 Nodes. However, the Node with value 3 is not the first Node in the list.
After
p = cons(3,nullptr);
The list is:
+---+ +-----+
+ p + ---> | 3 | ---> NULL
+---+ +-----+
After
p = cons(2,p);
The list is:
+---+ +-----+ +-----+
| p | ---> | 2 | ---> | 3 | ---> NULL
+---+ +-----+ +-----+
After
p = cons(4,p);
The list is:
+---+ +-----+ +-----+ +-----+ +-----+
| p | ---> | 4 | ---> | 1 |---> | 2 | ---> | 3 | ---> NULL
+---+ +-----+ +-----+ +-----+ +-----+

Understanding C++ code

I have been following a tutorials to make a linked list, and i'm trying to understand the code to the fullest. I just have some questions considering the code you guys might help me answer (i hope). This function is to insert a element.
node *temp = new node;
temp->nameOfFood = nameOfFood;
temp->eatCalories = eatCalories;
temp->next = NULL;
head = temp;
last = temp;
I understand this code (kinda), but i don't understand the last part - why does both head and last equals temp;? Then both the head, and last will be the same element/value?
And then the next part. Checking if the list is empty, elsewise inserting a element.
if(isEmpty(head)) //Cheacking if list is empty
insertNode(head, last, nameOfFood, eatCalories);
else
{
node *temp = new node;
temp->nameOfFood = nameOfFood;
temp->eatCalories = eatCalories;
temp->next = NULL;
last->next = temp;
last = temp;
I understand that you create the new node, and forward from there, but then last->next = temp; and last = temp; i'm not sure i understand why?
Lets say you have a list of three nodes, it will look something like
+--------+ +--------+ +--------+
| node 1 | --> | node 2 | --> | node 3 |
+--------+ +--------+ +--------+
The "arrows" is the next pointer.
Now with this list, head should point at "node 1" while last should point at "node 3".
What the two lines you are wondering about does, is make the last nodes next pointer point to the new node, and then make last point to the new node, thereby adding the new node last in the list.
So with the list above, and adding one node, then it will lokk like
+--------+ +--------+ +--------+ +--------+
| node 1 | --> | node 2 | --> | node 3 | --> | node 4 |
+--------+ +--------+ +--------+ +--------+
And last has been updated to now point at "node 4".
Why does both head and last equals temp;? Then both the head, and last will be the same element/value?
Because in this list you only have one element, so this element is the first and the last at the same time.
but then last->next = temp; and last = temp; i'm not sure i understand why?
last->next = temp is actually linking the last element of the list to the one that you just created, which is going to be the next in your list. And, since this is the new last element, you must update the value of last by doing last = temp.