0% found this document useful (0 votes)
10 views45 pages

Unit 3 Notes

Uploaded by

Benitta Mary
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
10 views45 pages

Unit 3 Notes

Uploaded by

Benitta Mary
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 45

LINEAR DATA STRUCTURES

Abstract Data Types (ADTs) – List ADT – Array-Based Implementation – Linked List
– Doubly-Linked Lists – Circular Linked List – Stack ADT – Implementation of Stack –
Applications – Queue ADT – Priority Queues – Queue Implementation – Applications.

1.1 ABSTRACT DATA TYPES (ADTS)


 An abstract data type is an abstraction of a data structure that provides only the
interface to which the data structure must adhere. The interface does not give
any specific details about something should be implemented or in what
programming language.
 In other words, we can say that abstract data types are the entities that are
definitions of data and operations but do not have implementation details. In this
case, we know the data that we are storing and the operations that can be
performed on the data, but we don't know about the implementation details.

1.1.1 Abstract data type model


Abstraction: It is a technique of hiding the internal details from the user and only
showing the necessary details to the user.
Encapsulation: It is a technique of combining the data and the member function in a
single unit is known as encapsulation.
There are two types of models in the ADT model, i.e., the public function and
the private function. The ADT model also contains the data structures that we are using
in a program. In this model, first encapsulation is performed, i.e., all the data is wrapped
in a single unit, i.e., ADT.

Abstract Data Type Model


The abstract or logical view of the integer array can be stated as:
 It stores a set of elements of integer type.
 It reads the elements by position, i.e., index.
 It modifies the elements by index
 It performs sorting
3.2 LIST ADT
 The list can be defined as an abstract data type in which the elements are stored
in an ordered manner for easier and efficient retrieval of the elements. List Data
Structure allows repetition that means a single piece of data can occur more than
once in a list.
 In the case of multiple entries of the same data, each entry of that repeating data
is considered as a distinct item or entry. It is very much similar to the array but
the major difference between the array and the list data structure is that array
stores only homogenous data in them whereas the list (in some programming
languages) can store heterogeneous data items in its object. List Data Structure
is also known as a sequence.
For example,
numbers = [ 1, 2, 3, 4, 5]
 In this example, 'numbers' is the name of the List Data Structure object and it
has five items stored in it. In the object named numbers, we have stored all the
elements of numeric type. In the list, the indexing starts from zero, which means
if we want to access or retrieve the first element of this list then we need to use
index zero and similarly whenever we want to access any element from this list
named numbers. In other words, we can say that element 1 is on the index 0 and
element 2 is on index 1 and similarly for further all elements.
Mixed_data = [205, ‘Mathu’, 8.56]
 In this second example, mixed_data is the name of the list object that stores the
data of different types. In the mixed_data list, we have stored data of three types,
first one is the integer type which is id '205', after the integer data we have
stored a string type data having the value ‘Mathu’ stored at index 1 and at last
the index value 2, we have stored a float type data having the value '8.56'.

3.3 ARRAY-BASED IMPLEMENTATION


 Arrays are defined as the collection of similar types of data items stored at
contiguous memory locations.
 It is one of the simplest data structures where each data element can be
randomly accessed by using its index number.
 They are the derived data types in C programming that can store the primitive
type of data such as int, char, double, float, etc.
 For example, if we want to store the marks of a student in 6 subjects, then we
don't need to define a different variable for the marks in different subjects.
Instead, we can define an array that can store the marks in each subject at the
contiguous memory locations.

3.3.1 Properties of array


 Each element in an array is of the same data type and carries the same size that
is 4 bytes.
 Elements in the array are stored at contiguous memory locations from which the
first element is stored at the smallest memory location.
 Elements of the array can be randomly accessed since we can calculate the
address of each element of the array with the given base address and the size of
the data element.

3.3.2 Representation of an array


 Array can be represented in various ways in different programming languages.
As an illustration, let's see the declaration of array in C language

Illustration of an Array
As per the above illustration of array, there are some of the following important points -
 Index starts with 0.
 The array's length is 10, which means we can store 10 elements.
 Each element in the array can be accessed via its index.

3.3.3 Memory allocation of an array


 Data elements of an array are stored at contiguous locations in the main
memory. The name of the array represents the base address or the address of the
first element in the main memory. Each element of the array is represented by
proper indexing.
 We can define the indexing of an array in the below ways
 0 (zero-based indexing): The first element of the array will be arr[0].
 1 (one-based indexing): The first element of the array will be arr[1].
 n (n - based indexing): The first element of the array can reside at any
random index number
 shows the memory allocation of an array arr of size 5. The array follows a 0-
based indexing approach. The base address of the array is 100 bytes. It is the
address of arr[0]. Here, the size of the data type used is 4 bytes; therefore, each
element will take 4 bytes in the memory.

Fig. 3.3: Memory allocation of an array

3.3.4 Access an element from the array


The information given below are required to access any random element from the array
 Base Address of the array.
 Size of an element in bytes.
 Type of indexing, array follows.
The formula to calculate the address to access an array element
Byte address of element A[i] = base address + size * ( i - first index)
Here, size represents the memory taken by the primitive data types. As an instance, int
takes 2 bytes, float takes 4 bytes of memory space in C programming.
Example 3.2
Suppose an array, A[-10.......+2 ] having Base address (BA) = 999 and size of an
element = 2 bytes, find the location of A[-1].
L(A[-1]) = 999 + 2 x [(-1) - (-10)]
= 999 + 18
= 1017

3.3.5 Basic operations of an Array


Basic operations supported in the array
 Traversal - This operation is used to print the elements of the array.
 Insertion - It is used to add an element at a particular index.
 Deletion - It is used to delete an element from a particular index.
 Search - It is used to search an element using the given index or by the value.
 Update - It updates an element at a particular index.

3.3.6 Complexity of Array operations


Time and space complexity of various array operations are described below.
Time Complexity
Operation Average Case Worst Case
Access O(1) O(1)
Search O(n) O(n)
Insertion O(n) O(n)
Deletion O(n) O(n)

Space Complexity
In array, space complexity for worst case is O(n).

3.4 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
3.4.1 Representation of a Linked list
 Linked list can be represented as the connection of nodes in which each node
points to the next node of the list. The representation of the linked list is shown
below.

Representation of Linked List


3.4.2 Declare a linked list
 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.,
 Simple variable,
 Pointer variable.
We can declare the linked list by using the user-defined data type structure.
The declaration of linked list is given as follows
struct node
{
int data;
struct node *next;
}
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.

3.4.3 Types of Linked list


Linked list is classified into the following types
 Singly-Linked List
 Doubly Linked List
 Circular Singly Linked List
 Circular Doubly Linked List

3.4.3.1 Singly-Linked List


 Singly linked list can be defined as the collection of an ordered set of elements.
 A node in the singly linked list consists of two parts: data part and link part.
 Data part of the node stores actual information that is to be represented by the
node
 Link part of the node stores the address of its immediate successor.
3.4.3.2 Doubly Linked List
 Doubly linked list is a complex type of linked list
 Here, a node contains a pointer to the previous as well as the next node in the
sequence.
 Therefore, in a doubly-linked list, a node consists of three parts:
 Node data,
 Pointer to the next node in sequence (next pointer), and
 Pointer to the previous node (previous pointer).

3.4.3.3 Circular Singly Linked List


 In a circular singly linked list, the last node of the list contains a pointer to the
first node of the list.
 We can have circular singly linked list as well as circular doubly linked list.

3.4.3.4 Circular Doubly Linked List


 Circular doubly linked list is a more complex type of data structure.
 Here a node contains pointers to its previous node as well as the next node.
 Circular doubly linked list doesn't contain NULL in any of the nodes.
 The last node of the list contains the address of the first node of the list.
 The first node of the list also contains the address of the last node in its previous
pointer.
3.4.4 Operations performed on Linked list
 Insertion - This operation is performed to add an element into the list.
 Deletion - It is performed to delete an operation from the list.
 Display - It is performed to display the elements of the list.
 Search - It is performed to search an element from the list using the given key.
3.4.5 Complexity of Linked list
1. Time Complexity
Operation Average Case Worst Case
Insertion O(1) O(1)
Deletion O(1) O(1)
Search O(n) O(n)

2. Space Complexity
Operation Space complexity
Insertion O(n)
Deletion O(n)
Search O(n)

3.5 DOUBLY LINKED LIST


 Doubly linked list is a complex type of linked list
 Here, a node contains a pointer to the previous as well as the next node in the
sequence.
 Therefore, in a doubly-linked list, a node consists of three parts:
 Node data,
 Pointer to the next node in sequence (next pointer), and
 Pointer to the previous node (previous
pointer). A sample node in a doubly linked list is shown in
Fig. 3.5
Sample node in a doubly linked list
A doubly linked list containing three nodes having numbers from 1 to 3 in their
data part, is shown in Fig 3.6

Doubly Linked List


In C, structure of a node in doubly linked list can be given as:
struct node
{
struct node *prev;
int data;
struct node *next;
}
 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.

3.5.1 Memory Representation of a doubly linked list


 Memory Representation of a doubly linked list is shown in Fig. 3.7. Generally,
doubly linked list consumes more space for every node and therefore, causes
more expansive basic operations such as insertion and deletion. However, we
can easily manipulate the elements of the list since the list maintains pointers in
both the directions (forward and backward).
 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.

Memory Representation of a doubly linked list

3.5.2 Operations on doubly linked list


Table 3.1 describes all the operations performed on Doubly Linked List
Table 3.1: Operations on Doubly Linked List
Sl. No. Operation Description
1. Insertion at beginning Adding the node into the linked list at beginning.
2. Insertion at end Adding the node into the linked list to the end.
3. Insertion after Adding the node into the linked list after the
specified node specified node.
4. Deletion at beginning Removing the node from beginning of the list
5. Deletion at the end Removing the node from end of the list.
6. Deletion of the node Removing the node which is present just after the
having given data node containing the given data.
7. Searching Comparing each node data with the item to be
searched and return the location of the item in the
list if the item found else return null
8. Traversing Visiting each node of the list at least once in
order to perform some specific operation like
searching, sorting, display, etc.

3.5.2.1 Insertion at beginning


 There are two scenarios of inserting any element into doubly linked list. Either
the list is empty or it contains at least one element.
The following steps to be performed for insert a node in doubly linked list at beginning.
 Allocate the space for the new node in the memory.
 In the second scenario, the condition head == NULL become false and the node
will be inserted in beginning.
 The next pointer of the node will point to the existing head pointer of the node.
 The prev pointer of the existing head will point to the new node being inserted.
 Since, the node being inserted is the first node of the list and therefore it must
contain NULL in its prev pointer.
 Hence assign null to its previous part and make the head point to this node.
Algorithm 3.1
Step 1: IF ptr = NULL
Write OVERFLOW
Go to Step 9
[END OF IF]
Step 2: SET NEW_NODE = ptr
Step 3: SET ptr = ptr -> NEXT
Step 4: SET NEW_NODE -> DATA = VAL
Step 5: SET NEW_NODE -> PREV = NULL
Step 6: SET NEW_NODE -> NEXT = START
Step 7: SET head -> PREV = NEW_NODE
Step 8: SET head = NEW_NODE
Step 9: EXIT

Insertion into Doubly Linked List at the beginning

3.5.2.2 Insertion at end


 To insert a node in doubly linked list at the end, make sure whether the list is
empty or it contains any element. Use the following steps in order to insert the
node in doubly linked list at the end.
 Allocate the memory for the new node. Make the pointer ptr point to the new
node being inserted.
 Check whether the list is empty or not. The list is empty if the condition head ==
NULL holds.
 For this reason, we have to traverse the whole list in order to reach the last node
of the list. Initialize the pointer temp to head and traverse the list by using this
pointer.
 Make the next pointer of temp point to the new node being inserted i.e. ptr.
 Make the previous pointer of the node ptr point to the existing last node of the list
i.e. temp.
Algorithm 3.2
Step 1: IF PTR = NULL
Write
OVERFLOW Go to
Step 11 [END OF
IF]
Step 2: SET NEW_NODE = PTR
Step 3: SET PTR = PTR -> NEXT
Step 4: SET NEW_NODE -> DATA = VAL
Step 5: SET NEW_NODE -> NEXT = NULL
Step 6: SET TEMP = START
Step 7: Repeat Step 8 while TEMP -> NEXT != NULL
Step 8: SET TEMP = TEMP -> NEXT
[END OF LOOP]
Step 9: SET TEMP -> NEXT = NEW_NODE
Step 10C: SET NEW_NODE -> PREV = TEMP
Step 11: EXIT

Insertion into Doubly Linked List at the end


3.5.2.3 Insertion after specified node
To insert a node after the specified node in the list, we need to skip the required
number of nodes in order to reach the mentioned node and then make the pointer
adjustments as required.
The following steps are used for this purpose.
 Allocate the memory for the new node.
 Traverse the list by using the pointer temp to skip the required number of nodes
in order to reach the specified node.
 The temp would point to the specified node at the end of the for loop. The new
node needs to be inserted after this node. Make the next pointer of ptr point to
the next node of temp.
 Make the prev of the new node ptr point to temp.
 Make the next pointer of temp point to the new node ptr.
 Make the previous pointer of the next node of temp point to the new node.
Algorithm 3.3
Step 1: IF PTR = NULL
Write OVERFLOW
Go to Step 15
[END OF IF]
Step 2: SET NEW_NODE = PTR
Step 3: SET PTR = PTR -> NEXT
Step 4: SET NEW_NODE -> DATA = VAL
Step 5: SET TEMP = START
Step 6: SET I = 0
Step 7: REPEAT 8 to 10 until I
Step 8: SET TEMP = TEMP -> NEXT
STEP 9: IF TEMP = NULL
STEP 10: WRITE "LESS THAN DESIRED NO. OF ELEMENTS"
GOTO STEP 15
[END OF IF] [END OF LOOP]
Step 11: SET NEW_NODE -> NEXT = TEMP -> NEXT
Step 12: SET NEW_NODE -> PREV = TEMP
Step 13 : SET TEMP -> NEXT = NEW_NODE
Step 14: SET TEMP -> NEXT -> PREV = NEW_NODE
Step 15: EXIT
Insertion of Doubly Linked List after specified node

3.5.2.4 Deletion at beginning


 Deletion in doubly linked list at the beginning is the simplest operation.
 Just need to copy the head pointer to pointer ptr and shift the head pointer to
its next.
 Make the prev of this new head node point to NULL.
 Now free the pointer ptr by using the free function.
Algorithm 3.4
STEP 1: IF HEAD = NULL
WRITE UNDERFLOW
GOTO STEP 6
STEP 2: SET PTR = HEAD
STEP 3: SET HEAD = HEAD →
NEXT STEP 4: SET HEAD → PREV =
NULL STEP 5: FREE PTR
STEP 6: EXIT

Deletion in Doubly Linked List from beginning

3.5.2.5 Deletion at the end


Deletion of the last node in a doubly linked list needs traversing the list in order
to reach the last node of the list and then make pointer adjustments at that position. To
delete the last node of the list, following steps are performed.
 If the list is already empty then the condition head == NULL will become true
and therefore the operation cannot be carried on.
 If there is only one node in the list then the condition head → next == NULL
become true. In this case, we just need to assign the head of the list to NULL
and free head in order to completely delete the list.
 The ptr would point to the last node of the ist at the end of the for loop. Just
make the next pointer of the previous node of ptr to NULL.
 Free the pointer as this the node which is to be deleted.
Algorithm 3.5:
Step 1: IF HEAD = NULL
Write UNDERFLOW
Go to Step 7
[END OF IF]
Step 2: SET TEMP = HEAD
Step 3: REPEAT STEP 4 WHILE TEMP->NEXT != NULL
Step 4: SET TEMP = TEMP->NEXT

[END OF LOOP]

Step 5: SET TEMP ->PREV-> NEXT = NULL


Step 6: FREE TEMP
Step 7: EXIT

Deletion in Doubly Linked List at the end

3.5.2.6 Deletion of the node having given data


 Copy the head pointer into a temporary pointer temp.
 Traverse the list until we find the desired data value.
 Check if this is the last node of the list. If it is so then we can't perform deletion.
 Check if the node which is to be deleted, is the last node of the list, if it so then
we have to make the next pointer of this node point to null so that it can be the
new last node of the list.
 Otherwise, make the pointer ptr point to the node which is to be deleted.
 Make the next of temp point to the next of ptr.
 Make the previous of next node of ptr point to temp. free the ptr.
Algorithm 3.6
Step 1: IF HEAD = NULL
Write UNDERFLOW
Go to Step 9
[END OF IF]
Step 2: SET TEMP = HEAD
Step 3: Repeat Step 4 while TEMP -> DATA != ITEM
Step 4: SET TEMP = TEMP -> NEXT
[END OF LOOP]
Step 5: SET PTR = TEMP -> NEXT
Step 6: SET TEMP -> NEXT = PTR -> NEXT
Step 7: SET PTR -> NEXT -> PREV = TEMP
Step 8: FREE PTR
Step 9: EXIT

Deletion of a specified node in Doubly Linked List at the end

3.5.2.7 Searching for a specific node


To search for a specific element in the list, traverse the list in order. The
following operations to be performed in order to search a specific operation.
 Copy head pointer into a temporary pointer variable ptr
 Traverse the list until the pointer ptr becomes null. Keep shifting pointer to its
next and increasing i by +1.
 Compare each element of the list with the item which is to be searched.
 If the item matched with any node value then the location of that value I will be
returned from the function else NULL is returned.
Algorithm 3.7
Step 1: IF HEAD == NULL
WRITE "UNDERFLOW"
GOTO STEP 8
[END OF IF]
Step 2: Set PTR = HEAD
Step 3: Set i = 0
Step 4: Repeat step 5 to 7 while PTR != NULL
Step 5: IF PTR → data = item
return i
[END OF
IF]
Step 6: i = i + 1
Step 7: PTR = PTR → next
Step 8: Exit
3.5.2.8 Traversing in doubly linked list
Traversing is the most common operation in case of each data structure. For this purpose,
 Copy the head pointer in any of the temporary pointer ptr.
 Traverse through the list by using while loop.
 Keep shifting value of pointer variable ptr until we find the last node.
 The last node contains null in its next part.
Algorithm 3.8
Step 1: IF HEAD == NULL
WRITE "UNDERFLOW"
GOTO STEP 6
[END OF IF]
Step 2: Set PTR = HEAD
Step 3: Repeat step 4 and 5 while PTR != NULL
Step 4: Write PTR → data
Step 5: PTR = PTR → next
Step 6: Exit

3.6 CIRCULAR LINKED LIST


 In a circular singly linked list, the last node of the list contains a pointer to the
first node of the list.
 We can have circular singly linked list as well as circular doubly linked list.
 We traverse a circular singly linked list until we reach the same node where we
started.
 The circular singly liked list has no beginning and no ending.
 There is no null value present in the next part of any of the nodes.
 Circular linked list are mostly used in task maintenance in operating systems. Fig.
3.14 shows a circular singly linked list.

Circular Singly Linked List.


3.6.1 Memory Representation of circular linked list
 Fig 3.15 shows the memory representation of a circular linked list containing
marks of a student in 4 subjects. However, the image shows a glimpse of how
the circular list is being stored in the memory. The start or head of the list is
pointing to the element with the index 1 and containing 13 marks in the data part
and 4 in
the next part. Which means that it is linked with the node that is being stored at
4th index of the list.
 However, due to the fact that we are considering circular linked list in the
memory therefore the last node of the list contains the address of the first node
of the list.

Memory Representation of Circular Linked List

3.6.2 Operations on Circular Singly linked list


Table 3.2 describes all the operations performed on a Doubly Linked List
Table 3.2: Operations on Doubly Linked List
Sl. No. Operation Description
Insertion at beginning Adding a node into circular singly linked list at
1.
the beginning.
Insertion at end Adding a node into circular singly linked list at
2.
the end.
Deletion at beginning Removing the node from circular singly linked
3.
list at the beginning.
Searching Compare each element of the node with the
4. given item and return the location at which the
item is present in the list otherwise return null.
Traversing Visiting each element of the list at least once in
5.
order to perform some specific operation.

3.6.2.1 Insertion at the beginning


 There are two scenario in which a node can be inserted in circular singly linked
list at beginning. Either the node will be inserted in an empty list or the node is
to be inserted in an already filled list.
 Firstly, allocate the memory space for the new node by using the malloc method
of C language.
 In the first scenario, the condition head == NULL will be true. Since, the list in
which, we are inserting the node is a circular singly linked list, therefore the
only node of the list (which is just inserted into the list) will point to itself only.
 Also need to make the head pointer point to this node.
 In the second scenario, the condition head == NULL will become false which
means that the list contains at least one node.
 In this case, traverse the list in order to reach the last node of the list.
Step 1: IF PTR = NULL
Write OVERFLOW
Go to Step 11
[END OF IF]
Step 2: SET NEW_NODE = PTR
Step 3: SET PTR = PTR -> NEXT
Step 4: SET NEW_NODE -> DATA = VAL
Step 5: SET TEMP = HEAD
Step 6: Repeat Step 8 while TEMP -> NEXT != HEAD
Step 7: SET TEMP = TEMP -> NEXT

[END OF LOOP]
Step 8: SET NEW_NODE -> NEXT = HEAD
Step 9: SET TEMP → NEXT = NEW_NODE
Step 10: SET HEAD = NEW_NODE
Step 11: EXIT
Insertion into a Circular Linked List at the beginning

3.6.2.2 Insertion at the end


 Allocate the memory space for the new node by using the malloc method of C
language.
 In the first scenario, the condition head == NULL will be true.
 Also make the head pointer point to this node.
 In the second scenario, the condition head == NULL will become false which
means that the list contains at least one node.
 In this case, traverse the list in order to reach the last node of the list.
 At the end of the loop, the pointer temp would point to the last node of the list.
 The existing last node i.e. temp must point to the new node ptr
Algorithm 3.10
Step 1: IF PTR = NULL
Write OVERFLOW
Go to Step 1 [END OF IF]
Step 2: SET NEW_NODE = PTR
Step 3: SET PTR = PTR -> NEXT
Step 4: SET NEW_NODE -> DATA = VAL
Step 5: SET NEW_NODE -> NEXT = HEAD
Step 6: SET TEMP = HEAD
Step 7: Repeat Step 8 while TEMP -> NEXT != HEAD
Step 8: SET TEMP = TEMP -> NEXT
[END OF LOOP]
Step 9: SET TEMP -> NEXT = NEW_NODE
Step 10: EXIT
Insertion into a Circular Linked List at the end

3.6.2.3 Deletion at the beginning


In order to delete a node in circular singly linked list, we need to make a few
pointer adjustments. There are three scenarios of deleting a node from circular singly
linked list at beginning.
 Scenario 1: (The list is Empty) - If the list is empty then the condition head ==
NULL will become true, in this case, just to print underflow on the screen and
make exit.
 Scenario 2: (The list contains single node) - If the list contains single node then,
the condition head → next == head will become true. In this case, delete the
entire list and make the head pointer free.
 Scenario 3: (The list contains more than one node) - If the list contains more
than one node then, in that case, traverse the list by using the pointer ptr to reach
the last node of the list.
 At the end of the loop, the pointer ptr point to the last node of the list.
 The last node of the list will point to the next of the head node.
 Now, free the head pointer by using the free() method.
 Make the node pointed by the next of the last node, the new head of the list.
Algorithm 3.11
Step 1: IF HEAD = NULL
Write UNDERFLOW
Go to Step 8
[END OF IF]
Step 2: SET PTR = HEAD
Step 3: Repeat Step 4 while PTR → NEXT != HEAD
Step 4: SET PTR = PTR → next
[END OF LOOP]
Step 5: SET PTR → NEXT = HEAD → NEXT
Step 6: FREE HEAD
Step 7: SET HEAD = PTR → NEXT
Step 8: EXIT

Deletion in a Circular Linked List at beginning


3.6.2.4 Deletion at the end
 Scenario 1 (the list is empty) - If the list is empty then the condition head ==
NULL will become true, in this case, just to print underflow on the screen and
make exit.
 Scenario 2(the list contains single element) - If the list contains single node then,
the condition head → next == head will become true. In this case, delete the
entire list and make the head pointer free.
 Scenario 3(the list contains more than one element) - If the list contains more
than one element, then in order to delete the last element, reach the last node.
Also keep track of the second last node of the list. For this purpose, the two
pointers ptr and preptr are defined.
Algorithm 3.12
Step 1: IF HEAD = NULL
Write UNDERFLOW
Go to Step 8
[END OF IF]
Step 2: SET PTR = HEAD
Step 3: Repeat Steps 4 and 5 while PTR -> NEXT != HEAD
Step 4: SET PREPTR = PTR
Step 5: SET PTR = PTR -> NEXT
[END OF LOOP]
Step 6: SET PREPTR -> NEXT = HEAD
Step 7: FREE PTR
Step 8: EXIT

Deletion in a Circular Linked List at the end

3.6.2.5 Searching
 Searching in circular singly linked list needs traversing across the list.
 The item which is to be searched in the list is matched with each node data of
the list once.
 If the match found then the location of that item is returned otherwise -1 is
returned.
Algorithm 3.13
STEP 1: SET PTR = HEAD
STEP 2: Set I = 0
STEP 3: IF PTR = NULL
WRITE "EMPTY LIST"
GOTO STEP 8
END OF IF
STEP 4: IF HEAD → DATA = ITEM
WRITE i+1 RETURN [END OF IF]
STEP 5: REPEAT STEP 5 TO 7 UNTIL PTR->next != head
STEP 6: if ptr → data = item
write i+1
RETURN
End of IF
STEP 7: I = I + 1
STEP 8: PTR = PTR → NEXT
[END OF LOOP]
STEP 9: EXIT

3.6.2.5 Searching
 Traversing in circular singly linked list can be done through a loop.
 Initialize the temporary pointer variable temp to head pointer and run the
while loop until the next pointer of temp becomes head.
Algorithm 3.14
STEP 1: SET PTR = HEAD
STEP 2: IF PTR = NULL
WRITE "EMPTY LIST"
GOTO STEP 8
END OF IF
STEP 4: REPEAT STEP 5 AND 6 UNTIL PTR → NEXT != HEAD
STEP 5: PRINT PTR → DATA
STEP 6: PTR = PTR → NEXT
[END OF LOOP]
STEP 7: PRINT PTR→ DATA
STEP 8: EXIT
3.7 STACK ADT
 A Stack is a linear data structure that follows the LIFO (Last-In-First-Out)
principle.
 A Stack is an abstract data type with a pre-defined capacity, which means that it
can store the elements of a limited size.
 Stack has one end, whereas the Queue has two ends (front and rear).
 It contains only one pointer top pointer pointing to the topmost element of the
stack.

Working principle of a Stack

3.7.1 Operations on Stack


The following are some common operations implemented on the stack:
 push(): When we insert an element in a stack then the operation is known as a
push. If the stack is full then the overflow condition occurs.
 pop(): When we delete an element from the stack, the operation is known as a
pop. If the stack is empty means that no element exists in the stack, this state is
known as an underflow state.
 isEmpty(): It determines whether the stack is empty or not.
 isFull(): It determines whether the stack is full or not.'
 peek(): It returns the element at the given position.
 count(): It returns the total number of elements available in a stack.
 change(): It changes the element at the given position.
 display(): It prints all the elements available in the stack
3.7.1.1 PUSH operation
 Before inserting an element in a stack, we check whether the stack is full.
 If we try to insert the element in a stack, and the stack is full, then the overflow
condition occurs.
 When we initialize a stack, we set the value of top as -1 to check that the stack is
empty.
 When the new element is pushed in a stack, first, the value of the top gets
incremented, i.e., top=top+1, and the element will be placed at the new position
of the top.
 The elements will be inserted until we reach the max size of the stack.

PUSH Operation in Stack

3.7.1.2 POP operation


 Before deleting the element from the stack, we check whether the stack is empty.
 If we try to delete the element from the empty stack, then the underflow
condition occurs.
 If the stack is not empty, we first access the element which is pointed by the top
 Once the pop operation is performed, the top is decremented by 1, i.e., top=top-1.
POP Operation in Stack

3.7.2 Applications of Stack


 Balancing of symbols: Stack is used for balancing a symbol.
 String reversal: Stack is also used for reversing a string
 UNDO/REDO: It can also be used for performing UNDO/REDO operations.
 Recursion: The recursion means that the function is calling itself again.
 DFS(Depth First Search): This search is implemented on a Graph, and Graph
uses the stack data structure.
 Backtracking: In order to come at the beginning of the path to create a new
path, use the stack data structure
 Expression conversion: Stack can also be used for expression conversion.
 Infix to prefix
 Infix to postfix
 Prefix to infix
 Prefix to postfix
 Postfix to infix

3.8 IMPLEMENTATION OF STACK


 Stack can be easily implemented using an Array or a Linked List. Arrays are
quick, but are limited in size and Linked List requires overhead to allocate, link,
unlink, and deallocate, but is not limited in size.

3.8.1 Array implementation of Stack


 In array implementation, the stack is formed by using the array. All the
operations regarding the stack are performed using arrays. Let’s see how each
operation can be implemented on the stack using array data structure.

3.8.1.1 Adding an element onto the stack (push operation)


 Adding an element into the top of the stack is referred to as push operation. Push
operation involves following two steps.
1. Increment the variable Top so that it can now refere to the next memory
location.
2. Add element at the position of incremented top. This is referred to as adding
new element at the top of the stack.
 Stack is overflown when we try to insert an element into a completely filled
stack therefore, our main function must always avoid stack overflow condition.
Algorithm
begin
if top = n then stack full
top = top + 1
stack (top) : = item;
end
Time Complexity: O (1)

3.8.1.1.1 Implementation of push algorithm in C language


void push (int val,int n) //n is size of the stack
{
if (top == n ) printf("\
n Overflow"); else
{
top = top +1;
stack[top] = val;

}
}

3.8.1.2 Deletion of an element from a stack (Pop operation)


 Deletion of an element from the top of the stack is called pop operation.
 The value of the variable top will be incremented by 1 whenever an item is
deleted from the stack.
 The top most element of the stack is stored in another variable and then the top
is decremented by 1.
 The operation returns the deleted value that was stored in another variable as the
result.
 The underflow condition occurs when we try to delete an element from an
already empty stack.
Algorithm 3.16
begin
if top = 0 then stack empty;
item := stack(top);
top = top - 1;
end;
Time Complexity: O (1)

3.8.1.2.1 Implementation of POP algorithm using C language


int pop ()
{
if(top == -1)
{
printf("Underflow");
return 0;
}
else
{
return stack[top - - ];
}
}

3.8.1.3 Visiting each element of the stack (Peek operation)


 Peek operation involves returning the element which is present at the top of the
stack without deleting it.
 Underflow condition can occur if we try to return the top element in an already
empty stack.
Algorithm 3.17
PEEK (STACK, TOP)
Begin
if top = -1 then stack empty
item = stack[top]
return item
End
Time complexity: O(n)
3.8.2 Linked list implementation of stack
 Linked list allocates the memory dynamically. However, time complexity in
both the scenario is same for all the operations i.e. push, pop and peek.
 In linked list implementation of stack, the nodes are maintained non-
contiguously in the memory.
 Each node contains a pointer to its immediate successor node in the stack.
 Stack is said to be overflown if the space left in the memory heap is not enough
to create a node.
 The top most node in the stack always contains null in its address field.
Linked List implementation of Stack
3.8.2.1 Adding a node to the stack (Push operation)
 Adding a node to the stack is referred to as push operation. Pushing an element
to a stack in linked list implementation is different from that of an array
implementation. In order to push an element onto the stack, the following steps
are involved.
 Create a node first and allocate memory to it.
 If the list is empty then the item is to be pushed as the start node of the list.
This includes assigning value to the data part of the node and assign null to
the address part of the node.

Adding new Node to Stack


3.8.2.2 Deleting a node from the stack (POP operation)
 Deleting a node from the top of stack is referred to as pop operation. Deleting a
node from the linked list implementation of stack is different from that in the
array implementation.
 In order to pop an element from the stack, do the following steps:
 Check for the underflow condition: The underflow condition occurs when
we try to pop from an already empty stack. The stack will be empty if the
head pointer of the list points to null.
 Adjust the head pointer accordingly: In stack, the elements are popped
only from one end, therefore, the value stored in the head pointer must be
deleted and the node must be freed. The next node of the head node now
becomes the head node.
Time Complexity: O (n)

3.9 APPLICATIONS OF STACK


 A Stack is a widely used linear data structure in modern computers in which
insertions and deletions of an element can occur only at one end, i.e., top of the
Stack. It is used in all those applications in which data must be stored and
retrieved in the last.
 Following are the various Applications of Stack in Data Structure:
 Evaluation of Arithmetic Expressions
 Balancing Symbols
 Processing Function Calls
 Backtracking
 Reverse a Data
3.9.1 Evaluation of Arithmetic Expressions
 A stack is a very effective data structure for evaluating arithmetic expressions in
programming languages. An arithmetic expression consists of operands and
operators.
 In addition to operands and operators, the arithmetic expression may also
include parenthesis like "left parenthesis" and "right parenthesis".
Example A + (B - C)
To evaluate the expressions, one needs to be aware of the standard precedence
rules for arithmetic expression. The precedence rules for the five basic arithmetic
operators are:
Operators Associativity Precedence
^ exponentiation Right to left Highest followed by
*Multiplication and /division
*Multiplication, Left to right Highest followed by + addition
/division and - subtraction
+ addition, - Left to right lowest
subtraction

Evaluation of Arithmetic Expression requires two steps:


 First, convert the given expression into special notation.
 Evaluate the expression in this new notation.
Notations for Arithmetic Expression
There are three notations to represent an arithmetic expression:
 Infix Notation
 Prefix Notation
 Postfix Notation

3.9.1.1 Infix Notation


The infix notation is a convenient way of writing an expression in which each
operator is placed between the operands. Infix expressions can be parenthesized or un
parenthesized depending upon the problem requirement.
Example A + B, (C - D) etc.
All these expressions are in infix notation because the operator comes between
the operands.

3.9.1.2 Prefix Notation


The prefix notation places the operator before the operands. This notation was
introduced by the Polish mathematician and hence often referred to as polish notation.
Example + A B, -CD etc.
All these expressions are in prefix notation because the operator comes before the
operands.

3.9.1.3 Postfix Notation


The postfix notation places the operator after the operands. This notation is just
the reverse of Polish notation and also known as Reverse Polish notation.
Example AB +, CD+, etc.
All these expressions are in postfix notation because the operator comes after the
operands.
Table 3.3 illustrates the conversion of Arithmetic Expression into various Notations
Table Conversion of Arithmetic Expression into various Notations
Infix Notation Prefix Notation Postfix Notation
A*B *AB AB*
(A+B)/C /+ ABC AB+C/
(A*B) + (D-C) +*AB - DC AB*DC-+
In the above example, the only change from the postfix expression is that the
operator is placed before the operands rather than between the operands.
Evaluating Postfix expression
 Stack is the ideal data structure to evaluate the postfix expression because the
top element is always the most recent operand. The next element on the Stack is
the second most recent operand to be operated on.
 When an expression has been completely evaluated, the Stack must contain
exactly one value.
Example
Now let us consider the following infix expression 2 * (4+3) - 5.
Its equivalent postfix expression is 2 4 3 + * 5.
The following step illustrates how this postfix expression is evaluated.

3.9.2 Backtracking
 Backtracking is used in algorithms in which there are steps along some path
(state) from some starting point to some goal. It uses recursive calling to find the
solution by building a solution step by step increasing values with time. It
removes the solutions that doesn't give rise to the solution of the problem based
on the constraints given to solve the problem.
 Let’s see how Stack is used in Backtracking in the N-Queens Problem
 For the N-Queens problem, one way we can do this is given by the following:
 For each row, place a queen in the first valid position (column), and then
move to the next row
 If one can successfully place a queen in the last row, then a solution is found.
Now backtrack to find the next solution
 Two examples of this are shown below:

 Starting with a queen in the first row, first column (represented by a stack
containing just "0"), we search left to right for a valid position to place another
queen in the next available row.
 If we find a valid position in this row, we push this position (i.e., the column
number) to the stack and start again on the next row.
 Putting all this into pseudo-code form, we have the following algorithm.
Create empty stack and set current position to 0
Repeat {
loop from current position to the last position until valid position found //current
row
if there is a valid position {
push the position to stack, set current position to 0 // move to next row
}
if there is no valid position {
if stack is empty, break // stop search
else pop stack, set current position to next position // backtrack to previous
row
}
if stack has size N { // a solution is found
pop stack, set current position to next position // backtrack to find next solution
}
}

3.10 QUEUE ADT


 A queue can be defined as an ordered list which enables insert operations to be
performed at one end called REAR and delete operations to be performed at
another end called FRONT.
 Queue is referred to be as First In First Out list. i.e., the data item stored first
will be accessed first.
 For example, people waiting in line for a rail ticket form a queue.

Data Structure of Queue


3.10.1 Applications of Queue
Due to the fact that queue performs actions on first in first out basis which is quite
fair for the ordering of actions. There are various applications of queues discussed as
below.
 Queues are widely used as waiting lists for a single shared resource like printer,
disk, CPU.
 Queues are used in asynchronous transfer of data (where data is not being
transferred at the same rate between two processes) for eg. pipes, file IO,
sockets.
 Queues are used as buffers in most of the applications like MP3 media player,
CD player, etc.
 Queue are used to maintain the play list in media players in order to add and
remove the songs from the play-list.
 Queues are used in operating systems for handling interrupts.

Basic Operations in Queue


 Enqueue operation: The term "enqueue" refers to the act of adding a new
element to a queue.
 Dequeue operation: Dequeue is the process of deleting an item from a queue.
We must delete the queue member that was put first since the queue follows the
FIFO principle. Front Operation: This works similarly to the peek operation in
stacks in that it returns the value of the first element without deleting it.
 isEmpty Operation: The isEmpty() function is used to check if the Queue is
empty or not.
 isFull Operation: The isFull() function is used to check if the Queue is full or not.

Types of Queue
 Simple Queue or Linear Queue
 Circular Queue
 Priority Queue
 Double Ended Queue (or Deque)

Fig. 3.28 Representation of Linear Queue

3.10.1.1 Circular Queue


 In Circular Queue, all the nodes are represented as circular. It is similar to the
linear Queue except that the last element of the queue is connected to the first
element. It is also known as Ring Buffer, as all the ends are connected to another
end.
 The drawback that occurs in a linear queue is overcome by using the circular
queue. If the empty space is available in a circular queue, the new element can
be added in an empty space by simply incrementing the value of rear. The main
advantage of using the circular queue is better memory utilization.

Representation of circular Queue

3.10.1.2 Priority Queue


 It is a special type of queue in which the elements are arranged based on the
priority. It is a special type of queue data structure in which every element has a
priority associated with it. Suppose some elements occur with the same priority,
they will be arranged according to the FIFO principle.
 Insertion in priority queue takes place based on the arrival, while deletion in the
priority queue occurs based on the priority. Priority queue is mainly used to
implement the CPU scheduling algorithms.

Representation of Priority Queue


There are two types of priority queue
1. Ascending priority queue - In ascending priority queue, elements can be
inserted in arbitrary order, but only smallest can be deleted first.
2. Descending priority queue - In descending priority queue, elements can be
inserted in arbitrary order, but only the largest element can be deleted first.

3.10.1.3 Deque (or, Double Ended Queue)


 In Deque or Double Ended Queue, insertion and deletion can be done from both
ends of the queue either from the front or rear. It means that we can insert and
delete elements from both front and rear ends of the queue. Deque can be used
as a palindrome checker means that if we read the string from both ends, then
the string would be the same.
 Deque can be used both as stack and queue as it allows the insertion and deletion
operations on both ends.

Representation of Double Ended Queue


There are two types of Deque
 Input restricted Deque - As the name implies, in input restricted queue,
insertion operation can be performed at only one end, while deletion can be
performed from both ends.
 Output restricted Deque - As the name implies, in output restricted queue,
deletion operation can be performed at only one end, while insertion can be
performed from both ends.

3.11 PRIORITY QUEUES


 A priority queue is an abstract data type that behaves similarly to the normal
queue except that each element has some priority, i.e., the element with the
highest priority would come first in a priority queue. The priority of the elements
in a priority queue will determine the order in which elements are removed from
the priority queue.
 The priority queue supports only comparable elements, which means that the
elements are either arranged in an ascending or descending order.
 For example, suppose we have some values like 1, 3, 4, 8, 14, 22 inserted in a
priority queue with an ordering imposed on the values is from least to the
greatest. Therefore, the 1 number would be having the highest priority while 22
will be having the lowest priority.

3.11.1 Representation of priority queue


represent the priority queue through a one-way list.
We will create the priority queue by using the list given below in which INFO
list contains the data elements, PRN list contains the priority numbers of each data
element available in the INFO list, and LINK basically contains the address of the next
node.

Let's create the priority queue step by step.


In the case of priority queue, lower priority number is considered the higher
priority, i.e., lower priority number = higher priority.
Step 1: In the list, lower priority number is 1, whose data value is 333, so it will be
inserted in the list as shown in the below diagram:
Step 2: After inserting 333, priority number 2 is having a higher priority, and data
values associated with this priority are 222 and 111. So, this data will be inserted
based on the FIFO principle; therefore 222 will be added first and then 111.
Step 3: After inserting the elements of priority 2, the next higher priority number is 4
and data elements associated with 4 priority numbers are 444, 555, 777. In this
case, elements would be inserted based on the FIFO principle; therefore, 444
will be added first, then 555, and then 777.
Step 4: After inserting the elements of priority 4, the next higher priority number is 5,
and the value associated with priority 5 is 666, so it will be inserted at the end of
the queue.

3.12 QUEUE IMPLEMENTATION


3.12.1 Array implementation of Queue
 Queue can be represented easily by using linear arrays.
 There are two variables i.e. front and rear that are implemented in the case of
every queue.
 Front and rear variables point to the position from where insertions and deletions
are performed in a queue.
 Initially, the value of front and queue is -1 which represents an empty queue.
Array representation of a queue containing 5 elements along with the respective
values of front and rear, is shown in figure 3.36.
figure, the queue will look something like following. The value of rear will become 5
while the value of front remains same.
Array representation of Queue

Queue after inserting an element


After deleting an element, the value of front will increase from -1 to 0. However,
the queue will look something like following.

Queue after deleting an element


Algorithm 3.20
Step 1: IF REAR = MAX - 1
Write OVERFLOW
Go to step
[END OF IF]
Step 2: IF FRONT = -1 and REAR = -
1 SET FRONT = REAR = 0
ELSE
SET REAR = REAR + 1
[END OF IF]
Step 3: Set QUEUE[REAR] = NUM
Step 4: EXIT
3.12.1.1 Algorithm to delete an element from the queue
 If, the value of front is -1 or value of front is greater than rear, write an underflow
message and exit.
 Otherwise, keep increasing the value of front and return the item stored at the front
end of the queue at each time.
Algorithm 3.21
Step 1: IF FRONT = -1 or FRONT > REAR Write
UNDERFLOW
ELSE
SET VAL = QUEUE[FRONT]
SET FRONT = FRONT + 1
[END OF IF]
Step 2: EXIT
}

3.13 APPLICATIONS OF QUEUE


There are several algorithms that use queues to give efficient running times. Some
simple examples of queue usage are follows.

3.13.1 Other applications


 When jobs are submitted to a printer, they are arranged in order of arrival. Thus,
essentially, jobs sent to a line printer are placed on a queue.
 Virtually every real-life line is (supposed to be) a queue. For instance, lines at
ticket counters are queues, because service is first-come first-served.
 Another example concerns computer networks. There are many network setups of
personal computers in which the disk is attached to one machine, known as the file
server. Users on other machines are given access to files on a first-come first-
served basis, so the data structure is a queue.
 Calls to large companies are generally placed on a queue when all operators are
busy.

You might also like