Unit-2 (Linked List)
Unit-2 (Linked List)
UNIT II
………………………………………..........
LINKED LISTS
A linked list is a way to store a collection of elements. Each element in a linked list is stored in
the form of a node. A data part stores the element and a next part stores the link to the next
node.
Linked List:
2
Linked lists are needed in certain situations where other data structures, like arrays, might not be as
efficient or practical. Here's why you might choose to use a linked list:
1. Dynamic Size:
o Linked lists allow for dynamic memory allocation. You don't need to specify the size
ahead of time, and you can easily grow or shrink the list without worrying about
running out of space or resizing like in arrays.
2. Efficient Insertions and Deletions:
o In linked lists, you can add or remove elements in constant time O(1),especially at the
beginning or middle of the list (if you have a reference to the node). This is much
faster than arrays, where shifting elements is required after insertion or deletion.
3. No Wasted Space:
o Linked lists allocate memory for each element as needed, meaning there's no wasted
space (unlike arrays, which might allocate more memory than needed, leading to
waste).
4. Flexibility:
o Linked lists are flexible in the sense that they can be used to implement other data
structures like stacks, queues, and graphs. You can easily modify the structure based
on the needs of your algorithm.
5. Efficient Memory Usage:
o Linked lists don't require contiguous memory space, so they can be useful in
situations with fragmented memory or when memory needs to be allocated on the fly.
3
1. Memory Overhead:
o Each node in a linked list requires additional memory to store a reference (or pointer)
to the next (and possibly previous) node. This pointer overhead can be significant,
especially for small data elements.
2. Sequential Access:
o Linked lists do not support direct access to elements by index (like arrays do). To
access a particular element, you have to traverse the list from the beginning, which
can be slow for large lists. This leads to slower performance for search operations,
which typically take O(n)O(n)O(n) time.
3. Cache Locality:
o Arrays benefit from better cache locality because their elements are stored in
contiguous memory locations. In contrast, linked list nodes are scattered in memory,
making it less cache-friendly and potentially slower in terms of accessing data.
4. Complexity in Implementation:
o Linked lists require more complex implementation and management compared to
arrays. You need to handle pointer manipulation carefully, especially in operations
like insertion, deletion, and traversal. This can increase the chance of errors, like
memory leaks or null pointer exceptions.
5. No Random Access:
o With arrays, you can directly access any element using an index, but in a linked list,
you can only access elements sequentially. This makes linked lists inefficient for
certain operations where quick access to arbitrary elements is required.
6. Slower Traversal:
o Traversing a linked list is slower than traversing an array, as you need to follow
pointers from one node to the next rather than accessing elements directly via indices.
7. Overhead for Small Data:
o If the data in each node is small, the overhead of storing pointers can outweigh the
benefits. For small datasets, arrays can be more efficient both in terms of time and
space.
Linked list
Linked list is a linear data structure that includes a series of
connected nodes. Linked list can be defined as the nodes that are randomly stored in the
memory. A node in the linked list contains two parts, i.e.,
first is the data part and second is the address part. The last node of the list contains a pointer
to the null. After array, linked list is the second most used data structure. In a linked list, every
link contains a connection to another link.
4
Linked list is a data structure that overcomes the limitations of arrays. Let's first see some of
the limitations of arrays -
o The size of the array must be known in advance before using it in the program.
o Increasing the size of the array is a time taking process. It is almost impossible to expand
the size of the array at run time.
o All the elements in the array need to be contiguously stored in the memory. Inserting an
element in the array needs shifting of all its predecessors.
Linked list is useful because -
o It allocates the memory dynamically. All the nodes of the linked list are non-contiguously
stored in the memory and linked together with the help of pointers.
o In linked list, size is no longer a problem since we do not need to define its size at the time
of declaration. List grows as per the program's demand and limited to the available memory
space.
It is simple to declare an array, as it is of single type, while the declaration of linked list is a bit
more typical than array. Linked list contains two parts, and both are of different types, i.e., one
is the simple variable, while another is the pointer variable. We can declare the linked list by
using the user-defined data type structure.
1. struct node
2. {
3. int data;
4. struct node *next;
5. }
In the above declaration, we have defined a structure named
as node that contains two variables, one is data that is of integer type, and another one
is next that is a pointer which contains the address of next node.
Since the last node and the first node of the circular linked list are connected,
the traversal in this linked list will go on forever until it is broken.
10
The basic operations in the linked lists are insertion, deletion, searching,
display, and deleting an element at a given key. These operations are
performed on Singly Linked Lists as given below −
o Dynamic data structure - The size of the linked list may vary according to the
requirements. Linked list does not have a fixed size.
o Insertion and deletion - Unlike arrays, insertion, and deletion in linked list is easier. Array
elements are stored in the consecutive location, whereas the elements in the linked list are
stored at a random location. To insert or delete an element in an array, we have to shift the
elements for creating the space. Whereas, in linked list, instead of shifting, we just have to
update the address of the pointer of the node.
o Memory efficient - The size of a linked list can grow or shrink according to the
requirements, so memory consumption in linked list is efficient.
o Implementation - We can implement both stacks and queues using linked list.
o Memory usage - In linked list, node occupies more memory than array. Each node of the
linked list occupies two types of variables, i.e., one is a simple variable, and another one is
the pointer variable.
o Traversal - Traversal is not easy in the linked list. If we have to access an element in the
linked list, we cannot access it randomly, while in case of array we can randomly access it
by index. For example, if we want to access the 3rd node, then we need to traverse all the
nodes before it. So, the time required to access a particular node is large.
o Reverse traversing - Backtracking or reverse traversing is difficult in a linked list. In a
doubly-linked list, it is easier but requires more memory to store the back pointer.
o With the help of a linked list, the polynomials can be represented as well as we can perform
the operations on the polynomial.
11
Example:
12
Insertion
Deletion
Display
Before we implement actual operations, first we need to set up an empty list. First, perform the following
steps before implementing actual operations.
Step 1 - Include all the header files which are used in the program.
Step 2 - Declare all the user defined functions.
Step 3 - Define a Node structure with two members data and next
Step 4 - Define a Node pointer 'head' and set it to NULL.
Step 5 - Implement the main method by displaying operations menu and make suitable function
calls in the main method to perform user selected operation.
Insertion
In a single linked list, the insertion operation can be performed in three ways. They are as follows...
Step 1 – Create a newNode with given value and newNode → next as NULL.
Step 2 – Check whether list is Empty (head == NULL).
Step 3 – If it is Empty then, set head = newNode.
Step 4 – If it is Not Empty then, define a node pointer temp and initialize with head.
Step 5 – Keep moving the temp to its next node until it reaches to the last node in the list (until temp
→ next is equal to NULL).
Step 6 – Set temp → next = newNode.
14
Deletion
In a single linked list, the deletion operation can be performed in three ways. They are as
follows…
Step 7 – If list has only one node and that is the node to be deleted, then set head = NULL and
delete temp1 (free(temp1)).
Step 8 – If list contains multiple nodes, then check whether temp1 is the first node in the list (temp1
== head).
Step 9 – If temp1 is the first node then move the head to the next node (head = head → next) and
delete temp1.
Step 10 – If temp1 is not first node then check whether it is last node in the list (temp1 → next ==
NULL).
Step 11 – If temp1 is last node then set temp2 → next = NULL and delete temp1 (free(temp1)).
Step 12 – If temp1 is not first node and not last node then set temp2 → next = temp1 → next and
delete temp1 (free(temp1)).
18
While the pointer is not null, we will access and print the data of the current
node, then we move the pointer to next node.
20
21
A doubly linked list containing three nodes having numbers from 1 to 3 in their data
part, is shown in the following image.
1. struct node
2. {
3. struct node *prev;
4. int data;
5. struct node *next;
6. }
22
The prev part of the first node and the next part of the last
node will always contain null indicating end in each direction.
In a singly linked list, we could traverse only in one direction, because each node contains
address of the next node and it doesn't have any record of its previous nodes. However,
doubly linked list overcome this limitation of singly linked list. Due to the fact that, each
node of the list contains the address of its previous node, we can find all the details about
the previous node as well by using the previous address stored inside the previous part of
each node.
In the following image, the first element of the list that is i.e. 13 stored at address 1. The
head pointer points to the starting address 1. Since this is the first element being added to
the list therefore the prev of the list contains null. The next node of the list resides at
address 4 therefore the first node contains 4 in its next pointer.
We can traverse the list in this way until we find any node containing null or -1 in its next
part.
23
1. Insertion
2. Deletion
3. Display
Insertion
In a double linked list, the insertion operation can be performed in three ways as follows...
Step 1 - Create a newNode with given value and newNode → previous as NULL.
Step 2 - Check whether list is Empty (head == NULL)
24
Step 3 - If it is Empty then, assign NULL to newNode → next and newNode to head.
Step 4 - If it is not Empty then, assign head to newNode → next and newNode to head.
Step 1 - Create a newNode with given value and newNode → previous as NULL.
Step 2 - Check whether list is Empty (head == NULL)
Step 3 - If it is Empty then, assign NULL to newNode → next and newNode to head.
Step 4 - If it is not Empty then, assign head to newNode → next and newNode to head.
Step 1 - Create a newNode with given value and newNode → next as NULL.
Step 2 - Check whether list is Empty (head == NULL)
Step 3 - If it is Empty, then assign NULL to newNode → previous and newNode to head.
Step 4 - If it is not Empty, then, define a node pointer temp and initialize with head.
Step 5 - Keep moving the temp to its next node until it reaches to the last node in the list
(until temp → next is equal to NULL).
Step 6 - Assign newNode to temp → next and temp to newNode → previous.
25
Deletion
In a double linked list, the deletion operation can be performed in three ways as follows...
28
Each node consists of a data value and a Each node consists of a data value, a pointer to the next node,
pointer to the next node. and a pointer to the previous node.
In single linked list, every node points to its next node in the sequence and the last node points NULL.
But in circular linked list, every node points to its next node in the sequence but the last node points to
A circular linked list is a sequence of elements in which every element has a link to its next
element in the sequence and the last element has a link to the first element.
30
Operations
In a circular linked list, we perform the following operations...
1. Insertion
2. Deletion
3. Display
Before we implement actual operations, first we need to setup empty list. First perform the following
steps before implementing actual operations.
Step 1 - Include all the header files which are used in the program.
Step 2 - Declare all the user defined functions.
Step 3 - Define a Node structure with two members data and next
Step 4 - Define a Node pointer 'head' and set it to NULL.
Step 5 - Implement the main method by displaying operations menu and make suitable function
calls in the main method to perform user selected operation.
Insertion
In a circular linked list, the insertion operation can be performed in three ways. They are as follows...
Step 6 - Set 'newNode → next =head', 'head = newNode' and 'temp → next = head'.
Step 4 - If it is Not Empty then, define a node pointer temp and initialize with head.
Step 5 - Keep moving the temp to its next node until it reaches to the node after which we want
to insert the newNode (until temp1 → data is equal to location, here location is the node value
after which we want to insert the newNode).
Step 6 - Every time check whether temp is reached to the last node or not. If it is reached to last
node then display 'Given node is not found in the list!!! Insertion not possible!!!' and
terminate the function. Otherwise move the temp to next node.
Step 7 - If temp is reached to the exact node after which we want to insert the newNode then
check whether it is last node (temp → next == head).
Step 8 - If temp is last node then set temp → next = newNode and newNode → next = head.
Step 8 - If temp is not last node then set newNode → next = temp → next and temp →
next = newNode.
Deletion
In a circular linked list, the deletion operation can be performed in three ways those are as follows...
Step 3 - If it is Not Empty then, define two Node pointers 'temp1' and 'temp2' and initialize both
'temp1' and 'temp2' with head.
Step 4 - Check whether list is having only one node (temp1 → next == head)
Step 5 - If it is TRUE then set head = NULL and delete temp1 (Setting Empty list conditions)
Step 6 - If it is FALSE move the temp1 until it reaches to the last node. (until temp1 →
next == head )
Step 7 - Then set head = temp2 → next, temp1 → next = head and delete temp2.
Step 2 - If it is Empty, then display 'List is Empty!!!' and terminate the function.
Step 3 - If it is Not Empty then, define a Node pointer 'temp' and initialize with head.
Step 4 - Keep displaying temp → data with an arrow (--->) until temp reaches to the last node
Step 5 - Finally display temp → data with arrow pointing to head → data.
follows:
1.Polynomial Representation
Array implementation:
Now, the question arises: we can also use the simple matrix to store the elements,
then why is the sparse matrix required?
Storage - We know that a sparse matrix contains lesser non-zero elements than zero,
so less memory can be used to store elements. It evaluates only the non-zero
elements.
Computing time: In the case of searching in sparse matrix, we need to traverse only
the non-zero elements rather than traversing all the sparse matrix elements. It saves
computing time by logically designing a data structure traversing non-zero elements.
o Array representation
o Linked list representation
41
In 2D array representation of sparse matrix, there are three fields used that are
named as -
Let's understand the array representation of sparse matrix with the help of the
example given below -
In the above figure, we can observe a 5x4 sparse matrix containing 7 non-zero
elements and 13 zero elements. The above matrix occupies 5x4 = 20 memory space.
Increasing the size of matrix will increase the wastage space.
Unlike the array representation, a node in the linked list representation consists of
four fields. The four fields of the linked list are given as follows -
o Row - It represents the index of the row where the non-zero element is
located.
o Column - It represents the index of the column where the non-zero element
is located.
o Value - It is the value of the non-zero element that is located at the index
(row, column).
o Next node - It stores the address of the next node.
43
The node structure of the linked list representation of the sparse matrix is shown in
the below image -
Example -
Let's understand the linked list representation of sparse matrix with the help of the
example given below -
In the above figure, we can observe a 4x4 sparse matrix containing 5 non-zero
elements and 11 zero elements. Above matrix occupies 4x4 = 16 memory space.
Increasing the size of matrix will increase the wastage space.
In the above figure, the sparse matrix is represented in the linked list form. In the
node, the first field represents the index of the row, the second field represents the
index of the column, the third field represents the value, and the fourth field contains
the address of the next node.
44
• Random deallocation
• Ordered deallocation
Linked lists find numerous real-world applications due to their dynamic nature and
efficiency in certain scenarios. Let's explore some of these practical uses: