DS Unit-2 (R23)
DS Unit-2 (R23)
1. LINKED LISTS
Basic Terminologies
A linked list, in simple terms, is a linear collection of data elements. These data elements are
called nodes. Linked list is a data structure which in turn can be used to implement other data
structures. Thus, it acts as a building block to implement data structures such as stacks, queues,
and their variations. A linked list can be perceived as a train or a sequence of nodes in which
each node contains one or more data fields and a pointer to the next node.
In above Fig., we can see a linked list in which every node contains two parts, an integer and a
pointer to the next node. The left part of the node which contains data may include a simple data
type, an array, or a structure. The right part of the node contains a pointer to the next node (or
address of the next node in sequence). The last node will have no next node connected to it, so it
will store a special value called NULL. In above Fig, the NULL pointer is represented by X.
While programming, we usually define NULL as –1. Hence, a NULL pointer denotes the end of
the list. Since in a linked list, every node contains a pointer to another node which is of the same
type, it is also called a self-referential data type.
Linked lists contain a pointer variable START that stores the address of the first node in the list.
We can traverse the entire list using START which contains the address of the first node; the
next part of the first node in turn stores the address of its succeeding node. Using this technique,
the individual nodes of the list will form a chain of nodes. If START = NULL, then the linked
list is empty and contains no nodes.
Both arrays and linked lists are a linear collection of data elements. But unlike an array, a
linked list does not store its nodes in consecutive memory locations.
Another point of difference between an array and a linked list is that a linked list does not
allow random access of data. Nodes in a linked list can be accessed only in a sequential
manner. But like an array, insertions and deletions can be done at any point in the list in a
constant time.
Another advantage of a linked list over an array is that we can add any number of
elements in the list. This is not possible in case of an array. For example, if we declare an
array as int marks[20], then the array can store a maximum of 20 data elements only.
There is no such restriction in case of a linked list.
A singly linked list is the simplest type of linked list in which every node contains some data and
a pointer to the next node of the same data type. By saying that the node contains a pointer to the
next node, we mean that the node stores the address of the next node in sequence. A singly
linked list allows traversal of data only in one way. Figure below shows a singly linked list.
Example
Traversing a linked list means accessing the nodes of the list in order to perform some processing
on them. Remember a linked list always contains a pointer variable START which stores the
address of the first node of the list. End of the list is marked by storing NULL or –1 in the NEXT
field of the last node. For traversing the linked list, we also make use of another pointer variable
PTR which points to the node that is currently being accessed.
To count the number of nodes in a linked list, we will traverse each and every node of the list
and while traversing every individual node, we will increment the counter by 1. Once we reach
NULL, that is, when all the nodes of the linked list have been traversed, the final value of the
counter will be displayed.
Searching a linked list means to find a particular element in the linked list. As already discussed,
a linked list consists of nodes which are divided into two parts, the information part and the next
part. So searching means finding whether a given value is present in the information part of the
node or not. If it is present, the algorithm returns the address of the node that contains the value.
Consider the linked list shown in Fig. Suppose we want to add a new node with data 9 and add it
as the first node of the list. Then the following changes will be done in the linked list.
Consider the linked list and suppose we want to add a new node with data 9 as the last node of
the list. Then the following changes will be done in the linked list. First we insert a new node at
the end of a linked list. We take a pointer variable PTR and initialize it with START. That is,
PTR now points to the first node of the linked list. We traverse PTR through the linked list to
reach the last node. Once we reach the last node, we change the NEXT pointer of the last node to
store the address of the new node. Remember that the NEXT field of the new node contains
NULL, which signifies the end of the linked list.
We take a pointer variable PTR and initialize it with START. That is, PTR now points to the first
node of the linked list. Then we take another pointer variable PREPTR which will be used to
store the address of the node preceding PTR. Initially, PREPTR is initialized to PTR. So now,
PTR, PREPTR, and START are all pointing to the first node of the linked list.
We traverse through the linked list to reach the node that has its value equal to NUM. We need to
reach this node because the new node will be inserted after this node. Once we reach this node,
we change the NEXT pointers in such a way that new node is inserted after the desired node.
Step 6: Repeat Steps 7 and 8 while PTR ≠ NULL AND PTR → DATA ≠ NUM
Step 7: SET PTR = PTR → NEXT
[END OF LOOP]
Suppose we want to add a new node, we take a pointer variable PTR and initialize it with
START. That is, PTR now points to the first node of the linked list. Then, we take another
pointer variable PREPTR and initialize it with PTR. So now, PTR, PREPTR, and START are all
pointing to the first node of the linked list. We traverse through the linked list to reach the node
that has its value equal to NUM. We need to reach this node because the new node will be
inserted before this node. Once we reach this node, we change the NEXT pointers in such a way
that the new node is inserted before the desired node.
If we want to delete node in already existing list consider three cases and then see how deletion
is done in each case.
Case 1: The first node is deleted.
Case 2: The last node is deleted.
Case 3: The node after a given node is deleted.
let us first discuss an important term called UNDERFLOW. Underflow is a condition that occurs
when we try to delete a node from a linked list that is empty. This happens when START =
NULL or when there are no more nodes to delete. Note that when we delete a node from a linked
list, we actually have to free the memory occupied by that node. The memory is returned to the
free pool so that it can be used to store other programs and data. Whatever be the case of
deletion, we always change the AVAIL pointer so that it points to the address that has been
recently vacated.
When we want to delete a node from the beginning of the list, then the following changes will be
done in the linked list. We check if the linked list exists or not. If START = NULL, then it
signifies that there are no nodes in the list and exit.
However, if there are nodes in the linked list, then we use a pointer variable PTR that is set to
point to the first node of the list. For this, we initialize PTR with START that stores the address
of the first node of the list. START is made to point to the next node in sequence and finally the
memory occupied by the node pointed by PTR (initially the first node of the list) is freed and
returned to the free pool.
DATA STRUCTURES – UNIT 2[R23] Page 10
Algorithm to delete the first node
Suppose we want to delete the last node from the linked list, then the following changes will be
done in the linked list. We take a pointer variable PTR and initialize it with START. That is,
PTR now points to the first node of the linked list. We take another pointer variable PREPTR
such that it always points to one node before the PTR. Once we reach the last node and the
second last node, we set the NEXT pointer of the second last node to NULL, so that it now
becomes the (new) last node of the linked list. The memory of the previous last node is freed and
returned back to the free pool.
Suppose we want to delete the node that succeeds the node which contains data value 4. Then the
following changes will be done in the linked list. We take a pointer variable PTR and initialize it
with START. That is, PTR now points to the first node of the linked list. In the while loop, we
take another pointer variable PREPTR such that it always points to one node before the PTR.
Once we reach the node containing VAL and the node succeeding it, we set the next pointer of
the node containing VAL to the address contained in next field of the node succeeding it. The
memory of the node succeeding the given node is freed and returned back to the free pool.
WHAT IS POLYNOMIAL
A polynomial p(x) is the expression in variable x which is in the form (axn + bxn-1 + …. + jx+ k),
where a, b, c …., k fall in the category of real numbers and 'n' is non negative integer, which is
called the degree of polynomial. An essential characteristic of the polynomial is that each term in
the polynomial expression consists of two parts:
The polynomial can be represented in linked list by using the nodes. Each node can consist of
coefficient, power and address of the next node.
If we want to add two polynomials first we can compare the exponentiation part
a. If the exponentiations of the two terms are equal then the coefficients are added and put
the same expression.
b. If the exponentiation part of the items is greater than the other simply write the greater
exponentiation term of coefficient and exponentiation.
Example:-
Algorithm PolynomialAdd_SL
Input: Two polynomials P and Q whose header pointers are PHEADER and QHEADER.
Output: A polynomial R is the sum of P and Q having the header RHEADER.
Pptr = PHEADER, Qptr = QHEADER //Get a header node for the resultant polynomial//
Rptr = RHEADER
While (Pptr ≠ NULL) and (Qptr ≠ NULL) do
CASE: Pptr →EXP = Qptr→ EXP
New= GetNode (NODE)
Rptr→ LINK= new, Rptr = new
Rptr →COEFF = Pptr→COEFF + Qptr→COEFF
Rptr→ EXP = Pptr→ EXP
Rptr →LINK = NULL
Pptr = Pptr→ LINK, Qptr = Qptr→LINK
Given two polynomials in the form of linked list. The task is to find the multiplication of both
polynomials.
Approach:
1. In this approach we will multiply the 2nd polynomial with each term of 1st polynomial.
2. Store the multiplied value in a new linked list.
Examples:
On multiplying each element of 1st polynomial with elements of 2nd polynomial, we get
18x^3 + 24x^2 + 30x^2 + 40x^1 + 36x^1 + 48
On adding values with same power of x,
18x^3 + 54x^2 + 76x^1 + 48
A matrix is a two-dimensional data object made of m rows and n columns, therefore having total
m x n values. If most of the elements of the matrix have 0 values, then it is called a sparse
matrix.
Why to use Sparse Matrix instead of simple matrix?
Storage: There are lesser non-zero elements than zeros and thus lesser memory can be
used to store only those elements.
Computing time: Computing time can be saved by logically designing a data structure
traversing only non-zero elements..
Example:-
00304
00570
00000
02600
This concept is essential as the matrix can be designed to:
1. Save Space: The sparse matrix is represented using forms where only the NON-ZERO
elements and their locations are stored. This saves space over a simple matrix where
ZERO elements would also consume memory.
2. Save Computing Time: The sparse matrix can be stored in a way that accessing the
elements becomes efficient.
Linked Representation`
A linked list may be used to store a sparse matrix by representing each NON-ZERO value as a
node and linking this Node in a specific way such that it represents the position in the original
array. To represent sparse matrix in linked list we can use three types of nodes called as head
node, row node and column node.
Head Node:-
In the head node the node contains 4-parts. In that node we can represents the size of the matrix
(row and column) and total non – zero values and pointer.
In the row node contain 3-parts. The 1st one is row number, 2nd one is pointer for next row and
3rd one is pointer for column.
Column Node:-
In the column node contains 3- parts. They are column number, value and pointer for next value
in the same row.
0 2 0 0
4 0 3 0
0 1 0 1
0 2 0 0
We can represent the given sparse matrix in linked list as
*DISADVANTAGE:-
1) It requires more space as pointers are also stored with information.
2) Different amount of time is required to access each element.
3) If we have to go to a particular element then we have to go through all those elements that
come before that element.
4) We cannot traverse it from last & only from the beginning.
5) It is not easy to sort the elements stored in the linear linked list.
A doubly linked list or a two-way linked list is a more complex type of linked list which contains
a pointer to the next as well as the previous node in the sequence. Doubly Linked List is a
variation of Linked list in which navigation is possible in both ways, either forward or backward
Example
Consider the doubly linked list shown in Fig. Suppose we want to add a new node with data 9 as
the first node of the list. To insert a new node at the beginning of a doubly linked list, we first
check whether memory is available for the new node. If the free memory has exhausted, then an
OVERFLOW message is printed. Otherwise, if free memory cell is available, then we allocate
space for the new node. Set its DATA part with the given VAL and the NEXT part is initialized
with the address of the first node of the list, which is stored in START. Now, since the new node
is added as the first node of the list, it will now be known as the START node, that is, the
START pointer variable will now hold the address of NEW_NODE.
Consider the doubly linked list shown in Fig. Suppose we want to add a new node with data 9 as
the last node of the list. To insert a new node at the end of a doubly linked list, we take a pointer
variable PTR and initialize it with START. In the while loop, we traverse through the linked list
Consider the doubly linked list shown in Fig. Suppose we want to add a new node with value 9
before the node containing 3. We first check whether memory is available for the new node.
Then, we take a pointer variable PTR and initialize it with START. That is, PTR now points to
the first node of the linked list. In the while loop, we traverse through the linked list to reach the
node that has its value equal to NUM. We need to reach this node because the new node will be
inserted before this node. Once we reach this node, we change the NEXT and PREV fields in
such a way that the new node is inserted before the desired node.
In this section, we will see how a node is deleted from an already existing doubly linked list. We
will take four cases and then see how deletion is done in each case.
Case 1: The first node is deleted.
Case 2: The last node is deleted.
Case 3: The node after a given node is deleted.
Case 4: The node before a given node is deleted.
Consider the doubly linked list shown in Fig. When we want to delete a node from the beginning
of the list, we check if the linked list exists or not. If START is NULL, then it signifies that there
are no nodes in the list and the control is transferred to the last statement of the algorithm.
However, if there are nodes in the linked list, then we use a temporary pointer variable PTR that
is set to point to the first node of the list. For this, we initialize PTR with START that stores the
address of the first node of the list. START is made to point to the next node in sequence and
finally the memory occupied by PTR (initially the first node of the list) is freed and returned to
the free pool.
Consider the doubly linked list shown in Fig. Suppose we want to delete the last node from the
linked list, we take a pointer variable PTR and initialize it with START. That is, PTR now points
to the first node of the linked list. Once we reach the last node, we can also access the second last
Consider the doubly linked list shown in Fig. Suppose we want to delete the node that succeeds
the node which contains data value 4. We take a pointer variable PTR and initialize it with
START. That is, PTR now points to the first node of the doubly linked list. Once we reach the
node containing VAL, the node succeeding it can be easily accessed by using the address stored
in its NEXT field. The NEXT field of the given node is set to contain the contents in the NEXT
Consider the doubly linked list shown in Fig. Suppose we want to delete the node preceding the
node with value 4. We take a pointer variable PTR and initialize it with START. That is, PTR
now points to the first node of the linked list. Once we reach the node containing VAL, the
PREV field of PTR is set to contain the address of the node preceding the node which comes
before PTR. The memory of the node preceding PTR is freed and returned to the free pool.
Hence, we see that we can insert or delete a node in a constant number of operations given only
that node’s address. Note that this is not possible in the case of a singly linked list which requires
the previous node’s address also to perform the same operation.
In a circular linked list, the last node contains a pointer to the first node of the list. We can have a
circular singly linked list as well as a circular doubly linked list. While traversing a circular
linked list, we can begin at any node and traverse the list in any direction, forward or backward,
until we reach the same node where we started. Thus, a circular linked list has no beginning and
no ending. Figure shows a circular linked list.
In this section, we will see how a new node is added into an already existing linked list. We will
take two cases and then see how insertion is done in each case.
Case 1: The new node is inserted at the beginning of the circular linked list.
Case 2: The new node is inserted at the end of the circular linked list.
Consider the linked list shown in Fig. Suppose we want to add a new node with data 9 as the first
node of the list. We first check whether memory is available for the new node. If the free
memory has exhausted, then an OVERFLOW message is printed. Otherwise, if free memory cell
is available, then we allocate space for the new node. Set its DATA part with the given VAL and
the NEXT part is initialized with the address of the first node of the list, which is stored in
START. Now, since the new node is added as the first node of the list, it will now be known as
the START node, that is, the START pointer variable will now hold the address of the
NEW_NODE. Because the last node contains a pointer to START, its NEXT field is updated so
that after insertion it points to the new node which will be now known as START.
Consider the linked list shown in Fig. Suppose we want to add a new node with data 9 as the last
node of the list. We take a pointer variable PTR and initialize it with START. That is, PTR now
points to the first node of the linked list. In the while loop, we traverse through the linked list to
reach the last node. Once we reach the last node, we change the NEXT pointer of the last node to
store the address of the new node. Remember that the NEXT field of the new node contains the
address of the first node which is denoted by START.
In this section, we will discuss how a node is deleted from an already existing circular linked list.
We will take two cases and then see how deletion is done in each case. Rest of the cases of
deletion is same as that given for singly linked lists.
Case 1: The first node is deleted.
Case 2: The last node is deleted
Consider the circular linked list shown in Fig. When we want to delete a node from the
beginning of the list, we check if the linked list exists or not. If START = NULL, then it signifies
that there are no nodes in the list and the control is transferred to the last statement of the
algorithm. However, if there are nodes in the linked list, then we use a pointer variable PTR
which will be used to traverse the list to ultimately reach the last node. We change the next
pointer of the last node to point to the second node of the circular linked list. In Step 6, the
memory occupied by the first node is freed. Finally, the second node now becomes the first node
of the list and its address is stored in the pointer variable START.
Consider the circular linked list shown in Fig. Suppose we want to delete the last node from the
linked list, we take a pointer variable PTR and initialize it with START. That is, PTR now points
to the first node of the linked list. We take another pointer variable PREPTR such that PREPTR
always points to one node before PTR. Once we reach the last node and the second last node, we
set the next pointer of the second last node to START, so that it now becomes the (new) last
node of the linked list. The memory of the previous last node is freed and returned to the free
pool.
It is used in the Operating system to share time for different users, generally uses a
Round-Robin time-sharing mechanism.
Multiplayer games use a circular list to swap between players in a loop.
Implementation of Advanced data structures like Fibonacci Heap
The browser cache which allows you to hit the BACK button
Undo functionality in Photoshop or Word