Unit-3 Linked List
Unit-3 Linked List
Introduction
We have already studied about arrays. Arrays are used to store similar data in memory.
Arrays are simple to use, understand and elements are easily accessible. But unfortunately
arrays have some serious limitations.
1. Array is a static data structure. It means that you have to define the size of the array when
the program is being written.
2. Insertion and deletion of elements are difficult because there are lots of movement of
elements when an element is inserted or deleted in the mid of an array.
These problems are overcome by linked list. A linked list can grow and shrink in size during
its lifetime. Another advantage of a linked list is that nodes are stored at different memory
locations. In linked list, insertion and deletion is also simpler than arrays.
Linked List – a collection of element, called as nodes, in which each element contains a
pointer or index to the "next" element, along with the data represented by the element
Figure-3.1 shows a linked list of an ordered sequence of nodes with links being represented
by arrows.
21 38 18 62 NULL
A link is a pointer or an address that indicates the location of next node in the linked list. The
link field of last node contains a special value, known as NULL that indicates that this is the
last node of the list. The entire list is accessed from an external pointer, say first, that points
(contains the address of) the first node in the list, as shown in figure 3.2 (a). It is important to
note that first is not a node, rather the address of the first node of the list.
first 21 38 18 62 NULL
left data right left data right left data right left data right
The linked list, as shown in figure 3.2(a) is known as singly linked list, because traversing is
possible in single direction only. The limitation of such a single linked list is that if we are at a
node number ‘6’ then we cannot reach at node number ‘3’. This limitation is overcome by
doubly linked list.
In a double linked list, each node contains two pointers – one to its predecessor and another
to its successor. Each node of a doubly linked list contains three pieces of information – Data
field, that contains the information of the node, and Right and Left fields that contains
pointers to the successor and predecessor nodes respectively, as shown in figure 3.2(b).
Chapter-3 Linked Lists 2
Doubly Linked List – a special type of linked list in which each element contains two
pointers, one to the previous element and one to the next element, along with the data
represented by the element
Let us study some notations for use in algorithms (but not in ‘C’ programs).
A linked list is defined as a collection of nodes that can be traversed starting at the first node.
A linked list is a collection of similar nodes; therefore it can be naturally implemented with the
help of an array.
Since array is a static data structure and it requires a contiguous memory locations for its
elements and linked lists are very useful in situations where the program needs to manage
memory very carefully and a contiguous block of memory is not needed. Therefore array
representation of linked list is not a good choice.
To overcome this limitation, we use dynamic nodes, rather than static nodes. A dynamic
node is created when needed and destroyed when it is no longer needed. The main
advantage of using dynamic nodes is that there is no need to mention the predefined limits
on the number of nodes in the list. As long as memory space is available, we can create a
dynamic node any time. Now let us see how a linked list is implemented using dynamic
variables.
The second way for implementing a linked list in memory is to use a structure (node) which is
called as self-referential structure. Nodes are created dynamically, when needed, using
malloc() function and destroyed using free(), when no longer needed. The link field of the last
node contains sentinel value, define as NULL in C.
The following table shows the comparison between linked list and arrays.
Let us study the representation and implementation of various types of linked lists using
dynamic variables and how various operations are implemented on them.
Chapter-3 Linked Lists 3
struct node
{
int data;
struct node *link;
};
Here the member - struct node *link points to the structure itself and it is represented as:
Node
Data Link
To maintain a linear linked list we use a pointer variable ‘first’, also known as an external
pointer variable. The ‘first’ pointer contains an address of first node in the list. Here the name
‘first’ is just an user-defined identifier. You can also use other names, such as start, or head
etc. if the list is empty then the value of this external pointer variable must contain a NULL
value. Figure-3.3 represents a linear linked list of 4 nodes.
The link field of last contains a NULL value to indicate that this is the last node of the list. Let
us see how this list is created. Since this list has four nodes, therefore firstly we create four
dynamic nodes as:
Here sizeof() is an operator which returns the number of bytes required for a structure type
“struct node”. The node1, node2, node3 and node4 are declared as:
node1 ? ?
node2 ? ?
node3 ? ?
node4 ? ?
The data fields of all these four nodes are set as:
node1->data = 21;
node2->data = 38;
Chapter-3 Linked Lists 4
node3->data = 18;
node4->data = 62;
node1 21 ?
node2 38 ?
node3 18 ?
node4 62 ?
node1->link = node2;
node2->link = node3;
node3->link = node4;
node4->link = NULL;
We store NULL in the link field of node4 in order to indicate the end of the list. Finally all
these five nodes are represented as shown in Figure-3.4. Now if we store the address of first
node node1 in an external pointer variable ‘first’ we can easily access all four nodes by
walking through one node to next by using the link field of a node.
first
node1 21
1
node2 38
2
node3 18
3
node4 62
4 NULL
However some other operations are also possible on lists, such as searching, reversing,
concatenating, disposing, etc. In all these operations, we will pass an address of external
pointer ‘first’ to allow it change during the initialization of a linked list.
Remind that the pointer variable ‘first’ contains either a NULL value (if the list is empty) or
the address of first node of the linked list.
Chapter-3 Linked Lists 5
When we want to traverse a linear linked list we access each node of it and make use of
pointer field of each node while moving from one node to next. Firstly we will check whether
the list is empty or not. If the list is empty then it just displays an error message and the
control is returned back. If the list is not empty then we start accessing of nodes from first
node.
Algorithm : Traverse
Traverse(First)
Implementation : Traverse
If we are given a linked list and we want to search an item in that list then we will move from
one node to next until the node is searched or the entire list is searched. Firstly we will check
whether the list is empty or not. If the list is empty then it just displays an error message and
the control is returned back. If the list is not empty then we start searching from first node.
Algorithm : Search
Search(First, Item)
Implementation : Search
Search(int item)
{
struct node *current;
current = first;
while (current != NULL)
{
If (current->data == item)
{
printf("%d\n is found in the list", current->data);
Chapter-3 Linked Lists 6
return;
}
else
current = current->link;
}
printf("%d\n is not found in the list", current->data);
}
Insertion at first position - When we insert a new node as a first node then firstly we
create a new node ‘Temp’ and then set the data field and assign the value of the ‘first’ pointer
variable to the link field of ‘temp’ node as:
Data(Temp) = 55
Link(Temp) = First
and finally we update the value of external pointer variable ‘First’ as:
First = Temp
.
Figure-3.5 illustrates a linear linked list before and after inserting a new node.
First 21 38 18 62 NULL
First 21 38 18 62 NULL
55
Temp
Algorithm : InsertionFirst
InsertionFirst (Item)
Implementation : InsertionFirst
InsertionFirst(int item)
{
struct node *temp;
temp = (struct node *)malloc(sizeof(struct node));
temp->data=item;
temp->link = first;
first=temp;
}
Insertion at last position - When insert a new node at last position we will create a new
dynamic node first and update the external pointer variable, first, if the list is empty;
otherwise we store the address of this newly created node in the link field of last node.
Figure-3.6 illustrates a linear linked list before and after inserting a new node as last node.
First 21 38 18 62 NULL
First 21 38 18 62
55 NULL
Temp
Algorithm : InsertionLast
InsertionLast (Item)
Implementation : InsertionLast
{
current = first;
while (current->link != NULL)
current = current->link;
current->link = temp;
}
}
Insertion at any position - When we insert a new node at any specific position we take two
pointer variables – ‘current’ and ‘previous’. The current pointer holds the address of current
node and previous pointer holds the address of previous node of current node. Now we
move from one node to next until we come at proper position. After this we insert the new
node between previous node and current node. However if we do not get proper position and
entire list gets exhausted then this new node is inserted as last node.
Figure-3.7 illustrates a linear linked list before and after inserting a new node at 4 th position.
First 21 38 18 62 NULL
First 21 38 18 62 NULL
Previous
55
Temp
Algorithm : InsertionAny
Implementation : InsertionAny
Deleting at First Position – When we delete first node, if the list is not empty. Figure-3.8
illustrates a linear linked list of deleting first node.
First 21 38 18 62 NULL
Current
First 21 38 18 62 NULL
Current = First
Now the Current points to first node of the list. So process the data field of current node and
update the value of First as:
First = Link(First)
Algorithm : DeletionFirst
DeletionFirst ( )
Implementation : DeletionFirst
DeletionFirst( )
{
struct node *current;
if (first == NULL)
printf("\nList is empty. ");
else
{
current = first;
printf(“\nDeleted item = %d”, current->data);
first = first->link;
free (current);
}
}
Deleting of Last Node - When we delete last node, if the list is not empty. Figure-3.8
illustrates a linear linked list before and after deleting first node.
First 21 38 18 62 NULL
Previous Current
First 21 38 18 62 NULL
NULL
Current = First
Previous = NULL
Now we move both Current and Previous till the end of list is reached. Once the Current
point to last node and Previous points to Current node as update the value of Previous as:
Link(Previous) = Link(Current)
Algorithm : DeletionLast
DeletionLast ( )
Implementation : DeletionLast
DeletionLast ()
{
struct node *current, *previous;
if (first == NULL)
printf("\nList is empty.");
else
{
current = first;
previous=NULL;
if (first->link == NULL ) /* If there is only one node in the list */
first = first->link;
else
{
while (current->link != NULL) /* Move to last node */
{
previous = current;
current = current->link;
}
previous->link = current->link;
}
printf(“\nDeleted item = %d”, current->data);
free(current);
}
Deletion at any position - When we delete any node specific node, we will first move to
that node and then delete that node. For this we will come at that specific position using two
pointer variable Current and Previous. The Previous pointer will always points to the node
predecessor to Current node. Figure-3.9 illustrates a linear linked list of deletion of 3rd node.
First 21 38 18 62 NULL
Previous Current
First 21 38 18 62 NULL
If the node is other than the first node of the linked list then we assign the link part of the
deleted node (Current) to the link part of the Previous node as:
Link(Previous) = Link(Current)
Algorithm : DeletionAny
DeletionAny (Pos)
Implementation : DeletionAny
DeletionAny(int pos)
{
struct node *current, *previous;
int item, i;
if (first == NULL)
printf("\nList is empty. ");
else
{
if (pos == 1) /* If the node to be deleted is the first node */
{
current = first;
first = first->link;
printf("\nDeleted item = %d", current->data);
free(current);
}
else
{
current = first->link;
previous = first;
i = 2;
while (current != NULL) /* Move to the specific position */
{
if ( i == pos)
{
previous->link = current->link;
printf(“\nDeleted item = %d”, current->data);
free(current);
break;
}
else
{
previous = current;
current = current->link;
}
i++;
Chapter-3 Linked Lists 13
}
}
}
}
3.4.1.5 Disposing a Linear Linked List - Sometimes we need to free all the nodes in a
linear linked list in order to free the memory occupied by node.
Dispose( )
{
struct node *current;
current = first;
while (first != NULL)
{
free = first->link;
free(current);
}
}
In the above linked list, the external pointer ‘ROOT’ point to the first node
of the linked list. The first node of the linked list contains the information
about the variable with the highest degree. The first node points to the next
node with next lowest degree of the variable.
6) Representation of Sparse Matrix: In linked list, each node has four fields.
These four fields are defined as:
Row: Index of row, where non-zero element is located
Column: Index of column, where non-zero element is located
Value: Value of the non zero element located at index – (row,column)
Next node: Address of the next node
slot but depicting them as a linked list. Hash Table chaining in Java is
achievable with both, Doubly Linked List and Singly Linked List.
first 21 38 18 62 last
Note that a circular linked list does not have a natural ‘first’ and ‘last’ node. We must,
therefore, establish a first and last node by convention. That’s why for the sake of simplicity
we will assume two external pointer variable ‘first’ and ‘last’. The ‘first’ and ‘last’ external
pointer variables will contain the address of first and last nodes respectively.
Circular Linked List – a special type of linked list in which the last element's pointer
points back to the first element, along with the data represented by the element
The structure of a circular linked list of a node is same as that of a linear linked list. The
structure of a node is as:
struct node
{
int data;
struct node *link;
};
And two external pointer variable ‘first’ and ‘last’ is declared as:
first = NULL;
last = NULL;
Doubly Linked List – a linked list in which each node has three fields – data
(information of the node), left (location of predecessor node) and right (location of
successor node).
Thus in a doubly linked list each node contains not only the address of next node but also the
address of previous node, as shown in Figure-3.14
struct dnode
{
struct dnode *left;
int data;
struct dnode *right;
};
dnode
left data right
Like singly linked list, we maintain an external pointer ‘first’ that contains the address of first
node, if the list is empty; otherwise it contains a NULL value.
Initially NULL is assigned to first to indicate that the list is empty. Generally we perform
following operations on doubly linked lists:
We can traverse a doubly linked list in either direction or in both directions. It means that we
can traverse the list from left to right or right to left. That’s why we have stored NULL in the
left link of first node and right link of last node. Here is the ‘C’ implementation of this function.
Traverse ( )
{
if (first == NULL)
printf("\nList is empty.\n");
else
{
while (first != NULL)
{
printf("%d", first ->data);
first = first ->right;
}
}
}
Like singly linked list, insertion into a doubly linked list is possible at three different positions
– first position, last position or at any specific position. Let us see these insertions one by
one.
Inserting as a First Node - It is very simple to insert a new node at the beginning of the
doubly linked list, that is left of the leftmost node in the list. We will also consider the situation
when the list is empty.
Figure-3.15 illustrates a doubly linked list before and after inserting a new node at first
position.
first 38 18 62 NULL
NULL 21
Temp
Algorithm : InsertionDFirst
InsertionDFirst (Item)
Implementation : InsertionDFirst
InsertDFirst(int item)
{
struct dnode *temp;
if (first == NULL)
temp->right = NULL;
else
{
temp->right = first;
first->left = temp;
}
first = temp;
}
Inserting as a Last Node - When we insert a node at the last of a doubly linked list we
traverse the entire list until the last node is reached. And once we reach at last node we can
easily delete this one. We will also consider the situation when the list is empty. Figure-3.16
illustrates a doubly linked list before and after inserting a new node at last position.
first NULL 38 18 62
21 NULL
Chapter-3 Linked Lists 18
Temp
Algorithm : InsertionDLast
InsertionDLast (Item)
Implementation : InsertinDLast
InsertDLast(int item)
{
struct dnode *temp;
Inserting a Node at Any Specific Location - When we insert a node at any position in
the doubly linked list we need to specify the position of the inserted node. If the position of
item is within the limitation then it is inserted at that specific position; otherwise this node is
inserted at the end of the doubly linked list.
Figure-3.17 illustrates a doubly linked list before and after inserting a new node at 3rd
position.
29
Temp
Algorithm : InsertionDAny
Implementation : InsertionDAny
if (current->right != NULL)
temp->right->left = temp;
current->right = temp;
}
Chapter-3 Linked Lists 20
Like insertion, deletion of an element from a doubly linked list is possible and classified into
three different categories - deleting first node, deleting last node and deleting any node. Let
us see these deletions one by one.
Deletion of First Node - When we delete a node from a doubly linked list we will first
check whether the list is empty or not. If the list is empty then it will simple report an error
message and the control is returned back; otherwise the first node of the list is deleted.
Figure-3.18 illustrates a doubly linked list before and after deletion of first node.
first
NULL 38 18 62 NULL
NULL 21
Algorithm : DeleteDFirst
DeleteDFirst ()
Perform the following steps if First <> NULL
1. Set Current = First
2. Update First – First = Right(First)
3. If First <> NULL then set Left(First) = NULL
4. Process the Data of Current node – Data(Current)
5. Free the memory occupied by Current node
6. Exit
Implementation : DeleteDFirst
DeleteDFirst()
{
struct donode *current;
if (first == NULL)
printf("\nList is empty.");
else
{
current = first;
first = first->right;
if (first != NULL)
first->left = NULL;
printf(“\nDeleted item = %d”, current->data);
free(current);
}
}
When we delete the last node from a doubly linked list we will first check whether the list is
empty or not. If the list is empty then it will simple report an error message and the control is
returned back; otherwise the last node of the list is deleted. Unlike singly linked list, we need
Chapter-3 Linked Lists 21
not to maintain a previous pointer in the doubly linked list, because it is the current node who
contains the address of its previous node.
Figure-3.19 illustrates a doubly linked list before and after deletion of last node.
62 NULL
Current
Algorithm : DeleteDLast
DeleteDLast ()
Perform the following steps if First <> NULL
1. Set Current = First
2. Repeat through Step-3 while Right(Current) <> NULL
3. Update Current – Current = Right(Current)
4. If Left(Current) <> NULL then set Right(Left(Current )) = Right(Current)
Otherwise Set First = NULL
5. Process the Data of Current node – Data(Current)
6. Free the memory occupied by Current node
7. Exit
Implementation : DeleteDLast
DeleteDLast()
{
struct dnode *current;
if (first == NULL)
printf("\nList is empty.");
else
{
current = first;
while (current->right != NULL)
current = current->right;
if (current->left != NULL)
current->left->right = current->right;
else
first = NULL;
When we delete any node from a doubly linked list we will first check whether the list is
empty or not. If the list is empty then it will simple report an error message and the control is
returned back; otherwise position of the node, to be deleted, is to be find out using a loop.
However if the loop completes and the item is not found then it will simple display an error
message that – “Such an item does not exist.”
Chapter-3 Linked Lists 22
Figure-3.20 illustrates a doubly linked list before and after deletion of node number 3.
Current
Algorithm : DeleteDAny
DeleteDAny (Pos)
Perform the following steps if First <> NULL
1. Set Current = First
2. Repeat through Step-8 while Current <> NULL
3. If I = Pos then go to Step-4;
Otherwise go to Step-7
4. If Left(Current) = NULL then update the following links:
Left(Right(Current)) = NULL
First = Right(Current)
Else If Right(Current) = NULL then update the following links:
Right(Left(Current)) = Right(Current)
Else update the following links:
Right(Left(Current)) = Right(Current)
Left(Right(Current)) = Left(Current)
5. Process the Data of Current node – Data(Current)
6. Free the memory occupied by Current node and go to Step-10
7. Increment the value of I – I = I + 1
8. Update the value of Current – Current = Right (Current)
9. Display – “Such a node number does not exist.”
10. Exit
Implementation : DeleteDAny
DeleteDAny(int pos)
{
struct dnode *current, *previous;
int i=1;
if (first == NULL)
printf("\nList is empty.");
else
{
current = first;
while (current != NULL)
{
if (i == pos)
{
if (current->left == NULL)
{
current->right->left = NULL;
first = current->right;
}
else if (current->right == NULL)
Chapter-3 Linked Lists 23
current->left->right = current->right;
else
{
current->left->right=current->right;
current->right->left = current->left;
}
printf(“\nDeleted item = %d”, current->data);
free(current);
return;
}
i++;
current = current->right;
}
printf("\nSuch a node number does not exist.");
}
}
Header Linked list – a special type of linked list in which the first nodes contains
special information about the linked list, rather than usual information of the node
(i) Grounded Header Linked Lists - A grounded header linked list is one whose last
node contains a NULL value
(ii) Circular Header Linked Lists - A circular leader linked list is one whose last node
points to the header node; rather than containing a NULL value.
first # 38 18 62 NULL
first last
# 38 18 62
first # 21 38 18 62 NULL
first # 21 38 18 62