Please can you explain to me how this function deletes the last node in a single linked list
void deleend()
{
Node *q;
Node *p;
for (q = head; q != NULL; q = q->next)
{
p=q;
p->next=NULL;
}
delete q;
}
The deletion of the last item of a list is a pretty simple algorithm.
You need to loop throught the whole list until you reach a node with the next pointer equals to NULL. This is your last element, the element you want to delete.
So you need to free the memory allocated by this object and set the next pointer for your previous item to NULL. This is the most important thing since it avoids to get segfaults.
Now, about the code you posted, I see you are doing something pretty bad.. you're declaring *q and *p, then looping throught your list (pointed by a global Node* head, I suppose).
The issue is that with the code in your loop you're unlinking the first item from the linked list and then the loop ends because You're copying the pointer q in p and then setting it's next pointer tu Null which leads to setting q->next to NULL. The first iterations goes ""fine"" leading you to have the first element with next set to Null the second iteration finds the next set to Null and thus it stops.
NOTE: Before posting the code solution I'd like to know if you have pretty clear in mind what the algorithm purpose is, try make an attempt to fix your code, if you can't do it again I'll post the correct algorithm :)
Related
The problem statement is the following:
Given a singly linked list, write a function to swap elements pairwise. For example, if the linked list is 1->2->3->4->5->6->7 then the function should change it to 2->1->4->3->6->5->7, and if the linked list is 1->2->3->4->5->6 then the function should change it to 2->1->4->3->6->5
Here is my solution:
void swapPairs(Node* head) {
if (!head->next || !head)return head;
Node* current = head->next;
Node*prev = head;
while (true) {
Node* next = current->next;
current->next = prev;
if (!next || !next->next) {
prev->next = next;
break;
}
prev->next = next->next;
prev = next;
current = prev->next;
}
}
The issue with the solution is that when it gets to the end of the function, the head no longer points to the beginning of the list since both current and prev have been moved. I've seen other solutions online which do the same thing as I'm doing here, but maybe since they are implemented in C instead of C++, there is some aspect of their code that allows for the head to remain pointing to the start of the list.
I realize that this is probably a really simple issue to solve, but I'm just not currently seeing the solution. What would be the best way to maintain the beginning of the list throughout the algorithm?
The task at hand will be much simpler once you undergo a slight paradigm shift. This might seem more complicated at first, but after pondering it a bit, its simplicity should be obvious.
Simply said: instead of carrying a pointer around -- to the first of each pair of list elements -- as you walk through the list, carry a pointer to the pointer to the first of each pair of list elements. This sounds complicated, on its face value; but once the dust settles, this simplifies the task at hand greatly.
You must have a head pointer stored separately, and you're passing it to swapPairs():
Node *head;
// The list gets populated here, then ...
swapPairs(head);
That's what you're doing now. But rather than doing this, pass a pointer to the head node, instead:
swapPairs(&head);
// ...
void swapPairs(Node **ptr)
{
while ( (*ptr) && (*ptr)->next)
{
// swap the next two elements in the list
// ...
// Now, advance by two elements, after swapping them.
ptr= &(*ptr)->next->next;
}
}
The body of the while loop is going to swap the next two elements in the list, and let's skip over that part for now, and just focus on this bit of logic that iterates through this linked list, a pair of elements at a time. What's going on here?
Well, you are trying to walk through the list, two elements at a time.
Remember, ptr is no longer the pointer to the first element of the pair. It's a pointer to wherever the pointer to the first element of the pair happens to live. So the initial ptr is pointing to your original head pointer.
Once you understand that, the next mental leap is to understand that you want to cycle through your iteration as long as there are at least two elements left in the list:
while ( (*ptr) && (*ptr)->next)
*ptr is the next element to the list, the first of the pair, and (*ptr)->next would therefore be the pointer to the second in the pair. Because of how we're iterating, ptr can be proven, by contract to never be NULL. So, if *ptr is NULL, you reached the end of the list. But if *ptr is not NULL, there's at least one element left, and (*ptr)->next is the "next 2nd element". If (*ptr)->next is NULL, the original list had an odd number of elements in it, so on the last iteration you ended up with *ptr pointing to the odd duck. And you're done in that case too, no need to go any further.
Finally:
ptr= &(*ptr)->next->next;
This simply advances ptr by two elements of the list. Remember, ptr is a pointer to wherever the pointer to the first of the next two elements in the list "happens to live", and this now sets ptr to point the where the pointer to the first of the ***next**** two elements in the list happens to live. Take a piece of paper, draw some diagrams, and figure this out yourself. Do not pass "Go", do not collect $200, until this sinks in.
Once you wrapped your brain around that, the only thing that's left is to swap the pairs. That's it. The body of the loop can simply be:
Node *first=*ptr;
Node *second=first->next;
Node *next=second->next;
*ptr=second;
second->next=first;
first->next=next;
That's it. You're done. And, guess what? Your original head is now automatically pointing to the right head node of the swapped list.
Now, wasn't that easy?
Change the signature of the function to
Node* swapPairs(Node* head)
and save the new head after the first swap, then at the end after your while loop's closing }, return that new head, to replace the old list head held by the caller, which would use this something like:
list = swapPairs(list);
You can keep a pointer to the new head at the beginning of the function and update the head at the end of the function with that. Note that I changed the argument from Node* to Node ** because we want to update the pointer value so that when we update head, we write to the same memory location that passed to this function. As a result, the correct value of head will be available in the caller of this function when we return from it.
void swapPairs(Node **head) {
if (!(*head)->next || !(*head))
return;
Node *new_head = (*head)->next; // the new_head
Node *current = (*head)->next;
Node *prev = (*head);
while (true) {
Node *next = current->next;
current->next = prev;
if (!next || !next->next) {
prev->next = next;
break;
}
prev->next = next->next;
prev = next;
current = prev->next;
}
*head = new_head; // now update the head
}
I don't understand how this code can delete node, please help!!!
Node* del_place(Node* L, int S)
{
int i=1;
Node *p=L;
while (p!=NULL&&i!=S-1)
{
p=p->next;
i++;
}
p->next=p->next->next;//why can this code delete node in L...
return L;
}
Let's take a look at what the function does. It takes two arguments, the linked list, and the index of the item to be removed.
First, it searches the right node:
p is the first item of the linked list. It starts stepping through the list, untill either, the right index is found (i=S-1) or untill the end of the list is reached (p=NULL).
when it has found the right node, it sets the link to the next item: p-> next, to the next item of the next item.
And now, you can also see the problems in the function:
When an item is removed, the item itself is still in the list, there
is just no more pointer to it, this is a memory leak like molbdnilo said.
When the end of the list is reached (p=NULL), you try to set p->next to NULL, this will cause the program to throw a nullpointerexception.
If p itself is the last item in the list, p->Next will be null, and since you try to call 'Next' on this item, you will also get a nullpointerexception.
The line does not actually delete the Node from the memory. It removes it from the linked list.
The code makes your current Node (p) points to the second Node on the right instead of the first on the right.
Several issues with this code:
Potential memory leak since the Node is not deleted from the memory
you need to do some check before p->next=p->next->next; or you might have some undefined behaviour when p or p->next end up being NULL. e.g. L is NULL, S > size of the linked list...
I implemented my linkedList function which inserts at the end, but I used the brute force method going through until the end and then adding it. I would like to change it to O(1). If you guys have any tips that would be great.
The only way to make this O(1) is to maintain a reference to the last Object in your List object. Whenever a new object is inserted at the end of the List, the pointer is updated to point to it.
Your actual problem has already been answered: Store an additional tail pointer at which you can insert without looping over the entire list.
But also take a look at your code:
for (node; node->getNext() != NULL && node->getNext()->getElement() != data;)
node= node->getNext();
node->setNext(insertNode);
The second condition in the for loop looks kind of weird to me. In case you would want to append a new element with element == data, your loop would stop at any existing element with that value and you would attach your newly allocated element just before it ... and lose all old elements starting with the existing node with element == data. Looks like a bug go me.
As other people have said, you need to add a tail node to your list, and then you can use this implementation for insertAtEnd():
template <class Object>
void List<Object>::insertAtEnd(const Object& o)
{
ListNode<Object>* insertNode = new ListNode<Object>(o, nullptr);
if (!head) head = insertNode;
if (tail) tail->setNext(insertNode);
tail = insertNode;
}
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.
Dont understand what the expression in the while statement means below. Please someone explain
while(trans->link){
trans = trans->link;
}
This is a simple linked-list traversal to find the last element of the list. That is, while trans->link is non-zero (i.e., not NULL - past the end of the list), it will move one step farther down the list: trans = trans->link.
-> is the class member accessor for a pointer. Presumably trans is a pointer and trans->link is a pointer of the same type. The above code says "while trans->link is not zero, assign trans to be trans->link, ultimately moving to the end of a linked list.
Let's suppose you have a structure:
struct Element
{
int value;
Element *next;
};
Linked list consists of nodes that are type Element , and it has a pointer to the head of linked list(first node). The next pointer of the last element of a list points to nullptr(if not familiar with linked lists read More Info).
If you wish to traverse the whole list you need to have a Element *temp pointer that will point to the head (because we don't want to lose our head of the list). And then, after visiting one node, we have to move temp to the next element of the node we are currently pointing to(temp=temp->next).
We will stop the traversal until temp reaches nullptr. That's when the while loop will break.
In your case
link=next
trans=temp
Hope it helps.