Linked List : What exactly sth.next refers to? - singly-linked-list

I recently watch a series of LinkedList video on youtube, as you may see in the below picture:
enter image description here
The video URL: https://www.youtube.com/watch?v=2RwWsHePdr8&index=11&list=PL6Zs6LgrJj3tWQfE6HK4JaX3wN96yhkD3
No I want to delete the number 15 (position 3), so here is the code:
if(position ==1) {
ListNode temp = head;
head = head.next;
temp.next = null;
return temp;
}else {
ListNode previous = head;
int count =1;
while(count < position -1) {
previous = previous.next;
count++;
}
ListNode current = previous.next;
previous.next = current.next;
current.next = null;
return current;
}
I have one question really confusing me : In the picture: |10|_|--> | 8 | __ |
if I type:『head.next』, does it means 8 ? or it means the node space next to 10?
Because in the code I revealed, I can't understand that: "why the last code is 『current.next = null; 』?"
I think 『current.next』 points to number 11 ??
If 『current.next』means the node next to 15, should the previous code『previous.next = current.next』be change to『previous.next = current.next.next』? Which means 『current.next.next』can refer to number 11
Thanks in advance!!
Update: Is the head.next and head.next.next means like this ?
enter image description here

Word next points to next node, which consists of address (memory address in system) and of value (for example 15)
If you know that you need to delete node with value 15, you can iterate through array and bind pointer of this nodes "next" to node, that 15 is showing on
ListNode temp = head;
while (temp.next != null){
if (temp.next.value == 15):
ListNode nodeWithValue15 = temp.next;
temp.next = nodeWithValue15.next;
// after rebinding address to your previous node, you can delete node with value 15
nodeWithValue15 = null;
temp = temp.next;
Here you can see what next.next does

Related

how can I reverse my Linked list . I wrote following code but this is giving only first node's data as output

Node *reverse(Node *head)
{
Node *answer = NULL, *p = head, *address = NULL;
while (p != NULL)
{
address = p;
address->next = answer;
answer = address;
p = p->next;
}
return answer;
}
In order to reverse a singly linked list, you need to keep one node in memory to be able to relink backwards.
It could look like this:
Node* reverse(Node* head) {
if(head) { // must have at least one node
Node* curr = head->next; // head + 1
head->next = nullptr; // this will be the new last node
Node* next; // for saving next while relinking
while(curr) { // while curr != nullptr
next = curr->next; // save the next pointer
curr->next = head; // relink backwards
head = curr; // move head forward
curr = next; // move curr forward
}
// head now points at the new start of the list automatically
}
return head;
}
Demo
I wrote following code but this is giving only first node's data as output
Because, in reverse() function, you are breaking the link of first node from rest of the list and returning it.
Look at this part of code:
address = p;
address->next = answer;
answer = address;
p = p->next;
In first iteration of while loop this is what happening:
Pointer address will point to head of list (as p is initialised with head) and, in the next statement, you are doing address->next = answer (note that answer is initialised with NULL). So, address->next is assigned NULL. Both, pointer p and pointer address are still pointing same node. After this, you are doing p = p->next, this will assign NULL to p because p->next is NULL. As, p is NULL, the while loop condition results in false and loop exits and function end up returning the first node.
You should assign p to its next before assigning answer to address->next, like this:
while (p != NULL)
{
address = p;
p = p->next; // moved up
address->next = answer;
answer = address;
}
Suggestion:
In C++, you should use nullptr instead of NULL.
Reversing a linked list, in essence, is pretty much flipping the arrows:
Original: A->B->C->D->null
Intermediate: null<-A<-B<-C<-D
Reversed: D->C->B->A->null
void reverseList(void)
{
Node *prev = nullptr;
Node *curr = head;
while (curr)
{
Node *nxt = curr->next;
curr->next = prev;
prev = curr;
curr = nxt;
}
head = prev;
}
The crux of the solution will be to use the previous and current node strategy to loop through the list. On lines two and line 3, I set the prev to null and curr to the head respectively. Next, I set the while loop, which will run until curr is equal to null or has reached the end of the list. In the 3rd and 4th lines of the body of the while loop, I set prev to curr and curr to nxt to help me move through the list and keep the traversal going while keeping track of the previous and current nodes.
I am storing the next of the current node in a temporary node nxt since it gets modified later.
Now, curr->next = prev is the statement that does some work. Flipping of the arrows takes place through this statement. Instead of pointing to the next node, we point the next of the current node to the previous node.
Now, we need to take care of the head node only. On the last line, head=prev, prev is the last node in the list. We set the head equal to that prev node in the list, which completes our code to reverse a list.
Suppose you have any trouble visualizing the algorithm. In that case, you even have the privilege to print the data stored in the current and previous nodes after each line in the while loop for a better understanding.
Hope this helps getting the gist of how we reverse a linked list.

What is the issue with this C++ simple linked list implementation?

This is a fairly simply project and I've spent probably about 20 hours on it traveling in a circle with no progress at all. I seemed to be heading in the right direction at the beginning but I had a TA try to explain it to me and it warped my brain putting me back at square one.
I know it's most likely a simple error so I will post code as well as my explanation. NOTE: Assert function is not an issue
IN H FILE
struct Node {
int num;
Node *next;
};
CPP File
void Intset::insert(int key)
{
Node * current;
current->num = key;
current->next = NULL;
assert (!find(key));
if(head == NULL)
{
head = current;
}
else if(head->num >= key)
{
head->next = head;
head = current;
}
else if(head->num < key)
{
head->next = current;
}
So my thought process behind this function (insert key into a sorted linked list) is to create a new node current and fill its num field with the user entered key and have its next field equal to NULL. My first check is to see if head is empty and if it is copy the contents of current to it. My second check is to see if head's num field contains a number greater than or equal to the user entered key.
If so I move the head node to the next node and replace it with the current node (smaller number in front). My third check sees if the number in head is less than the user entered key and if so it fills head's next field with current (smaller number goes first). So far I've run into seg fault errors and I'm not sure what I am allocating incorrectly.
Start here:
Node * current;
current->num = key;
current->next = NULL;
Where does current point? You are dereferencing an un-initialized pointer. This is undefined behavior which could very well result in a seg fault.

swapping 2 nodes in a linked list c++

I'm trying to swap 2 adjacent nodes in a linked list (75 and 9 in this case), and every time I run the code, say with a linked list of 75->9->767->2..., I get the whole list just turning to 75->9->75->9->75->9, etc.. I have to update pointers
Your problem is with the lines
nextPtr->next = tempPtr;
nextPtr = tempPtr;
I'm not sure, but i think you only mean to type
nextPtr = tempPtr;
instead.
I guess you are looking for pairwise swap, use this for the same. Let me know if it went fine.
for 75->9->767->2 it produces 9->75->2->762... If you want something different but similar, you can use it and make changes accordingly.
void swap(struct node **head)
{
if (*head == NULL || (*head)->next == NULL)
return;
struct node *prev = *head;
struct node *cur = (*head)->next;
*head = cur;
while (true)
{
struct node *next = cur->next;
cur->next = prev;
if (next == NULL || next->next == NULL)
{
prev->next = next;
break;
}
prev->next = next->next;
prev = next;
cur = prev->next;
}
}
Hint: If you want to swap nodes H (what you're calling hdList) and N (nextPtr) in a linked list you have to make whatever points to H now point to N. You're not keeping track of whatever points to H at all.
That is, suppose you know that part of your list is
... P -> H -> N -> Q ...
and you want to swap H and N. The state of the list after the swap should be
... P -> N -> H -> Q ...
right? But you can't do this because you don't know what used to point to H (i.e. P) so you can make it point to N.
I think you're going to have to go back to the drawing board on this one.
If you want to swap 2 nodes in linked list, why are you trying to swap the pointers and all? Just swap the data in it with the simple swap logic. let the pointers be as it is. If this is not what you want, tell me in detail what exactly you want it to be.

Deleting every other node of a linked list

I searched previous asked questions but could not find exactly what I was looking for. I was curious if anyone had any idea on how to delete every other node of a linked list. I have a function called duplicate which take 1 2 3 and turns it into 1 1 2 2 3 3. Deleting every other node would work just fine, no need to compare them or anything. If anyone has any insights. Please don't just post source code.
Heres what I was trying to do but wasn't working.
Node *current;
Node *undo;
for (current = front, undo = current->next->next;
undo != NULL; current = current->next, undo = current->next->next){
current->next = undo;
}
This will output 1 1 2 2 3 3 3
Thank you for any help. I can comment back later to clarify any misconceptions.
Original code:
for (current = front, undo = current->next->next;
undo != NULL;
current = current->next, // this moves current on before you use it's next pointer
undo = current->next->next){
current->next = undo;
}
To fix, without deallocating the unwanted nodes (assumes an even number of nodes):
for (current = front; current != NULL; current = current->next){
current->next = current->next->next
}
To handle odd length lists, and delete memory of removed nodes:
for (current = front; current && current->next ; current = current->next){
undo = current->next;
current->next = current->next->next
delete undo;
}
I would use std::list (or perhaps std::forward_list if so needed) and std::copy_if or std::remove_if in C++11.
Otherwise, remember the address of the pointer to be modified, something like:
Node**undoad = &front;
int cnt=0;
for (current=front; current != NULL; current=current->next) {
if (cnt%2 == 1) {
Node*undo = *undoad;
undoad = &current->next;
if (undo) undo->next = current->next;
}
cnt++;
}
However, the above probably is a memory leak: you may need to use delete somewhere.

What is the pointer-to-pointer technique for the simpler traversal of linked lists? [duplicate]

This question already has answers here:
An interesting C linked list idiom
(11 answers)
Closed 5 years ago.
Ten years ago, I was shown a technique for traversing a linked list: instead of using a single pointer, you used a double pointer (pointer-to-pointer).
The technique yielded smaller, more elegant code by eliminating the need to check for certain boundary/edge cases.
Does anyone know what this technique actually is?
I think you mean double pointer as in "pointer to a pointer" which is very efficient for inserting at the end of a singly linked list or a tree structure. The idea is that you don't need a special case or a "trailing pointer" to follow your traversal pointer once you find the end (a NULL pointer). Since you can just dereference your pointer to a pointer (it points to the last node's next pointer!) to insert. Something like this:
T **p = &list_start;
while (*p) {
p = &(*p)->next;
}
*p = new T;
instead of something like this:
T *p = list_start;
if (p == NULL) {
list_start = new T;
} else {
while (p->next) {
p = p->next;
}
p->next = new T;
}
NOTE: It is also useful for making efficient removal code for a singly linked list. At any point doing *p = (*p)->next will remove the node you are "looking at" (of course you still need to clean up the node's storage).
By "double-pointer", I think you mean "pointer-to-pointer". This is useful because it allows you to eliminate special cases for either the head or tail pointers. For example, given this list:
struct node {
struct node *next;
int key;
/* ... */
};
struct node *head;
If you want to search for a node and remove it from the list, the single-pointer method would look like:
if (head->key == search_key)
{
removed = head;
head = head->next;
}
else
{
struct node *cur;
for (cur = head; cur->next != NULL; cur = cur->next)
{
if (cur->next->key == search_key)
{
removed = cur->next;
cur->next = cur->next->next;
break;
}
}
}
Whereas the pointer-to-pointer method is much simpler:
struct node **cur;
for (cur = &head; *cur != NULL; cur = &(*cur)->next)
{
if ((*cur)->key == search_key)
{
removed = *cur;
*cur = (*cur)->next;
break;
}
}
I think you mean doubly-linked lists where a node is something like:
struct Node {
(..) data // The data being stored in the node, it can be of any data type
Node *next; // A pointer to the next node; null for last node
Node *prev; // A pointer to the previous node; null for first node
}
I agree with the comments about using the STL containers for handling your list dirty work. However, this being Stack Overflow, we're all here to learn something.
Here's how you would normally insert into a list:
typedef struct _Node {
void * data;
Node * next;
} Node;
Node * insert( Node * root, void * data ) {
Node * list = root;
Node * listSave = root;
while ( list != null ) {
if ( data < list->data ) {
break;
}
listSave = list;
list = list->next;
}
Node * newNode = (Node*)malloc( sizeof(Node) );
newNode->data = data;
/* Insert at the beginning of the list */
if ( listSave == list ) {
newNode->next = list;
list = newNode;
}
/* Insert at the end of the list */
else if ( list == null ) {
listSave->next = newNode;
newNode->next = null;
list = root;
}
/* Insert at the middle of the list */
else {
listSave->next = newNode;
newNode->next = list;
list = root;
}
return list;
}
Notice all the extra checking you have to do depending on whether the insertion occurs at the beginning, end or middle of the list. Contrast this with the double pointer method:
void insert( Node ** proot, void * data ) {
Node ** plist = proot;
while ( *plist != null ) {
if ( data < (*plist)->data ) {
break;
}
plist = &(*plist)->next;
}
Node * newNode = (Node *)malloc( sizeof(Node) );
newNode->data = data;
newNode->next = *plist;
*plist = newNode;
}
As Evan Teran indicated, this works well for singly linked lists, but when it's doubly linked, you end up going through just as many if not more manipulations as the single pointer case. The other draw back is that you're going through two pointer dereferences for each traversal. While the code looks cleaner, it probably doesn't run as quickly as the single pointer code.
You probably mean a doubly-linked list, with one of the pointers going forward and the other going backward. This allows you to get to the next and previous nodes for a given node without having to remember the last one or two nodes encountered (as in a singly-linked list).
But the one thing I discovered which made the code even more elegant was to always have two dummy elements in the list at all times, the first and the last. This gets rid of the edge cases for insertion and deletion since you're always acting on a node in the middle of the list.
For example, an empty list is created:
first = new node
last = new node
first.next = last
first.prev = null
last.next = null
last.prev = first
// null <- first <-> last -> null
Obviously, traversing the list is slightly modified (forward version shown only):
curr = first.next
while curr <> last:
do something with curr
curr = curr.next
The insertions are much simpler since you don't have to concern yourself with whether you're inserting at the start or end of the list. To insert before the current point:
if curr = first:
raise error
add = new node
add.next = curr
add.prev = curr.prev
curr.prev.next = add
curr.prev = add
Deletions are also simpler, avoiding the edge cases:
if curr = first or curr = last:
raise error
curr.prev.next = curr.next
curr.next.prev = curr.prev
delete curr
All very much cleaner code and at the cost of only having to maintain two extra nodes per list, not a great burden in today's huge memory space environments.
Caveat 1: If you're doing embedded programming where space still might matter, this may not be a viable solution (though some embedded environments are also pretty grunty these days).
Caveat 2: If you're using a language that already provides linked list capabilities, it's probably better to do that rather than roll your own (other than for very specific circumstances).