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.
Related
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;
}
}
In this piece of code
Node* insert(int num, Node *head) {
if (head == NULL|| num <= head->next)
return addNewNode(num, head);
head->next = insert(num, head->next);
return head;
}
Why is it
head->next = insert(num,head->next);
and not
head = insert(num,head->next);
I understand we have to traverse through the singly linked list and I thought "head->next" inside the function call takes care of that.
When you don't insert the element as the first node, you want to keep the head and insert into the list's tail.
head->next = insert(num, head->next); replaces the tail with the modified one.
head = insert(num, head->next); would ignore the head and replace it with the result of inserting an element in its tail.
Example: say that we have
head
|
v
1 -> 3 -> X
and want to insert 2.
The recursive insertion returns a pointer to
2 -> 3 -> X
and pointing head->next at this gives
head
|
v
1 -> 2 -> 3 -> X
while your suggestion would give
head
|
v
1 -> 2 -> 3 -> X
and you've lost the 1.
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.
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;
I was studying Linked List and then I found a code for reversing the Linked List recursively. Here is the C++ code.
void recursiveReverse(node*& head)
{
node* first;
node* rest;
/* checking for an empty list */
if (head == NULL)
return;
first = head;
rest = first->next;
/* List has only one node */
if (rest == NULL)
return;
recursiveReverse(rest);
first->next->next = first;
first->next = NULL;
/* fix the head pointer */
head = rest;
}
I understood the whole code except the last line. Because according to me, the rest pointer is also updated similarly as the first pointer during unwinding of the recursion and therefore, at the end of this code, the head will not point to the last node.
Here's my interpretation of the following code.
Let's take a Linked List 1 -> 2 -> 3.
Initially, first will store the address of the head node and rest
will contain the address of the node 2.
Now, since rest is not NULL, therefore, recursiveReverse(rest) will be called.
Now, first will point to node 2 and rest will point to node 3.
Again, rest is not NULL, therefore, recursiveReverse(rest) will be called.
Now, first will point to node 3 and rest will contain NULL.
After that, the recursion will start unwinding and first will be back to node 2 and the rest will be back to node 3.
Now, the statement first -> next -> next = first; will cause the next part of node 3 to point to node 2 and the Linked List will become 1 -> 2 <- 3. The next part of node 2 will contain NULL and since head = rest, therefore, head will also point to last node as the rest pointer.
After that, first will point to node 1 and the statement first -> next -> next = first; will cause the next part of node 2 to point to node 1 and the Linked List will become 1 <- 2 <- 3. The next part of the node 1 will contain NULL and the statement head = rest will cause the head to point to node 2 and not the node 3 since, the rest (which is first -> next) is currently at node 2.
Can anyone please explain where I am wrong in interpreting this code?
Maybe there are other misinterpretations, but I assume that the basic one concerns your interpretation "the statement head = rest will cause the head to point to node 2 and not the node 3 since, the rest (which is first -> next) is currently at node 2".
At the end, head will point to the last node of the initial list. Let's consider a simplified/shortened portion of your code:
rest = head->next;
if (rest == NULL) // end of list reached; head points tho the last node
return;
recursiveReverse(rest); // if the end is not reached, go forward with the next node (i.e. the value of head->next
head = rest; // reset head to the (shared) value of rest.
This is because statement recursiveReverse(rest) will be called again and again until head->next will be NULL, i.e. the end of the list is reached. The very last run of recursiveReverse returns because head->next == NULL, and in the caller, variable rest points to the last node.
Now note that "rest" is shared among all the calls to recursiveReverse, as it is passed by reference. So statement head = rest will be called for every instance of recursiveReverse called so far, but - as rest is shared among all the calls and is not changed after the recursive calls - statement head = rest will assign the head always to the same value of rest, which remains the one pointing to the last node.
Puh - hope this is comprehensive.
Anyway, doing recursive functions with parameters passed by reference is usually hard to understand; Typically things become easier when recursive functions manage their private states but use the return value to coordinate the results. If you arrange the code such that you have node* reverseRecursive(node *current), your code will become easier to understand.
It looks like in step 8. you forgot that head in void recursiveReverse(node*& head) is a reference. So when you recursively call recursiveReverse(rest); then rest is passed by reference. That means that, when inside the recursion, head is a reference to the rest variable in the calling function. Therefore when it was changed to point to 3 inside the recursion then rest in the calling function was also changed.
If this sounds confusing then drawing up the local variables on the stack might help:
1) Initially, head will be a reference to the pointer to the node passed to the function, first will store the address of the head node and rest will contain the address of the node 2.
The stack will look like this (only showing local variables and ignoring whatever was already there when calling the function):
====================================
head: reference to original head
first: node 1
rest: node 2
2) Now, since rest is not NULL, recursiveReverse(rest) will be called.
3) Now, head will reference rest in the calling function, first will point to node 2 and rest will point to node 3.
The stack will look like this:
====================================
head: reference to original head
first: node 1
rest: node 2 <---------------+
==================================== |
head: reference to ---------------+
first: node 2
rest: node 3
4) Again, rest is not NULL, therefore recursiveReverse(rest) will be called.
5) Now, head will reference rest in the last calling function, first will point to node 3 and rest will contain NULL.
The stack will look like this:
====================================
head: reference to original head
first: node 1
rest: node 2 <---------------+
==================================== |
head: reference to ---------------+
first: node 2
rest: node 3 <---------------+
==================================== |
head: reference to ---------------+
first: node 3
rest: NULL
6) Since rest is NULL we just return and the stack is back to this:
====================================
head: reference to original head
first: node 1
rest: node 2 <---------------+
==================================== |
head: reference to ---------------+
first: node 2
rest: node 3
7) Now, the statement first->next->next = first; will cause the next part of node 3 to point to node 2 and the Linked List will become 1 -> 2 <- 3. The next part of node 2 will contain NULL. Since head is a reference to rest in the calling function then head = rest will make the rest referenced by head to point to the same node as the local rest:
====================================
head: reference to original head
first: node 1
rest: node 3 <---------------+ (head = rest; made *this* rest
==================================== | be equal to the *local* rest)
head: reference to ---------------+
first: node 2
rest: node 3
8) After that, we return and first will again point to node 1 and the statement first->next->next = first; will cause the next part of node 2 to point to node 1 and the Linked List will become 1 <- 2 <- 3. The next part of the node 1 will contain NULL and the statement head = rest will cause the pointer referenced by head to point to node 3 since rest was changed to point to node 3 in step 7.
We beginners should help each other.:)
In my opinion it is not easy to understand how the function works for such beginners as we.
So it is better to figure out its work using schemes.
If the list either does not contain nodes or contains only one node then there is nothing to reverse.
This code snippet corresponds to this conclusion.
/* checking for an empty list */
if (head == NULL)
return;
first = head;
rest = first->next;
/* List has only one node */
if (rest == NULL)
return;
Now let's assume that the list contains exactly two nodes. In this case it looks like
-------- ---------- ----------------
| head | -> | A |B| -> | B |nullptr|
-------- ---------- ----------------
This list is split into the following parts the following way
-------- ----------
| head | -> | A |B|
-------- ----------
-------- ----------
| first| -> | A |B|
-------- ----------
-------- ----------------
| rest | -> | B |nullptr|
-------- ----------------
This code snippet corresponds to this conclusion
first = head;
rest = first->next;
Now the function calls itself recursively
recursiveReverse(rest);
In fact it is called for this new list
-------- ----------------
| rest | -> | B |nullptr|
-------- ----------------
as this new list contains only one node then the function just returns.
As the original list must be reversed then the head must contain the value of rest that is the head must point to the node "B"
This code snippet corresponds to this conclusion
head = rest;
However in this case we will get
-------- ----------------
| head | -> | B |nullptr|
-------- ----------------
But this list contains only one node "B". So before executing this statement
head = rest;
we need to append the list with the node "A".
As we have that the pointer first points to the node "A"
-------- ----------
| first| -> | A |B|
-------- ----------
then we can do the following
first->next->next = first;
that results in
-------- ---------- -----------
| first | -> | A |B| -> | B | A|
-------- ---------- -----------
that is on the other hand we have
-------- ---------- -----------
| rest | -> | B |A| -> | A | B|
-------- ---------- -----------
and then after this statement
first->next = NULL;
we will get
-------- ---------------- | -----------
| first | -> | A |nullptr| | | B | A|-----------
-------- ---------------- | ----------- |
^ V
-------- | -----------------
| rest | ---------------------------- | A | nullptr|
-------- -----------------
Now it is indeed time to call the statement
head = rest;
and we will get
-------- ---------------- | -----------
| first | -> | A |nullptr| | | B | A|-----------
-------- ---------------- | ----------- |
^ V
-------- | -----------------
| head | ---------------------------- | A | nullptr|
-------- -----------------
That is the list is reversed.
If the list contains more than two nodes then after splitting the original list the pointer first will point to the first node of the original list that has to be the last node in the reversed list. In turn this first node will point to the next node that in the reversed list will be the last node.
Using this code snippet
first->next->next = first;
first->next = NULL;
we can place it after the last node in the reversed list. And all we need to do is to set the head to the value stored in the pointer rest because the pointer rest is the head of the reversed list to which the node pointed to by the pointer first is appended.
head = rest;
That is all.
Here is a demonstrative program
#include <iostream>
struct node
{
int value;
node *next;
};
void push( node * &head, int value )
{
head = new node { value, head };
}
std::ostream & out( node * const &head, std::ostream &os = std::cout )
{
for ( node *current = head; current != nullptr; current = current->next )
{
os << current->value << ' ';
}
return os;
}
void recursiveReverse( node * &head )
{
if ( head != nullptr && head->next != nullptr )
{
node *first = head;
node *rest = head->next;
recursiveReverse( rest );
first->next->next = first;
first->next = nullptr;
head = rest;
}
}
int main()
{
node *head = nullptr;
const int N = 10;
for ( int value = 0; value < N; value++ )
{
push( head, value );
}
out( head ) << std::endl;
recursiveReverse( head );
out( head ) << std::endl;
return 0;
}
Its output is
9 8 7 6 5 4 3 2 1 0
0 1 2 3 4 5 6 7 8 9