I've been trying to figure out how to create link based stack and came across a snippet of code that I don't quite understand.
int pop()
{
// If the stack is empty return a sentinel value
if (isEmpty())
return -999;
// Get the data to return from the top of the stack
int intReturn = top->info;
// Create a pointer to keep track of the top node
IntSLLNode *temp;
temp = top;
// Move the top of the stack to the next element
// or null if there is no next element
top = top->next;
// Free up memory
delete temp;
// Send back the data
return intReturn;
...
}
I understand up until top=top->next.
1) What was the point of creating a temp node if we never really use it?
2) By moving the top pointer to the next node, are we deleting the former top node? Thus popping it?
Thanks
1) temp is needed because we will need the old value of top after top is moved in order to free the memory of the node being popped. We have to move top then free the memory; if we try to do it the other way around (free memory, then move top) then we would have to use a temporary variable to hold top->next (as that would have been lost in this scenario). In either case, you can't avoid a temporary variable.
2) Moving top results in promoting the second node to the top node, and removing the top node from the stack (which is half of what we expect from pop - the other half being returning the value of the popped node). The node is not deleted until delete temp, which is why we needed to preserve it.
Related
Considering that this is my function:
void addtoSameList(const List &another){
for (Node *temp = new Node(*head); temp != nullptr; temp = temp -> next){
Node *ptr = other.head;
Node *temp2 = new Node;
temp2->value = temp->value;
while (ptr -> next != nullptr) {
ptr = ptr -> next;
}
ptr->next = temp2;
temp2->next = nullptr;
}
return;
}
where my goal is to append a linkedlist to itself, I do not know exactly what goes wrong.
If, for example, I have a linkedlist called n in the main function, where I then declare:
n.addtoSameList(n);
meaning that &other is going to be pointing at the same node as n, I figured that I would make a new node and deep copy the contents of n.
However, my two outputs are either that I end up in an infinite loop, or that some node ends up getting skipped.
How do I fix this issue?
This code has numerous issues. First, the interface doesn't suggest that the only use is to append a linked list to itself. Nor does it suggest that a deep copy is necessary in any other case.
So, lets adjust the requirements...
You want a member function that will append a copy of a linked list to the existing one. Then the case of self-appending naturally falls out of the problem description.
The approach here would be to step through the linked list that is passed in, carefully copying each node, then re-adjusting the pointers on the main linked list to point at your new node and the pointer in the new node to be set to appear to be the end of the list. This maintains a list invariant as the list is stepped through.
There is a pitfall here though. If you are self appending, you risk creating an infinite loop. So you should find the end node of the passed in list before you start this process and consistently use it to find out if you've gotten to the end of the list. If you maintain a tail pointer, this is trivial. If you don't, it means a list traversal.
Another way would be to simply create a copy first, carefully maintaining the pointer to the first node of the copy. Then just adjust the tail node's next pointer to point at the new list, and then adjust the tail node (if you maintain that pointer in the LinkedList data structure) to point at the tail node of the copy. And that's probably the way you should go. It's cleaner and more efficient. The main drawback is cleanup when doing exception handling. But, at your level, you shouldn't be concerned with that right now.
Here's an alternate approach. Create three pointers: ptrBegin, ptrEnd and ptrNew. ptrBegin points to the beginning of the linked list and traverse the linked list so that ptrEnd and ptrNew point to the last element of the linked list. Then increment ptrBegin until ptrBegin != ptrEnd at the same time copying the data at ptrBegin to a new node at ptrNew->next and increment ptrNew.
I feel really silly asking this, as it seems really simple, but I just can't figure it out. All I want to do is set the node pointer to the next node in the list. The function is from a teacher, I wrote the body, so I don't want to mess with the head of the function.
void LList::insert(int num, int at)
{
node* n = new node(num);
if (!n) throw runtime_error("Can't allocate node!");
if(!root || at == 0){
// if empty list - new node is root…
if (!root) root = n;
}
if(root){
node* nextNode = new node(num);
int numF = 0;
for (node* t = root; t != NULL ; t = t->next){
numF++;
if(numF == at){
n->next=t->next;
t->next=n;
}
}
}
}
Since it seems you are using n for the new node to be inserted into the linked list (I'm inferring that it's a singly linked list from the existing code and class name), there are a few things you have to do off the top of my head:
Identify the existing member of the list after which the new node will be inserted. You are making an attempt to do this already with that for loop, but in my opinion you may want to rewrite that as a while loop since you probably don't want it to keep iterating after the insertion position has been identified. Alternately, you could short-circuit out of the for loop with a break once you've found the right place for insertion, but I don't like that for stylistic reasons. :)
Set the newly inserted node's next pointer to the same location to which the next pointer of the node identified in #1.
Set the next pointer of the node identified in #1 to point at the new node, thus re-establishing the integrity of the chain.
Your code looks like it is attempting to do #2 and #3 out of order, which won't work. You're obliterating the value of t->next before you've had a chance to point n->next at it.
Finally, you may need to define some behavior to which you can fall back in case you are adding to a position not already defined in the list (i.e. inserting into the fourth position of a linked list that currently has three elements). You may need to re-jigger your loop to terminate when t->next is null rather than when t itself is null - otherwise you lose the hook to be able to connect the (currently) last element of the list to your new node.
It is difficult to understand how this node is being created, Can you please write step-wise what this set of code is actually doing, and what actions they represent?
void list::create_node(int value)
{
struct node *temp;// Please write in words the meaning of this statement
temp = new(struct node);// is this a dynamic node? )
temp->info = value;// is this value being assigned to this node?
if (last == NULL)// what is this set of code testing??
{
last = temp;// who is this last; the node which has been created?
temp->next = last; // is the node pointing to itself being only one node?
}
else
{
temp->next = last->next;((( // What is this statement saying?
last->next = temp;// What is this statement saying?
last = temp;// What is this statement saying?
}
}
void list::create_node(int value)
{
The above line declares a function that creates a node with the given value and inserts the node into the list. The code must be examined to see where the new node is inserted.
struct node *temp;
Declares a pointer to a node. The memory has not been allocated yet, only a pointer that will be used later.
temp = new(struct node);
Allocates memory for a node from the dynamic (runtime) memory area (a.k.a. heap). Calls the constructor of the node structure to initialize the memory, if a constructor exists.
The pointer temp is now pointing to the node object.
temp->info = value;
This assigns the value to the data field, info. Need the declaration of struct node in order to confirm this guess.
if (last == NULL)
{
Assuming that last is a pointer and points to the last node, this check is looking for an empty list. Common implementation is to have pointer values set to null to mark the end of the list.
last = temp;
temp->next = last;
}
The above code inserts the new node as the last node. The last pointer allows fast access to the end of the list. This allows for reverse iteration without having to traverse all the links to find the last node.
Some implementations set the next field to null to indicate the end of the list, others like this one, make it point to the last node.
else
{
temp->next = last->next;
At this point, the list is not empty.
The new node is made to point to the same node that the last node points to.
This is best understood by drawing the node boxes and arrows pointing to the nodes.
last->next = temp;
Updating the last node to point to itself. See the above section.
last = temp;
Updating the pointer to the last (end of list) node to point to the new node.
}
}
I suggest you draw the linked list and walk through this algorithm a couple of times to see how it works. Also review the singly linked list data type.
The circular reference of the last node may be confusing to you. This may not be the standard implementation that most books describe, but it is valid.
struct node
{
char *ptr = (char *)malloc(frames*sizeof(char));
}*start,*current;
Then I have allocated memory equal to node to start.
[...]//Assigned values to start node.
current = start;//Current points to start
node *temp = new node();//temp will point a newly created node
*temp = *current;// COPYING VALUES OF CURRENT TO TEMP
[...]
I want to create a new node, make temp point to it and copy values of current (here current is pointing to start) to temp.
BUT this is making temp point current (here start) instead.
Frustrated. Where am I going wrong?
*temp = *current should be temp = current.
There could be two solutions
Change *temp=*current to temp=current. Doing this, you can access values of "current" using "temp" as these two pointers are now referring to the same memory location. Caution, changing value by using "current" or "temp" will cause to change in value in both pointers as they are referring to same memory location.
Use memcpy. It will copy values from one memory location to other. Here is the reference. Now you have two independent copies of values.
I'm trying to make a Stack using an underlying linked list structure.
Maybe I'm wrong, but I'm having trouble with the remove() function.
int Stack::remove(){
node* victim = new node;
int popped;
popped = top->element;
victim = top;
top = victim->next;
delete victim;
return popped;
}
I'm getting glibc dectecting
double free or corruption (out);
Since I'm allocating new memory with victim, don't I have to delete victim, or is that something I don't have to worry about?
A stack is much like a bunch of dishes that are being washed and set on top of one another. That is the first one in is the last one out (FILO data type). That is if your stack read in 2, 7, 8 then it would appear as :
8
7
2
That is first the 2 is placed in the stack, followed by the 7 and then by the 8. If you want to remove or pop the stack you need to move the head of the pointer. Your code looks a bit strange to me...
int Stack::remove()
{
int datum; //to store the popped value
node* temp=head; //assign pointer to head of list
datum = temp->data; //grab the data value stored at the head (or temp since they carry same reference)
head = temp->next; //move the head pointer (in our example now it points to 7)
delete temp;
return datum;
}
There's no reason to allocate heap memory in a remove() method as you are doing with victim. What you want is:
int Stack::remove(){
node* new_top = top->next;
int popped = top->element;
delete top;
top = new_top;
return popped;
}
You don't need to allocate a node for victim. Just assign the top of the stack to it and, if it's not null, set top to its next pointer, retrieve the value from victim, and then deallocate the victim.
It's not actually a corruption, but a memory leak - you are allocating a node, and then override that pointer with victim = top; thus losing track of just allocated memory.