For starters this is apart of my current homework assignment for my Data Structures class. I am not asking for answers, I am asking for help.
I have a stack class that is implementing a Linked List instead of an array. I am currently trying to write my pop() function. I have a node for my theBack part of the stack.
I am just confused as to getting to the predecesor of my theBack node.
Any help with this would be awesome! Thanks!
A stack is actually reasonably simple to implement as a singly linked list, due to its restricted push and pop operations. It's actually a lot easier if you insert pushed elements at the head of the list. Since it's homework, I'll provide pseudo-code.
To initialise a stack, it's simply creating:
top -> null
with this code:
def init (stk):
stk->top = null # just initialise to empty.
Pushing an item is actually inserting it at the start of the list. So, when you push 3, 4 and 5, you get:
+---+
top -> | 3 | -> null
+---+
+---+ +---+
top -> | 4 | -> | 3 | -> null
+---+ +---+
+---+ +---+ +---+
top -> | 5 | -> | 4 | -> | 3 | -> null
+---+ +---+ +---+
with the following code:
def push (stk, val):
item = new node # Create the node.
item->value = val # Insert value.
item->next = stk->top # Point it at current top.
stk->top = item # Change top pointer to point to it.
And popping is then just removing that first node.
def pop (stk):
if stk->top == null: # Catch stack empty error.
abort with "stack empty"
first = stk->top # Save it for freeing.
val = first->value # Get the value from the top.
stk->top = first->next # Set top to the top's next.
free first # Release the memory.
return val # Return the value.
Each node in the singly-linked list links to the previous node. The very first item pushed onto the stack has a NULL, all the others point to the item 'below' them (the predecessor) in the stack.
So before you destroy the top node, you grab the backlink and save it as the new top. Something like this pseudocode, which presumes a stack of int values:
pop()
ALink *poppedLink = myTop;
myTop = poppedLink.nextNode; // point to next node
int returnValue = poppedLink.value; // save the value
delete poppedLink; // destroy the instance
return returnValue;
If by "predecessor", you mean: "the thing that was popped before this": that's long gone, isn't it?
if you're implementing a stack, then you would want to pop the top node anyways, so you would set theTop to be the next node in line (which should be a pointer in theTop node)
What do you mean the "predecessor" of top? Top node is the head of your list, it doesn't have any predecessors.
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;
}
}
How would I write a pop() method for LinkedStack in O(1)?
I have two private data members in my LinkedStack class: ListNode* head and ListNode* tail.
head points to the beginning of the LinkedStack, and tail points to the end of the LinkedStack.
pop() will remove the ListNode being pointed to by tail, then tail will point to the ListNode that was before tail.
Knowing this, how would I write pop() in O(1)? Obviously, I can write a for loop that grabs the previous ListNode right before tail, but then pop() wouldn't be O(1).
Since this is for homework, I'm not looking for code solutions, just maybe a hint in the right direction.
Edit: One solution I possibly see is having a ListNode* prev data member, which always points to the previous ListNode before tail. But I feel like there's a more efficient way....
Edit2: Thanks #user4581301. Assume that pop() will not be called when LinkedStack is empty.
As you state, any situation where you have to traverse the list to locate a specific element is going to make the constant time requirement impossible to meet. This includes a singly-linked list where you're pushing items on to the end. A doubly-linked list will be easier since you can then get from the tail to the penultimate item without traversal.
However, I'm not sure why you're pushing on to the end. If you were to push new elements on the the front of the list, achieving constant time for both push and pop is trivial.
By that, I mean (pseudo-code since, as you mention, "this is for homework"):
def push(x):
allocate node # get new node and set data.
node.data = x
node.next = head # insert at head of list
head = node
def pop():
assert head != null # catch pop on empty stack
node = head # get first node and data
retval = node.data
head = head.next # set head to be second node
free node # free node and return data
return retval
You can see that there is no traversal of the list for either operation. First, pushing 7 on to a stack of primes:
Starting list:
head
\
5 -> 3 -> 2 -|
Create new node, point to current head:
head
\
7 -> 5 -> 3 -> 2 -|
Point head at new node:
head
\
7 -> 5 -> 3 -> 2 -|
Now let's pop that same value.
Starting list:
head
\
7 -> 5 -> 3 -> 2 -|
Save head as node, and value to return (7):
head
\
7 -> 5 -> 3 -> 2 -|
/
node
Adjust head:
head
\
7 -> 5 -> 3 -> 2 -|
/
node
Free node and return stored value (7):
head
\
5 -> 3 -> 2 -|
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
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.