Pointers Chapter Practice Section: Wadsfsaaawaaadsss
Pointers Chapter Practice Section: Wadsfsaaawaaadsss
Pointers Chapter Practice Section: Wadsfsaaawaaadsss
Linked list is one of the most important data structures. We often face situations,
where the data is dynamic in nature and number of data can’t be predicted or the
number of data keeps changing during program execution. Linked lists are very
useful in this type of situations.
The implementation of a linked list in C++ is done using pointers. You can go
through the pointers chapter if you don’t have a strong grip over it. You can also
practice a good number of questions from practice section.
A linked list is made up of many nodes which are connected in nature. Every node
is mainly divided into two parts, one part holds the data and the other part is
connected to a different node. It is similar to the picture given below.
Here, each node contains a data member (the upper part of the picture) and link to
another node(lower part of the picture).
Notice that the last node doesn’t point to any other node and just stores NULL.
struct node
{
int data;
struct node *next;
};
The first data member of the structure (named node) is an integer to hold an integer
and the second data member is the pointer to a node (same structure). This means
that the second data member holds the address of the next node and in this way,
every node is connected as represented in the picture above.
So, if we have access to the first node then we can access any node of the linked
list. For example, if ‘a’ is a node then a->next is the node next to the ‘a’ (the
pointer storing the address of the next node is named ‘next’).
One thing you should notice here is that we can easily access the next node but
there is no way of accessing the previous node and this is the limitation of singly
linked list.
You are now clear with the concepts of a linked list. Let’s code it up. The first part
is to create a node (structure).
#include <iostream>
Now, we will create a class ‘linked_list’ which will contain all the functions and
data members required for a linked list. This class will use the structure ‘node’ for
the creation of the linked list.
The second and the most important part of a linked list is to always keep the track
of the first node because access to the first node means access to the entire list. So,
let’s call our first node as ‘ head’.
#include <iostream>
struct node
{
int data;
node *next;
};
class linked_list
{
private:
node *head,*tail;
public:
linked_list()
{
head = NULL;
tail = NULL;
}
};
int main()
{
linked_list a;
return 0;
}
We have made two nodes – head and tail. We will store the first node in ‘head’ and
the last node in ‘tail’. The constructor of the linked list is making both ‘head ’ and ‘
tail’ NULL because we have not yet added any element to our linked list and thus
both are NULL.
#include <iostream>
struct node
{
int data;
node *next;
};
class linked_list
{
private:
node *head,*tail;
public:
linked_list()
{
head = NULL;
tail = NULL;
}
void add_node(int n)
{
node *tmp = new node;
tmp->data = n;
tmp->next = NULL;
if(head == NULL)
{
head = tmp;
tail = tmp;
}
else
{
tail->next = tmp;
tail = tail->next;
}
}
};
int main()
{
linked_list a;
a.add_node(1);
a.add_node(2);
return 0;
}
If you are not familiar with the ‘malloc’ function, then just read the dynamic
memory allocation chapter.
node *tmp=new node – We are allocating the space required for a node by
the new operator. Now, ‘tmp’ points to a node (or space allocated for the node).
tmp->data = n – We are giving a value to the ‘data’ of ‘tmp’ as passed to the
function.
tmp->next=NULL – We have given the value to ‘data’ in the previous line and a
value of the pointer ‘next’ (NULL) in this line and thus making our node ‘tmp’
complete.
The next part after the creation of a node is to join the nodes and create the linked
list. We will first check if the ‘head’ is NULL or not. If the ‘head’ is NULL, it
means that there is no linked list yet and our current node(tmp) will be the ‘head’.
if(head == NULL)
{
head = tmp;
tail = tmp;
}
If ‘head’ is NULL, our current node (tmp) is the first node of the linked list and
this it will be ‘head’ and ‘tail’ both (as it is also the last element right now).
If ‘head’ is not NULL, it means that we have a linked list and we just have to add
the node at the end of the linked list.
else
{
tail->next = tmp;
tail = tail->next;
}
The new node (tmp) will go after the ‘tail’ and then we are changing the tail
because the new node is the new ‘tail’.
Traversing
In this post, we will traverse through each node in the linked list with a loop and
also with recursion.
Traversal means “visiting” or examining each node of the list. We start from the
beginning and visit one node at a time until the end of the list (until the ‘next’ is
NULL). As discussed in the previous post, we need the first element (head) to
reach to any element of the list. So, we will do the traversal using the ‘head’ and
print its element and then proceed to the next element of the list.
Thus, the steps for the traversal of the linked list are:
while(p != NULL)
{
printf("%d\n",p->data);
p = p->next;
}
Here, we are first checking if the node ‘p’ is not NULL then we are printing the
‘data’ stored in it. And then changing the p to the element stored in the ‘next’.
#include <iostream>
struct node
{
int data;
node *next;
};
class linked_list
{
private:
node *head,*tail;
public:
linked_list()
{
head = NULL;
tail = NULL;
}
void add_node(int n)
{
node *tmp = new node;
tmp->data = n;
tmp->next = NULL;
if(head == NULL)
{
head = tmp;
tail = tmp;
}
else
{
tail->next = tmp;
tail = tail->next;
}
}
void display()
{
node *tmp;
tmp = head;
while (tmp != NULL)
{
cout << tmp->data << endl;
tmp = tmp->next;
}
}
};
int main()
{
linked_list a;
a.add_node(1);
a.add_node(2);
a.display();
return 0;
}
We can also traverse the linked list using recursion. The same logic is also used in
traversing using recursion with just a difference that we will use recursion instead
of the while loop. Let’s see it in action.
#include <iostream>
struct node
{
int data;
node *next;
};
class linked_list
{
private:
node *head,*tail;
public:
linked_list()
{
head = NULL;
tail = NULL;
}
void add_node(int n)
{
node *tmp = new node;
tmp->data = n;
tmp->next = NULL;
if(head == NULL)
{
head = tmp;
tail = tmp;
}
else
{
tail->next = tmp;
tail = tail->next;
}
}
node* gethead()
{
return head;
}
int main()
{
linked_list a;
a.add_node(1);
a.add_node(2);
a.display(a.gethead());
return 0;
}
Here, we have declared a new function ‘gethead’ which is returning the head of the
linked list and then we are passing this head to the ‘display’ function.
In this code, we have first checked if the node is NULL or not. If it is NULL, then
we just printed “NULL” and when it is not then we printed the value of the ‘data’
and called the function ‘display’ again with the node next to it (‘head->next’).
Concatenating
Concatenating or joining two linked lists is not at all a difficult task. We just need
to follow some very simple steps and the steps to join two lists (say ‘a’ and ‘b’) are
as follows:
1. Traverse over the linked list ‘a’ until the element next to the node is not
NULL.
2. If the element next to the current element is NULL (a->next == NULL) then
change the element next to it to ‘b’ (a->next = b).
Here, we are traversing over the article using recursion as explained in the article
“Linked list traversal using while loop and recursion”. We are firstly checking if
the next node (a->next) is NULL or not. If it is NULL, then we are just changing
its value from NULL to ‘b’ (a->next = b) and if it is not then we are calling the
‘concatenate’ function again with the next element to traverse over the list.
#include <iostream>
struct node
{
int data;
node *next;
};
class linked_list
{
private:
node *head,*tail;
public:
linked_list()
{
head = NULL;
tail = NULL;
}
void add_node(int n)
{
node *tmp = new node;
tmp->data = n;
tmp->next = NULL;
if(head == NULL)
{
head = tmp;
tail = tmp;
}
else
{
tail->next = tmp;
tail = tail->next;
}
}
node* gethead()
{
return head;
}
There are three different possibilities for inserting a node into a linked list. These
three possibilities are:
In the first case, we make a new node and points its next to the head of the existing
list and then change the head to the newly added node. It is similar to picture given
below.
2. Point the ‘next’ of the new node to the ‘head’ of the linked list.
The code is very simple to understand. We just made a new node first – node
*tmp = new node;
tmp->next=head – In this line, we have followed the second step which is to point
the ‘next’ of the new node to the head of the linked list.
And in the last line, we are making the new node ‘head’ as per the third step
– head = tmp;
The second case is the simplest one. We just add a new node at the end of the
existing list. It is shown in the picture given below:
We have already dealt with this in the first post with the ‘add_node’ function. I am
just mentioning the ‘add_node’ function here again.
void add_node(int n)
{
node *tmp = new node;
tmp->data = n;
tmp->next = NULL;
if(head == NULL)
{
head = tmp;
tail = tmp;
}
else
{
tail->next = tmp;
tail = tail->next;
}
}
You can read the explanation of the above code in the first post of linked list.
The third and the last case is a little bit complicated. To insert a node in between a
linked list, we need to first break the existing link and then create two new links. It
will be clear from the picture given below.
The steps for inserting a node after node ‘a’ (as shown in the picture) are:
2. Point the ‘next’ of the new node to the node ‘b’ (the node after which we
have to insert the new node). Till now, two nodes are pointing the same
node ‘b’, the node ‘a’ and the new node.
#include <iostream>
struct node
{
int data;
node *next;
};
class linked_list
{
private:
node *head,*tail;
public:
linked_list()
{
head = NULL;
tail = NULL;
}
void add_node(int n)
{
node *tmp = new node;
tmp->data = n;
tmp->next = NULL;
if(head == NULL)
{
head = tmp;
tail = tmp;
}
else
{
tail->next = tmp;
tail = tail->next;
}
}
node* gethead()
{
return head;
}
void front(int n)
{
node *tmp = new node;
tmp -> data = n;
tmp -> next = head;
head = tmp;
}
int main()
{
linked_list a;
a.add_node(1);
a.add_node(2);
a.front(3);
linked_list::display(a.gethead());
return 0;
}
Deletion
We delete any node of a linked list by connecting the predecessor node of the node
to be deleted by the successor node of the same node. For example, if we have a
linked list a → b → c, then to delete the node ‘b’, we will connect ‘a’ to ‘c’ i.e., a
→ c. But this will make the node ‘b’ inaccessible and this type of inaccessible
nodes are called garbage and we need to clean this garbage. We do this cleaning by
the use of ‘delete’ operator. If you are not familiar with the ‘delete’ operator then
you can visit the ‘Dynamic memory’ chapter of the C++ course. So, the steps to be
followed for deletion of the node ‘B’ from the linked list A → B → C are as
follows:
#include <iostream>
struct node
{
int data;
node *next;
};
class linked_list
{
private:
node *head,*tail;
public:
linked_list()
{
head = NULL;
tail = NULL;
}
void add_node(int n)
{
node *tmp = new node;
tmp->data = n;
tmp->next = NULL;
if(head == NULL)
{
head = tmp;
tail = tmp;
}
else
{
tail->next = tmp;
tail = tail->next;
}
}
node* gethead()
{
return head;
}
void front(int n)
{
node *tmp = new node;
tmp -> data = n;
tmp -> next = head;
head = tmp;
}
int main()
{
linked_list a;
a.add_node(1);
a.add_node(2);
a.front(3);
a.add_node(5);
a.add_node(15);
a.after(a.gethead()->next->next->next, 10);
a.del(a.gethead()->next);
linked_list::display(a.gethead());
return 0;
}