CS221L-DataStructure&Algorithms Lab Manual-2023 Updated
CS221L-DataStructure&Algorithms Lab Manual-2023 Updated
2023
& Algorithms
________________________________________________________________________________________
Lab Manual
Proposed By:
Engr. Amna Arooj
&
Engr. Kiran
1
CS221L - DATA STRUCTURES AND ALGORITHMS
Contents
I) OBE COURSE OUTLINES ............................................................................................ 10
II) BENCHMARK REPORT ................................................................................................ 13
III) LAB EVALUATION AND RUBRICS ......................................................................... 16
IV) WEEKLY CONTENTS BREAKDOWN ..................................................................... 18
Lab#01 Structures, Pointers, Arrays ........................................................................................ 22
1.1 C++ Structures ................................................................................................................... 22
1.1.1 Defining a Structure .................................................................................................... 22
1.1.2 Accessing Structure Members..................................................................................... 23
1.1.3 Structures as Function Arguments .............................................................................. 24
1.1.4 Pointers to Structures .................................................................................................. 25
1.1.5 The typedef Keyword.................................................................................................. 26
1.2 Introduction to Pointers in Data Structure .................................................................... 27
1.2.1 Why do We Need Pointers in Data Structure? ....................................................... 27
1.2.1.1 Control Program Flow .................................................................................... 27
1.2.1.2 secondary data structures ............................................................................... 28
1.2.1.3 Dynamic Memory Allocation ......................................................................... 28
1.2.2 How do Pointers Work in Data Structure? .................................................................. 28
C Program on Pointers ......................................................................................................... 30
1.2.3 Disadvantage Of Pointers ........................................................................................... 31
1.3 Dynamic Allocation of 2D Arrays in C++ (with code) ...................................................... 31
1.3.1 What is a Dynamic 2D Array in C++? ........................................................................ 32
1.3.2 Methods to Dynamically Allocate a 2D Array ............................................................ 32
1.3.2.1 Single Pointer Method ......................................................................................... 32
1.3.2.2 Using an Array of Pointer .................................................................................... 34
Practice Problems: ................................................................................................................... 36
Lab#02 Abstract Data types and Single Linked List ............................................................... 39
2.1 Introduction to ADT ........................................................................................................... 39
2.1.1 Abstract Data Type Model .......................................................................................... 39
2.2 Introduction to List ............................................................................................................ 40
2.2.1 Why Do We Need a Linked List? ................................................................................... 40
2.2.2 Types of Linked List ................................................................................................... 42
2.2.2.1 Singly Linked List................................................................................................ 42
2.2.2.2How Can We Declare a Linked List?.................................................................... 42
2.2.3 Operations on Linked List .......................................................................................... 43
2
CS221L - DATA STRUCTURES AND ALGORITHMS
3
CS221L - DATA STRUCTURES AND ALGORITHMS
4
CS221L - DATA STRUCTURES AND ALGORITHMS
5
CS221L - DATA STRUCTURES AND ALGORITHMS
6
CS221L - DATA STRUCTURES AND ALGORITHMS
7
CS221L - DATA STRUCTURES AND ALGORITHMS
8
CS221L - DATA STRUCTURES AND ALGORITHMS
9
CS221L - DATA STRUCTURES AND ALGORITHMS
10
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab Introduction
This lab aims to introduce the fundamental concept of data structures and to emphasize the importance of data structures in developing
and implementing efficient algorithms. Efficient data structure provides basis for a good algorithm (code). This lab focuses on the most
common data structures utilized in various computational problems. It will be taught that how these data structures work and their
implementation in C++/C. Students will practice implementing them in a few programming tasks. This will help them understand the
nuts and bolts of various data structures and enable to write efficient programs.
Lab Contents
Broadly, this lab will cover following contents: algorithm design, Abstract Data Types (ADTs), lists, stacks, queues, trees, Binary trees,
B-trees, AVL tree, hashing, sorting, graph algorithms and other recent topics in data structures.
Text books:
• Lab Manual
11
CS221L - DATA STRUCTURES AND ALGORITHMS
Administrative Instruction
▪ According to institute policy, 100% attendance is mandatory to appear in the final examination.
▪ Assignments assigned must be submitted as per instructions mentioned in the assignments.
▪ For queries, kindly follow the office hours to avoid any inconvenience.
Lecture Breakdown
Lab 1 Pointers
Structures
Arrays (static and Dynamic)
Lab 2 Abstract Data Types (ADT)
List Data Structure
Single Linked List
Lab 3 List Data Structure
Double Linked List
Lab 4 Stacks
o Array Implementation
o Linked List Implementation
Lab 5 Queue
o Array Implementation
o Linked List Implementation
Lab 6 Sorting I
o Bubble sort
o Insertion sort
o Selection sort
Lab 7 Sorting II
o Merge sort
o Quick sort
Lab 8 Binary Search Tree
Lab 9 AVL Trees
Lab 10 Graph Algorithms
Lab 11 Hash table and Hash Function in Data Structures
Lab 12 Open Ended Lab
1.
12
CS221L - DATA STRUCTURES AND ALGORITHMS
13
CS221L - DATA STRUCTURES AND ALGORITHMS
14
CS221L - DATA STRUCTURES AND ALGORITHMS
15
CS221L - DATA STRUCTURES AND ALGORITHMS
_____________________________________________________
Engr. Amna Arooj, Engr. Kiran
FACULTY OF COMPUTER SCIENCE AND ENGINEERING (FCSE)
GHULAM ISHAQ KHAN INSTITUTE OF ENGINEERING SCIENCES AND TECHNLOLOGY (GIKI)
16
CS221L - DATA STRUCTURES AND ALGORITHMS
Clarity 2 The solution is clear, The solution is The student has not
and the student is able partially formulated the solution
to formulate and clear and the student correctly or can not
explain the solution can explain parts of explain his/her solution
coherently. the at all.
program
Completion 2 The final complete The final complete The final complete
Time solution for all tasks solution for all tasks solution was submitted
was submitted before was submitted later along with the last 20%
half of the class than half of the class of the class
but before 80% of
the
size of class.
Total 10 10 5 0
17
CS221L - DATA STRUCTURES AND ALGORITHMS
________________________________________________________________
18
CS221L - DATA STRUCTURES AND ALGORITHMS
Weekly Breakdown
Week 1 Pointers
Structures
Arrays (static and Dynamic)
Week 4 Stacks
o Array Implementation
o Linked List Implementation
Week 5 Queue
o Array Implementation
o Linked List Implementation
Week 6 Sorting I
o Bubble sort
o Insertion sort
o Selection sort
Week 8 Sorting II
o Merge sort
o Quick sort
Week 9 Binary Search Tree
Week 10 AVL Trees
Week 11 Graph Algorithms
19
CS221L - DATA STRUCTURES AND ALGORITHMS
20
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#01
Structures, Pointers, Arrays
21
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#01
Structures, Pointers, Arrays
22
CS221L - DATA STRUCTURES AND ALGORITHMS
#include <iostream>
#include <cstring>
struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main() {
struct Books Book1; // Declare Book1 of type Book
struct Books Book2; // Declare Book2 of type Book
// book 1 specification
strcpy( Book1.title, "Learn C++ Programming");
strcpy( Book1.author, "Chand Miyan");
strcpy( Book1.subject, "C++ Programming");
Book1.book_id = 6495407;
// book 2 specification
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Yakit Singha");
strcpy( Book2.subject, "Telecom");
Book2.book_id = 6495700;
return 0;
23
CS221L - DATA STRUCTURES AND ALGORITHMS
When the above code is compiled and executed, it produces the following result −
Book 1 title : Learn C++ Programming
Book 1 author : Chand Miyan
Book 1 subject : C++ Programming
Book 1 id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Yakit Singha
Book 2 subject : Telecom
Book 2 id : 6495700
#include <iostream>
#include <cstring>
struct Books {
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main() {
struct Books Book1; // Declare Book1 of type Book
struct Books Book2; // Declare Book2 of type Book
// book 1 specification
strcpy( Book1.title, "Learn C++ Programming");
strcpy( Book1.author, "Chand Miyan");
strcpy( Book1.subject, "C++ Programming");
Book1.book_id = 6495407;
// book 2 specification
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Yakit Singha");
strcpy( Book2.subject, "Telecom");
Book2.book_id = 6495700;
24
CS221L - DATA STRUCTURES AND ALGORITHMS
printBook( Book1 );
return 0;
}
void printBook( struct Books book ) {
cout << "Book title : " << book.title <<endl;
cout << "Book author : " << book.author <<endl;
cout << "Book subject : " << book.subject <<endl;
cout << "Book id : " << book.book_id <<endl;
}
When the above code is compiled and executed, it produces the following result −
Book title : Learn C++ Programming
Book author : Chand Miyan
Book subject : C++ Programming
Book id : 6495407
Book title : Telecom Billing
Book author : Yakit Singha
Book subject : Telecom
Book id : 6495700
#include <iostream>
#include <cstring>
struct Books {
25
CS221L - DATA STRUCTURES AND ALGORITHMS
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main() {
struct Books Book1; // Declare Book1 of type Book
struct Books Book2; // Declare Book2 of type Book
// Book 1 specification
strcpy( Book1.title, "Learn C++ Programming");
strcpy( Book1.author, "Chand Miyan");
strcpy( Book1.subject, "C++ Programming");
Book1.book_id = 6495407;
// Book 2 specification
strcpy( Book2.title, "Telecom Billing");
strcpy( Book2.author, "Yakit Singha");
strcpy( Book2.subject, "Telecom");
Book2.book_id = 6495700;
return 0;
}
When the above code is compiled and executed, it produces the following result −
Book title : Learn C++ Programming
Book author : Chand Miyan
Book subject : C++ Programming
Book id : 6495407
Book title : Telecom Billing
Book author : Yakit Singha
Book subject : Telecom
Book id : 6495700
26
CS221L - DATA STRUCTURES AND ALGORITHMS
typedef struct {
char title[50];
char author[50];
char subject[100];
int book_id;
} Books;
Now, you can use Books directly to define variables of Books type without using struct
keyword. Following is the example −
Books Book1, Book2;
You can use typedef keyword for non-structs as well as follows −
typedef long int *pint32;
pint32 x, y, z;
x, y and z are all pointers to long ints.
Pointers are the variables that are used to store the location of value present in the memory. A
pointer to a location stores its memory address. The process of obtaining the value stored at a
location being referenced by a pointer is known as dereferencing. It is the same as the index
for a textbook where each page is referred by its page number present in the index. One can
easily find the page using the location referred to there. Such pointers usage helps in the
dynamic implementation of various data structures such as stack or list.
Optimization of our code and improving the time complexity of one algorithm. Using
pointers helps reduce the time needed by an algorithm to copy data from one place to another.
Since it used the memory locations directly, any change made to the value will be reflected at
all the locations.
Example:
Call_by_value needs the value of arguments to be copied every time any operation needs to
be performed.
Call_by_reference makes this task easier using its memory location to update the value at
memory locations.
27
CS221L - DATA STRUCTURES AND ALGORITHMS
Another use of pointers is to control the program flow. This is implemented by control tables
that use these pointers. These pointers are stored in a table to point to each subroutine’s entry
point to be executed one after the other. These pointers reference the addresses of the various
procedures. This helps while working with a recursive procedure or traversal of algorithms
where there is a need to store the calling step’s location.
1.2.1.2 secondary data structures
secondary data structures such as linked lists or structures to point to the next memory
locations in the list.
struct Node {
int data;
struct Node* next;
};
Example:
Defining a Pointer
Here we discuss defining a pointer in the data structure.
28
CS221L - DATA STRUCTURES AND ALGORITHMS
Syntax:
<datatype> *variable_name
Above depicts, vaiable_name is a pointer to a variable of the specified data type.
Example:
print(“%d”,**ptr2) // prints 30
We need to specify datatype- It helps to identify the number of bytes data stored in a variable;
thus. Simultaneously, we increment a pointer variable, and it is incremented according to the
size of this datatype only.
29
CS221L - DATA STRUCTURES AND ALGORITHMS
C Program on Pointers
Following is an example of creating pointers using C Program.
Example:
#include <stdio.h>
void pointerDemo()
{
int var1 = 30;
int *ptr1;
int **ptr2;
ptr1 = &var1;
ptr2 = &ptr1;
printf("Value at ptr1 = %p \n",ptr1);
printf("Value at var1 = %d \n",var1);
printf("Value of variable using *ptr1 = %d \n", *ptr1);
printf("Value at ptr2 = %p \n",ptr2);
printf("Value stored at *ptr2 = %d \n", *ptr2);
printf("Value of variable using **ptr2 = %d \n", **ptr2);
}
int main()
{
pointerDemo();
return 0;
}
Output:
30
CS221L - DATA STRUCTURES AND ALGORITHMS
Explanation: In the above program, we have used single and double dereferencing to display
the value of the variable.
31
CS221L - DATA STRUCTURES AND ALGORITHMS
You already know that a 2D array array is an array of arrays. But it is defined at the compiled
time. In this article, we learn about dynamically allocating a 2D array in C++ at run time.
Let's dive deep to understand the dynamic world!
// Driver Code
int main()
{
// Dimensions of the 2D array
int m = 3, n = 4, c = 0;
32
CS221L - DATA STRUCTURES AND ALGORITHMS
// size m*n
int* arr = new int[m * n];
// Assign values to
// the memory block
*(arr + i * n + j) = ++c;
}
}
return 0;
}
Output:
1 2 3 4
5 6 7 8
9 10 11 12
First, let's understand this 'new int[m *n]' Here the new operator is used for dynamic
allocation and we are creating an array of type int and contiguous allocation of size m * n.
This will return us an address as explained above already and stored in a pointer.
Then we are just assigning the values to the address blocks in heap memory using the
pointers syntax. 'arr + i * n + j' -> this is the address of the heap block and *(arr + i * n + j)
this is the value of that heap block.
33
CS221L - DATA STRUCTURES AND ALGORITHMS
// Driver Code
int main()
{
// Dimensions of the array
int m = 3, n = 4, c = 0;
34
CS221L - DATA STRUCTURES AND ALGORITHMS
// arrays
delete[] a[i];
delete[] a; // To delete the outer array
// which contained the pointers
// of all the inner arrays
return 0;
}
Output:
1 2 3 4
5 6 7 8
9 10 11 12
'int a' - > This means we are creating a pointer of type int and this pointer will store the
address of an array (in this case) of int type pointers. This array of pointers will point to each
row in an array in heap memory.
35
CS221L - DATA STRUCTURES AND ALGORITHMS
Practice Problems:
Lab Activity 1:
Write a C++ program of a structure variable to assign data to three members, i-e name, age
and salary of a person and display it on screen.
Lab Activity 2: Write a structure to store the roll no., name, age (between 11 and 14) and
address of students (more than 10). Store the information of the students.
1 - Write a function to print the names of all the students having age 14.
2 - Write another function to print the names of all the students having even roll no.
3 - Write another function to display the details of the student whose roll no is given (i.e. roll
no. entered by the user).
Lab Activity 3:
In C/C++ language, arrays work on memory addresses so as pointers and hence they
are strongly related. Design a C program which take an array of 6 elements from the user
:and do the following
a) Declare the pointer and refernce it with the array address
b) Displayevery element of an array by using the pointer
c) Find the maximum value in arrayusi n g pointer
Lab Activity 4:
Learning Objective: Pointers in function call
In this activity you will have to use pointers to perform the following tasks on randomly
generated 1D array of type int having size of 20.
i. Write a function int smallest = smallest_value(int *temp, int size), which
receives an array as pointer and find out smallest value using pointer to
array.
36
CS221L - DATA STRUCTURES AND ALGORITHMS
37
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#02
Abstract Data Types
Single Linked list
38
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#02
Abstract Data types and Single Linked List
In every programming language, we implement ADTs using different methods and logic.
Although, we can still perform all the associated operations which are defined for that ADT
irrespective of language. For example, in C, ADTs are implemented mostly using structure.
On the other hand, in C++ or JAVA, they’re implemented using class. However, operations
are common in all languages.
39
CS221L - DATA STRUCTURES AND ALGORITHMS
Since only you were buying popcorn for all, how would you distribute that to your friends?
You can't remember where everyone sat, and it's dark inside the hall.
So, instead of you remembering where everyone sat, if everyone kept track of the next
friend's seat, then such reference would help popcorn tubs to traverse up to a friend who's yet
to get popcorn. This could be achieved by passing popcorn to the next friend starting from
you!
40
CS221L - DATA STRUCTURES AND ALGORITHMS
See how the linked list came in handy while keeping track of all these randomly distributed
disjoint seats?
In a computer, you can think of memory as a movie theatre, the virtual address space as the
seats, and any particular memory address as a seat number.
Now, if we had initiated booking in advance, we could have booked an entire row of
consecutive seats much like an array does when we declare it with a fixed size in advance,
like so:
int seats[24];
In our context of a movie theater, if more friends later decide to join the group to catch the
movie. We cannot simply append them to the array of seats since there might be other
audiences seating just after the last allocated seat.
So either we find another larger empty row of consecutive seats so that all friends can sit
together (much like dynamic array), or we rely on an approach similar to the linked list, in
that we simply insert new friends in vacant spots but still have references to them should we
require to pass popcorn and drinks.
You see, arrays are suitable when we need fast access. Like who's seating at seat no. 13 can
be answered in constant time! But arrays require you to declare a fixed size at the compile-
time, due to which memory can be either wasted or fell short.
41
CS221L - DATA STRUCTURES AND ALGORITHMS
Whereas linked list shines when we need to modify existing data by insertion and deletion
because it doesn't have a fixed size. So, our memory consumption is determined at run time
as the linked list shrinks and grows dynamically in constant time.
Here, we can only traverse in one direction (not the band ) due to the linking of every node to
its next node.
class Node {
some_constructor(int value) {
int data = value;
Node* next = NULL;
}
42
CS221L - DATA STRUCTURES AND ALGORITHMS
where data can be any valid type and not just integer, but next must be a Node pointer.
Some of the most essential operations defined in List ADT are listed below.
43
CS221L - DATA STRUCTURES AND ALGORITHMS
• front(): returns the value of the node present at the front of the list.
• back(): returns the value of the node present at the back of the list.
• push_front(int val): creates a pointer with value = val and keeps this pointer to the
front of the linked list.
• push_back(int val): creates a pointer with value = val and keeps this pointer to the
back of the linked list.
• size(): returns the number of nodes that are present in the list.
2.2.3.1 Insertion
Inserting a new node at a given position is achieved by manipulating at most 2 next pointers
like so; consider two pointers, prevNode, and newNode set newNode's next pointer to
the prevNode's next pointer and set prevNode's next pointer to
the newNode where prevNode denotes a pointer to the node after which newNode is to be
inserted.
And since only a constant number of pointers gets changed irrespective of the size of the
linked list, the complexity should have been O(1).
However, to get access at any given position, we have to traverse starting from the head
till prevNode. Thus, the worst case for insertion could be expressed as; Traversal O(n) +
Just the insertion O(1) = Insertion O(n). However, the best case would be to insert in the
beginning and hence the time complexity becomes Ω(1).
Notice that the order of execution does matter in case of insertion. If we interchange the steps
i.e. first set prevNode's next pointer to the newNode then we lose the reference to the
remaining of the linked list previously occurring after the prevNode. Something to keep in
mind!
44
CS221L - DATA STRUCTURES AND ALGORITHMS
45
CS221L - DATA STRUCTURES AND ALGORITHMS
2.2.3.2 Deletion
We can delete a node located at a specified index by manipulating at most 2 next pointers like
so; consider two pointers, prevNode, and targetNode set prevNode's next pointer to
the targetNode's next pointer and set targetNode's next pointer to NULL
where prevNode denotes a pointer to the node after which targetNode is to be deleted.
Following the same reasoning as insertion, the best case and the worst case time complexity
stands at Ω(1) and O(n) respectively.
Again just like insertion, the order is important. It's important to realize that
setting targetNode's next pointer to NULL as the first step would cost us the reference to the
remaining of the linked list (if the targetNode wasn't the Tail).
46
CS221L - DATA STRUCTURES AND ALGORITHMS
2.2.3.3 Traversal
We can traverse the entire linked list starting from the head node. If there are n nodes then the
time complexity for traversal becomes O(n) as we hop through each and every node.
47
CS221L - DATA STRUCTURES AND ALGORITHMS
2.2.3.4 Search
Given a particular key (data), we need to search for a node whose data matches the key. In
the best-case scenario, the head would be the node we are looking for, whereas in the worst-
case the required node would be the tail. In terms of time complexity the best case, the
average case, and the worst case of searching are denoted as Ω(1), Θ(n),
and O(n) respectively.
class LinkedList {
public:
// constructor for creating a linked list
// and storing it in 'head'
LinkedList() {}
void traversal() {
48
CS221L - DATA STRUCTURES AND ALGORITHMS
49
CS221L - DATA STRUCTURES AND ALGORITHMS
50
CS221L - DATA STRUCTURES AND ALGORITHMS
Accessing a node - If you want to access a node in a linked list, you have to traverse starting
from the head. We cannot access any random nodes directly except for the head itself, since
nodes don't share a linear order in the physical memory and are only referenced by pointers.
Traversing in reverse order - Traversing in reverse order is difficult. Although a doubly-
linked list makes it easier but requires more memory to store those extra 'prev' pointers.
51
CS221L - DATA STRUCTURES AND ALGORITHMS
Practice Problems:
Lab Activity 1:
Write a C++ function to count the number of nodes in a singly linked list.
You can take the following structure as a reference:
struct Node {
int data;
Node* next;
};
Your task is to implement the function with the following prototype:
int countNodes(Node* head);
The function should take the head of a singly linked list as an argument and return the total
number of nodes present in the list.
Lab Activity 2:
Write a C++ function to check if a given singly linked list is empty. You can use question#01
structure as reference.
Your task is to implement the function with the following prototype:
bool isListEmpty(Node* head);
The function should take the head of a singly linked list as an argument and return true if the
list is empty (i.e., it has no nodes), and false otherwise.
Lab Activity 3:
Write a C++ function to delete a node with a given value from a singly linked list. Assume
that the value to be deleted is always present in the list.
52
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#03
Double Linked List
53
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab 03
Doubly Linked List
Let's see how we can represent a doubly linked list on an algorithm/code. Suppose we have a
doubly linked list:
Each struct node has a data item, a pointer to the previous struct node, and a pointer to the
next struct node.
54
CS221L - DATA STRUCTURES AND ALGORITHMS
Now we will create a simple doubly linked list with three items to understand how this
works.
/* Initialize nodes */
struct node *head;
struct node *one = NULL;
struct node *two = NULL;
struct node *three = NULL;
/* Allocate memory */
one = malloc(sizeof(struct node));
two = malloc(sizeof(struct node));
three = malloc(sizeof(struct node));
/* Connect nodes */
one->next = two;
one->prev = NULL;
two->next = three;
two->prev = one;
three->next = NULL;
three->prev = two;
In the above code, one , two , and three are the nodes with data items 1, 2, and 3 respectively.
55
CS221L - DATA STRUCTURES AND ALGORITHMS
For node one: next stores the address of two and prev stores null (there is no node
before it)
For node two : next stores the address of three and prev stores the address of one
For node three : next stores null (there is no node after it) and prev stores the address
of two .
Note: In the case of the head node, prev points to null , and in the case of the tail
pointer, next points to null. Here, one is a head node and three is a tail node.
56
CS221L - DATA STRUCTURES AND ALGORITHMS
New node
57
CS221L - DATA STRUCTURES AND ALGORITHMS
// point next of newNode to the first node of the doubly linked list
newNode->next = (*head);
// point previous of the first node (now first node is the second node) to newNode
if ((*head) != NULL)
(*head)->prev = newNode;
New node
58
CS221L - DATA STRUCTURES AND ALGORITHMS
assign the value of next from previous node to the next of newNode
assign the address of newNode to the next of previous node
3. Set the prev pointer of new node and the next node
assign the value of prev of next node to the prev of newNode
assign the address of newNode to the prev of next node
Final list
59
CS221L - DATA STRUCTURES AND ALGORITHMS
60
CS221L - DATA STRUCTURES AND ALGORITHMS
New node
2. Set prev and next pointers of new node and the previous node
If the linked list is empty, make the newNode as the head node. Otherwise, traverse to the end
of the doubly linked list and
Reorganize the
pointers
The final doubly linked list looks like this.
61
CS221L - DATA STRUCTURES AND ALGORITHMS
// if the linked list is not empty, traverse to the end of the linked list
while (temp->next != NULL)
temp = temp->next;
62
CS221L - DATA STRUCTURES AND ALGORITHMS
63
CS221L - DATA STRUCTURES AND ALGORITHMS
Final list
if (del_node->prev != NULL)
del_node->prev->next = del_node->next;
free(del);
64
CS221L - DATA STRUCTURES AND ALGORITHMS
Final list
if (del_node->prev != NULL)
del_node->prev->next = del_node->next;
Final list
if (del_node->prev != NULL)
del_node->prev->next = del_node->next;
65
CS221L - DATA STRUCTURES AND ALGORITHMS
Note: We can also solve this using the first condition (for the node
before del_node ) of the second case (Delete the inner node).
#include <iostream>
using namespace std;
// node creation
struct Node {
int data;
struct Node* next;
struct Node* prev;
};
66
CS221L - DATA STRUCTURES AND ALGORITHMS
67
CS221L - DATA STRUCTURES AND ALGORITHMS
newNode->prev = prev_node;
// if the linked list is not empty, traverse to the end of the linked list
while (temp->next != NULL)
68
CS221L - DATA STRUCTURES AND ALGORITHMS
temp = temp->next;
// if del_node is the head node, point the head pointer to the next of del_node
if (*head == del_node)
*head = del_node->next;
// if del_node is not at the last node, point the prev of node next to del_node to the previous
of del_node
if (del_node->next != NULL)
del_node->next->prev = del_node->prev;
// if del_node is not the first node, point the next of the previous node to the next node of
del_node
if (del_node->prev != NULL)
del_node->prev->next = del_node->next;
69
CS221L - DATA STRUCTURES AND ALGORITHMS
int main() {
// initialize an empty node
struct Node* head = NULL;
insertEnd(&head, 5);
insertFront(&head, 1);
insertFront(&head, 6);
insertEnd(&head, 9);
70
CS221L - DATA STRUCTURES AND ALGORITHMS
insertAfter(head->next, 15);
displayList(head);
displayList(head);
}
71
CS221L - DATA STRUCTURES AND ALGORITHMS
Exercise 1
Design doubly linked list having basic functionality of adding an element at the end of the list
and display all the entered list elements when user entered -1. Also implement the
functionality for deletion in doubly linked list based upon the data (value in the list).
Exercise 2
Write a C++ program to check if a double linked list is a palindrome or not.
Test Data and Expected Output :
Original List:
1 2 3 4 5
Linked list is not a palindrome.
Original List:
72
CS221L - DATA STRUCTURES AND ALGORITHMS
MADAM
Linked list is a palindrome.
Exercise 3
Write a C++ program to remove duplicates from a double unsorted linked list.
Test Data and Expected Output :
Original List:
1 2 3 3 4
After removing duplicate elements from the said singly list:
1 2 3 4
Original List:
1 2 3 3 4 4
After removing duplicate elements from the said singly list:
1 2 3 4
73
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab 04
Stack Data Structure
74
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab# 04
Stack Data Structure in C++
As shown above, there is a pile of plates stacked on top of each other. If we want to add
another item to it, then we add it at the top of the stack as shown in the above figure (left-
hand side). This operation of adding an item to stack is called “Push”.
On the right side, we have shown an opposite operation i.e. we remove an item from the
stack. This is also done from the same end i.e. the top of the stack. This operation is called
“Pop”.
As shown in the above figure, we see that push and pop are carried out from the same end.
This makes the stack to follow LIFO order. The position or end from which the items are
pushed in or popped out to/from the stack is called the “Top of the stack”.
Initially, when there are no items in the stack, the top of the stack is set to -1. When we add
an item to the stack, the top of the stack is incremented by 1 indicating that the item is added.
As opposed to this, the top of the stack is decremented by 1 when an item is popped out of
the stack.
75
CS221L - DATA STRUCTURES AND ALGORITHMS
4.2.1 PUSH
This method allows us to add an element to the stack. Adding an element in a Stack in
C++ occurs only at its top because of the LIFO policy.
In this process, the following steps are performed:
1. Check if the stack is full or not.
2. If the stack is full, then print error of overflow and exit the program.
3. If the stack is not full, then increment the top and add the element.
4.2.2 POP
This method allows us to remove an element from the top of the stack.
Dequeue operation consists of the following steps:
1. Check if the stack is empty or not.
2. If the stack is empty, then print error of underflow and exit the program.
3. If the stack is not empty, then print the element at the top and decrement the top.
4.2.3 Illustration
76
CS221L - DATA STRUCTURES AND ALGORITHMS
The above illustration shows the sequence of operations that are performed on the stack.
Initially, the stack is empty. For an empty stack, the top of the stack is set to -1.
Next, we push the element 10 into the stack. We see that the top of the stack now points to
element 10.
Next, we perform another push operation with element 20, as a result of which the top of the
stack now points to 20. This state is the third figure.
Now in the last figure, we perform a pop () operation. As a result of the pop operation, the
element pointed at the top of the stack is removed from the stack. Hence in the figure, we see
that element 20 is removed from the stack. Thus the top of the stack now points to 10.
• When we implement stack uisng array we take the direction of the stack i.e the
direction in which elements are inserted towards right.
Lets take an example of an array of 5 elements to implement stack. So we define the size of
the array using pre-processor directive #deifne SIZE 5 & then we can create an array of 5
elements as int A[SIZE]; Also we will declare a top variable to track the element at the top
of the stack which will initially be -1 when the stack is empty i.e int top=-1;
• isempty()- Now that we know that the stack is empty when top is equal to -1 we
can use this to implement our isempty() function i.e. when top == -1 retrun true
else return false.
• push()- To push an element into the stack we will simply increment top by one
and insert the element at that position. While inserting we have to take care of
the condition when the array is full i.e. when top == SIZE-1;
77
CS221L - DATA STRUCTURES AND ALGORITHMS
• pop()- To pop an element from the stack we will simple decrement top by one
which will simply mean that the element is no longer the part of the stack. In this
case we have to take care of the condition when the stack is empty i.e top == -
1 then we cannot perform the pop operation.
• show_top()- we will simply print the element at top if the stack is not empty.
• Lets say we have an stack with one element i.e 2 and we have to insert ot push an
element 3 to this stack.
• then we will simply increment top by one and push the element at top.
#define SIZE 5
int A[SIZE];
int top = -1;
bool isempty()
{
if(top==-1)
return true;
78
CS221L - DATA STRUCTURES AND ALGORITHMS
else
return false;
}
void pop()
{
if(isempty())
cout<<"Stack is empty!\n";
else
top--;
}
void show_top()
{
if(isempty())
cout<<"Stack is empty!\n";
else
cout<<"Element at top is: "<<A[top]<<"\n";
void displayStack()
{
if(isempty())
{
cout<<"Stack is empty!\n";
}
else
{
for(int i=0 ; i<=top; i++)
cout<<A[i]<<" ";
cout<<"\n";
int main()
{
79
CS221L - DATA STRUCTURES AND ALGORITHMS
cin>>value;
push(value);
break;
case 2: pop();
break;
case 3: show_top();
break;
case 4: displayStack();
break;
case 5: flag = 0;
break;
}
}
return 0;
}
▪ Easy to implement.
▪ Memory is saved as pointers are not involved.
Disadvantages of array implementation:
So we need to follow a simple rule in the implementation of a stack which is last in first
out and all the operations can be performed with the help of a top variable. Let us learn how
to perform Pop, Push, Peek, and Display operations:
80
CS221L - DATA STRUCTURES AND ALGORITHMS
In the stack Implementation, a stack contains a top pointer. which is the “head” of the stack
where pushing and popping items happens at the head of the list. The first node has a null in
the link field and second node-link has the first node address in the link field and so on and
the last node address is in the “top” pointer.
#include <iostream>
using namespace std;
struct Node {
int data;
struct Node *next;
};
struct Node* top = NULL;
void push(int val) {
struct Node* newnode = (struct Node*) malloc(sizeof(struct Node));
newnode->data = val;
81
CS221L - DATA STRUCTURES AND ALGORITHMS
newnode->next = top;
top = newnode;
}
void pop() {
if(top==NULL)
cout<<"Stack Underflow"<<endl;
else {
cout<<"The popped element is "<< top->data <<endl;
top = top->next;
}
}
void display() {
struct Node* ptr;
if(top==NULL)
cout<<"stack is empty";
else {
ptr = top;
cout<<"Stack elements are: ";
while (ptr != NULL) {
cout<< ptr->data <<" ";
ptr = ptr->next;
}
}
cout<<endl;
}
int main() {
int ch, val;
cout<<"1) Push in stack"<<endl;
cout<<"2) Pop from stack"<<endl;
cout<<"3) Display stack"<<endl;
cout<<"4) Exit"<<endl;
do {
cout<<"Enter choice: "<<endl;
cin>>ch;
switch(ch) {
82
CS221L - DATA STRUCTURES AND ALGORITHMS
case 1: {
cout<<"Enter value to be pushed:"<<endl;
cin>>val;
push(val);
break;
}
case 2: {
pop();
break;
}
case 3: {
display();
break;
}
case 4: {
cout<<"Exit"<<endl;
break;
}
default: {
cout<<"Invalid Choice"<<endl;
}
}
}while(ch!=4);
return 0;
}
Output:
1) Push in stack
2) Pop from stack
3) Display stack
4) Exit
Enter choice: 1
Enter value to be pushed: 2
Enter choice: 1
Enter value to be pushed: 6
83
CS221L - DATA STRUCTURES AND ALGORITHMS
Enter choice: 1
Enter value to be pushed: 8
Enter choice: 1
Enter value to be pushed: 7
Enter choice: 2
The popped element is 7
Enter choice: 3
Stack elements are:8 6 2
Enter choice: 5
Invalid Choice
Enter choice: 4
Exit
Advantages of Linked List implementation:
▪ The linked list implementation of a stack can grow and shrink according to
the needs at runtime.
▪ It is used in many virtual machines like JVM.
Disadvantages of Linked List implementation:
The time complexities for push() and pop() functions are O(1) because we always have to
insert or remove the data from the top of the stack, which is a one step process.
• CD/DVD stand.
• Stack of books in a book shop.
• Call center systems.
• Undo and Redo mechanism in text editors.
84
CS221L - DATA STRUCTURES AND ALGORITHMS
Practice Problems:
LAB Activity#01:
Write a C++ function to check if a given string of parentheses is balanced or not using a
stack.Your task is to implement the function with the following prototype:
bool isBalanced(const std::string& parentheses);
The function should take a string containing only parentheses as an argument. It should return
true if the parentheses in the string are balanced (i.e., every opening parenthesis has a
corresponding closing parenthesis in the correct order), and false otherwise.
For example, if the input string is "((()))", the function should return true. If the input string
is "((())", the function should return false.
LAB Activity#02:
85
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#05
Queues Data Structure in C++
86
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab# 05
Queue Data Structure In C++
We have two ends i.e. “front” and “rear” of the queue. When the queue is empty, then both
the pointers are set to -1.
The “rear” end pointer is the place from where the elements are inserted in the queue. The
operation of adding /inserting elements in the queue is called “enqueue”.
The “front” end pointer is the place from where the elements are removed from the queue.
The operation to remove/delete elements from the queue is called “dequeue”.
When the rear pointer value is size-1, then we say that the queue is full. When the front is
null, then the queue is empty.
• EnQueue: Adds an item to the queue. Addition of an item to the queue is always
done at the rear of the queue.
• DeQueue: Removes an item from the queue. An item is removed or de-queued
always from the front of the queue.
• isEmpty: Checks if the queue is empty.
• isFull: Checks if the queue is full.
• peek: Gets an element at the front of the queue without removing it.
87
CS221L - DATA STRUCTURES AND ALGORITHMS
5.2.1 Enqueue
In this process, the following steps are performed:
5.2.2 Dequeue
Dequeue operation consists of the following steps:
Next, we will see a detailed illustration of insertion and deletion operations in queue.
5.2.3 Illustration
This is an empty queue and thus we have rear and empty set to -1.
Next, we add 1 to the queue and as a result, the rear pointer moves ahead by one location.
In the next figure, we add element 2 to the queue by moving the rear pointer ahead by another
increment.
88
CS221L - DATA STRUCTURES AND ALGORITHMS
In the following figure, we add element 3 and move the rear pointer by 1.
At this point, the rear pointer has value 2 while the front pointer is at the 0th location.
Next, we delete the element pointed by the front pointer. As the front pointer is at 0, the
element that is deleted is 1.
Thus the first element entered in the queue i.e. 1 happens to be the first element removed
from the queue. As a result, after the first dequeue, the front pointer now will be moved ahead
t0 the next location which is 1.
#include <iostream>
#define MAX_SIZE 5
using namespace std;
89
CS221L - DATA STRUCTURES AND ALGORITHMS
class Queue {
private:
int myqueue[MAX_SIZE], front, rear;
public:
Queue(){
front = -1;
rear = -1;
}
boolisFull(){
if(front == 0 && rear == MAX_SIZE - 1){
return true;
}
return false;
}
boolisEmpty(){
if(front == -1) return true;
else return false;
}
90
CS221L - DATA STRUCTURES AND ALGORITHMS
}
}
int deQueue(){
int value;
if(isEmpty()){
cout << "Queue is empty!!" << endl; return(-1); } else { value = myqueue[front]; if(front
>= rear){ //only one element in queue
front = -1;
rear = -1;
}
else {
front++;
}
cout << endl << "Deleted => " << value << " from myqueue";
return(value);
}
}
91
CS221L - DATA STRUCTURES AND ALGORITHMS
}
}
};
int main()
{
Queue myq;
myq.deQueue(); //deQueue
myq.displayQueue();
//deQueue =>removes 10
myq.deQueue();
return 0;
}
Output:
Queue is empty!!
Queue created:
10 20 30 40 50
Queue is full!!
Front = 0
Queue elements : 10 20 30 40 50
Rear = 4
92
CS221L - DATA STRUCTURES AND ALGORITHMS
Queue elements: 20 30 40 50
Rear = 4
The above implementation shows the queue represented as an array. We specify the max_size
for the array. We also define the enqueue and dequeue operations as well as the isFull and
isEmpty operations.
struct node {
int data;
};
if (rear == NULL) {
rear->next = NULL;
rear->data = val;
front = rear;
} else {
temp=new node;
rear->next = temp;
temp->data = val;
temp->next = NULL;
rear = temp;
void Delete() {
93
CS221L - DATA STRUCTURES AND ALGORITHMS
temp = front;
if (front == NULL) {
temp = temp->next;
free(front);
front = temp;
} else {
free(front);
front = NULL;
rear = NULL;
void Display() {
temp = front;
cout<<"Queue is empty"<<endl;
return;
cout<<endl;
int main() {
cout<<"Queue Created:"<<endl;
Insert(10);
Insert(20);
Insert(30);
Insert(40);
Insert(50);
Display();
94
CS221L - DATA STRUCTURES AND ALGORITHMS
Delete();
Display();
return 0;
Output:
Queue Created:
10 20 30 40 50
Element deleted from queue is: 10
Queue after one deletion:
20 30 40 50
Stacks and queues are secondary data structures which can be used to store data. They can be
programmed using the primary data structures like arrays and linked lists. Having discussed
both the data structures in detail, it’s time to discuss the main differences between these two
data structures.
Stacks Queues
Uses LIFO (Last in, First out) approach. Uses FIFO (First in, First out) approach.
Items are added or deleted from only one Items are added from “Rear” end of the queue and are
end called “Top” of the stack. removed from the “front” of the queue.
The basic operations for the stack are The basic operations for a queue are “enqueue” and
“push” and “Pop”. “dequeue”.
We can do all operations on the stack by In queues, we need to maintain two pointers, one to
maintaining only one pointer to access the access the front of the queue and the second one to
top of the stack. access the rear of the queue.
The stack is mostly used to solve recursive Queues are used to solve problems related to ordered
problems. processing.
95
CS221L - DATA STRUCTURES AND ALGORITHMS
• The queue can also be used for print spooling wherein the number of print jobs
is placed in a queue.
• Handling of interrupts in real-time systems is done by using a queue data
structure. The interrupts are handled in the order they arrive.
• Breadth-first search in which the neighboring nodes of a tree are traversed
before moving on to next level uses a queue for implementation.
• Call center phone systems use queues to hold the calls until they are answered
by the service representatives.
• In general, we can say that the queue data structure is used whenever we require
the resources or items to be serviced in the order they arrive i.e. First in, First
Out.
Conclusion
The queue is a FIFO (First In, First Out) data structure that is mostly used in resources where
scheduling is required. It has two pointers rear and front at two ends and these are used to
insert an element and remove an element to/from the queue respectively.
Practice Problems:
Implement the queue that perform following functions:
1: Add a node (data member of type: string), Enqueue()
2: Delete a node, Dequeue()
3: Display the queue, Display()
In this activity modify above program by writing another function int
LengthOfString(Queue *) “This function will return the number of characters in the string of
nodes one by one and dequeue that node until queue is empty”.
96
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#06
Sorting Algorithms I
97
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#06
Sorting Algorithms I
1. Starting from the first index, compare the first and the second elements.
2. If the first element is greater than the second element, they are swapped.
3. Now, compare the second and the third elements. Swap them if they are not in
order.
4. The above process goes on until the last element.
98
CS221L - DATA STRUCTURES AND ALGORITHMS
2. Remaining Iteration
The same process goes on for the remaining iterations.
After each iteration, the largest element among the unsorted elements is placed at the end.
In each iteration, the comparison takes place up to the last unsorted element.
The array is sorted when all the unsorted elements are placed at their correct positions.
The array is sorted if all elements are kept in the right order.
99
CS221L - DATA STRUCTURES AND ALGORITHMS
100
CS221L - DATA STRUCTURES AND ALGORITHMS
bubbleSort(data, size);
101
CS221L - DATA STRUCTURES AND ALGORITHMS
This is exactly how insertion sort works. It starts from the index 1(not 0), and each index
starting from index 1 is like a new card, that you have to place at the right position in the
sorted subarray on the left.
Step 1 - If the element is the first element, assume that it is already sorted. Return 1.
Step3 - Now, compare the key with all elements in the sorted array.
Step 4 - If the element in the sorted array is smaller than the current element, then move to
the next element. Else, shift greater elements in the array towards the right.
Initial array
102
CS221L - DATA STRUCTURES AND ALGORITHMS
1. The first element in the array is assumed to be sorted. Take the second element
and store it separately in key .
Compare key with the first element. If the first element is greater than key ,
then key is placed in front of the first element.
If the first element is greater than key, then key is placed in front of the first element.
2. Now, the first two elements are sorted.
Take the third element and compare it with the elements on the left of it. Placed
it just behind the element smaller than it. If there is no element smaller than it,
then place it at the beginning of the array.
103
CS221L - DATA STRUCTURES AND ALGORITHMS
Place 4 behind 1
#include <iostream>
using namespace std;
104
CS221L - DATA STRUCTURES AND ALGORITHMS
// Compare key with each element on the left of it until an element smaller than
// it is found.
// For descending order, change key<array[j] to key>array[j].
while (key < array[j] && j >= 0) {
array[j + 1] = array[j];
--j;
}
array[j + 1] = key;
}
}
// Driver code
int main() {
int data[] = {9, 5, 1, 4, 3};
int size = sizeof(data) / sizeof(data[0]);
insertionSort(data, size);
cout << "Sorted array in ascending order:\n";
printArray(data, size);
}
Best O(n)
Worst O(n2)
Average O(n2)
105
CS221L - DATA STRUCTURES AND ALGORITHMS
6.3.1.1 Illustration:
Let’s consider below array:
1. Set the first element as minimum
2. Compare minimum with the second element. If the second element is smaller
than minimum , assign the second element as minimum .
Compare minimum with the third element. Again, if the third element is smaller,
106
CS221L - DATA STRUCTURES AND ALGORITHMS
then assign minimum to the third element otherwise do nothing. The process goes
on until the last element.
107
CS221L - DATA STRUCTURES AND ALGORITHMS
selectionSort(array, size)
repeat (size - 1) times
set the first unsorted element as the minimum
for each of the unsorted elements
if element < currentMinimum
set element as new minimum
108
CS221L - DATA STRUCTURES AND ALGORITHMS
#include <iostream>
using namespace std;
// driver code
int main() {
int data[] = {20, 12, 10, 15, 2};
int size = sizeof(data) / sizeof(data[0]);
selectionSort(data, size);
cout << "Sorted array in Acsending Order:\n";
printArray(data, size);
}
109
CS221L - DATA STRUCTURES AND ALGORITHMS
Hence for a given input size of n, following will be the time and space complexity for
selection sort algorithm:
Worst Case Time Complexity [ Big-O ]: O(n2)
Best Case Time Complexity [Big-omega]: O(n2)
Average Time Complexity [Big-theta]: O(n2)
Space Complexity: O(1)
Practice Problems:
Lab Activity #01:
Write a C++ function called insertion_sort that takes in a list of integers and sorts it using
the insertion sort algorithm. The function should modify the original list in-place and return
nothing.
For example, if the input list is [5, 2, 8, 12, 3], the function should modify the list to become
[2, 3, 5, 8, 12].
110
CS221L - DATA STRUCTURES AND ALGORITHMS
111
CS221L - DATA STRUCTURES AND ALGORITHMS
112
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#07
Sorting Algorithms II
113
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#07
Sorting Algorithms II
Merge sort is defined as a sorting algorithm that works by dividing an array into smaller
subarrays, sorting each subarray, and then merging the sorted subarrays back together to form
the final sorted array.
In simple terms, we can say that the process of merge sort is to divide the array into two
halves, sort each half, and then merge the sorted halves back together. This process is
repeated until the entire array is sorted.
7.1.2 Illustration:
Lets consider an array arr[] = {38, 27, 43, 10}
Initially divide the array into two equal halves:
• These subarrays are further divided into two halves. Now they become array of
unit length that can no longer be divided and array of unit length are always
sorted.
114
CS221L - DATA STRUCTURES AND ALGORITHMS
Merge Sort: Divide the subarrays into two halves (unit length subarrays here)
These sorted subarrays are merged together, and we get bigger sorted subarrays.
Merge Sort: Merge the unit length subarrys into sorted subarrays
This merging process is continued until the sorted array is built from the smaller
subarrays.
115
CS221L - DATA STRUCTURES AND ALGORITHMS
Merge Sort: Merge the sorted subarrys to get the sorted array
The following diagram shows the complete merge sort process for an example array {38, 27,
43, 3, 9, 82, 10}.
#include <bits/stdc++.h>
116
CS221L - DATA STRUCTURES AND ALGORITHMS
if (leftArray[indexOfSubArrayOne]
<= rightArray[indexOfSubArrayTwo]) {
array[indexOfMergedArray]
= leftArray[indexOfSubArrayOne];
indexOfSubArrayOne++;
else {
array[indexOfMergedArray]
= rightArray[indexOfSubArrayTwo];
indexOfSubArrayTwo++;
indexOfMergedArray++;
117
CS221L - DATA STRUCTURES AND ALGORITHMS
array[indexOfMergedArray]
= leftArray[indexOfSubArrayOne];
indexOfSubArrayOne++;
indexOfMergedArray++;
array[indexOfMergedArray]
= rightArray[indexOfSubArrayTwo];
indexOfSubArrayTwo++;
indexOfMergedArray++;
delete[] leftArray;
delete[] rightArray;
return;
118
CS221L - DATA STRUCTURES AND ALGORITHMS
// UTILITY FUNCTIONS
// Driver code
int main()
printArray(arr, arr_size);
printArray(arr, arr_size);
return 0;
119
CS221L - DATA STRUCTURES AND ALGORITHMS
Output
Given array is
12 11 13 5 6 7
Sorted array is
5 6 7 11 12 13
Auxiliary Space: O(N), In merge sort all elements are copied into an auxiliary array. So N
auxiliary space is required for merge sort.
120
CS221L - DATA STRUCTURES AND ALGORITHMS
121
CS221L - DATA STRUCTURES AND ALGORITHMS
122
CS221L - DATA STRUCTURES AND ALGORITHMS
123
CS221L - DATA STRUCTURES AND ALGORITHMS
#include <bits/stdc++.h>
using namespace std;
124
CS221L - DATA STRUCTURES AND ALGORITHMS
// Driver Code
int main()
{
int arr[] = { 10, 7, 8, 9, 1, 5 };
int N = sizeof(arr) / sizeof(arr[0]);
// Function call
quickSort(arr, 0, N - 1);
cout << "Sorted array: " << endl;
for (int i = 0; i < N; i++)
cout << arr[i] << " ";
return 0;
}
Output
Sorted array:
1 5 7 8 9 10
125
CS221L - DATA STRUCTURES AND ALGORITHMS
Best Case:
Average Case:
Worst Case: O(N2)
Auxiliary Space: O(1) as no extra space is used
Practice Problems:
Algorithm
1. If head is NULL or list contains only one element then return list
2. Create two lists by dividing original list into 2 parts
3. Sort first and second part of list
4. Merge both sorted list
126
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#08
Binary Search Tree Algorithm
127
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#08
Binary Search Tree (BST)
8.1.2 Example
The following tree is a Binary Search Tree. In this tree, left subtree of every node contains
nodes with smaller values and right subtree of every node contains larger values.
128
CS221L - DATA STRUCTURES AND ALGORITHMS
The binary tree on the right isn't a binary search tree because the right subtree of the node "3"
contains a value smaller than it.
Note: Every binary search tree is a binary tree but every binary tree need not to be
binary search tree.
Step 2 - Compare the search element with the value of root node in the tree.
Step 3 - If both are matched, then display "Given node is found!!!" and terminate the function
Step 4 - If both are not matched, then check whether search element is smaller or larger than
that node value.
Step 5 - If search element is smaller, then continue the search process in left subtree.
Step 6- If search element is larger, then continue the search process in right subtree.
Step 7 - Repeat the same until we find the exact element or until the search element is
compared with the leaf node
Step 8 - If we reach to the node having the value equal to the search value then display
"Element is found" and terminate the function.
Step 9 - If we reach to the leaf node and if it is also not matched with the search element, then
display "Element is not found" and terminate the function.
8.2.1.1 Algorithm:
If root == NULL
return NULL;
If number == root->data
return root->data;
If number < root->data
return search(root->left)
If number > root->data
return search(root->right)
129
CS221L - DATA STRUCTURES AND ALGORITHMS
8.2.1.2 Illustration:
Let us try to visualize this with a diagram.
4 is found
If the value is found, we return the value so that it gets propagated in each recursion step as
shown in the image below.
If you might have noticed, we have called return search(struct node*) four times. When we
return either the new node or NULL, the value gets returned again and again until
search(root) returns the final result.
130
CS221L - DATA STRUCTURES AND ALGORITHMS
If the value is found in any of the subtrees, it is propagated up so that in the end it is returned,
otherwise null is returned.
If the value is not found, we eventually reach the left or right child of a leaf node which is
NULL and it gets propagated and returned.
8.2.2.1 Algorithm:
If node == NULL
return createNode(data)
if (data < node->data)
node->left = insert(node->left, data);
else if (data > node->data)
node->right = insert(node->right, data);
return node;
131
CS221L - DATA STRUCTURES AND ALGORITHMS
8.2.2.2 Illustration:
The algorithm isn't as simple as it looks. Let's try to visualize how we add a number to an
existing BST.
132
CS221L - DATA STRUCTURES AND ALGORITHMS
We have attached the node but we still have to exit from the function without doing any
damage to the rest of the tree. This is where the return node; at the end comes in handy. In
the case of NULL , the newly created node is returned and attached to the parent node,
otherwise the same node is returned without any change as we go up until we return to the
root.
This makes sure that as we move back up the tree, the other node connections aren't changed.
Image showing the importance of returning the root element at the end so that the elements
don't lose their position during the upward recursion step.
133
CS221L - DATA STRUCTURES AND ALGORITHMS
We use the following steps to delete a node with one child from BST...
• Step 1 - Find the node to be deleted using search operation
• Step 2 - If it has only one child then create a link between its parent node and
child node.
• Step 3 - Delete the node using free function and terminate the function.
Case I:
In the first case, the node to be deleted is the leaf node. In such a case, simply
delete the node from the tree.
4 is to be deleted
134
CS221L - DATA STRUCTURES AND ALGORITHMS
In the second case, the node to be deleted lies has a single child node. In such a
case follow the steps below:
1. Replace that node with its child node.
2. Remove the child node from its original position.
6 is to be deleted
copy the value of its child to the node and delete the child
135
CS221L - DATA STRUCTURES AND ALGORITHMS
Final tree
Case III
In the third case, the node to be deleted has two children. In such a case follow the
steps below:
1. Get the inorder successor of that node.
2. Replace the node with the inorder successor.
3. Remove the inorder successor from its original position.
3 is to be deleted
136
CS221L - DATA STRUCTURES AND ALGORITHMS
#include <iostream>
using namespace std;
struct node {
int key;
struct node *left, *right;
};
// Create a node
struct node *newNode(int item) {
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->key = item;
temp->left = temp->right = NULL;
return temp;
}
// Inorder Traversal
void inorder(struct node *root) {
if (root != NULL) {
// Traverse left
inorder(root->left);
// Traverse root
cout << root->key << " -> ";
// Traverse right
inorder(root->right);
}
}
// Insert a node
struct node *insert(struct node *node, int key) {
// Return a new node if the tree is empty
if (node == NULL) return newNode(key);
return node;
}
137
CS221L - DATA STRUCTURES AND ALGORITHMS
return current;
}
// Deleting a node
struct node *deleteNode(struct node *root, int key) {
// Return if the tree is empty
if (root == NULL) return root;
// Driver code
int main() {
struct node *root = NULL;
root = insert(root, 8);
root = insert(root, 3);
root = insert(root, 1);
138
CS221L - DATA STRUCTURES AND ALGORITHMS
Average
Best Case Worst Case
Operation Case
Complexity Complexity
Complexity
139
CS221L - DATA STRUCTURES AND ALGORITHMS
140
CS221L - DATA STRUCTURES AND ALGORITHMS
Practice Problems:
Lab Activity #01:
Write a C++ program to implement a binary search tree (BST) given below and perform the
following operations:
5
/ \
3 7
/\ /\
2 46 8
1. Insert a new node into the BST.
2. Search for a given value in the BST.
3. Delete a node from the BST.
4. Print the elements of the BST in ascending order.
You can use any preferred data structure or approach to implement the BST.
141
CS221L - DATA STRUCTURES AND ALGORITHMS
142
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#09
AVL Trees
143
CS221L - DATA STRUCTURES AND ALGORITHMS
Avl tree
144
CS221L - DATA STRUCTURES AND ALGORITHMS
Left Rotate
In left-rotation, the arrangement of the nodes on the right is transformed into the
arrangements on the left node.
Algorithm
Left rotate
145
CS221L - DATA STRUCTURES AND ALGORITHMS
Right Rotate
In left-rotation, the arrangement of the nodes on the left is transformed into the arrangements
on the right node.
1. Let the initial tree be:
Initial tree
2. If x has a right subtree, assign y as the parent of the right subtree of x .
146
CS221L - DATA STRUCTURES AND ALGORITHMS
147
CS221L - DATA STRUCTURES AND ALGORITHMS
.
Left rotate x-y
2. Do right rotation on y-z.
148
CS221L - DATA STRUCTURES AND ALGORITHMS
In right-left rotation, the arrangements are first shifted to the right and then to the left.
1. Do right rotation on x-y.
149
CS221L - DATA STRUCTURES AND ALGORITHMS
New node
b) Go to the appropriate leaf node to insert a newNode using the following recursive
steps. Compare newKey with rootKey of the current tree.
a) If newKey < rootKey , call insertion algorithm on the left subtree of the current
node until the leaf node is reached.
b) Else if newKey > rootKey , call insertion algorithm on the right subtree of current
node until the leaf node is reached.
c) Else, return leafNode.
150
CS221L - DATA STRUCTURES AND ALGORITHMS
151
CS221L - DATA STRUCTURES AND ALGORITHMS
152
CS221L - DATA STRUCTURES AND ALGORITHMS
153
CS221L - DATA STRUCTURES AND ALGORITHMS
154
CS221L - DATA STRUCTURES AND ALGORITHMS
155
CS221L - DATA STRUCTURES AND ALGORITHMS
Remove w
3. Update balanceFactor of the nodes.
Update bf
4. Rebalance the tree if the balance factor of any of the nodes is not equal to -1, 0 or
1.
a) If balanceFactor of currentNode > 1,
i) If balanceFactor of leftChild >= 0, do right rotation.
156
CS221L - DATA STRUCTURES AND ALGORITHMS
#include <iostream>
using namespace std;
157
CS221L - DATA STRUCTURES AND ALGORITHMS
class Node {
public:
int key;
Node *left;
Node *right;
int height;
};
// Calculate height
int height(Node *N) {
if (N == NULL)
return 0;
return N->height;
}
158
CS221L - DATA STRUCTURES AND ALGORITHMS
// Rotate right
Node *rightRotate(Node *y) {
Node *x = y->left;
Node *T2 = x->right;
x->right = y;
y->left = T2;
y->height = max(height(y->left),
height(y->right)) +
1;
x->height = max(height(x->left),
height(x->right)) +
1;
return x;
}
// Rotate left
Node *leftRotate(Node *x) {
Node *y = x->right;
Node *T2 = y->left;
y->left = x;
x->right = T2;
x->height = max(height(x->left),
height(x->right)) +
1;
y->height = max(height(y->left),
height(y->right)) +
1;
return y;
159
CS221L - DATA STRUCTURES AND ALGORITHMS
// Insert a node
Node *insertNode(Node *node, int key) {
// Find the correct postion and insert the node
if (node == NULL)
return (newNode(key));
if (key < node->key)
node->left = insertNode(node->left, key);
else if (key > node->key)
node->right = insertNode(node->right, key);
else
return node;
160
CS221L - DATA STRUCTURES AND ALGORITHMS
// Delete a node
Node *deleteNode(Node *root, int key) {
// Find the node and delete it
if (root == NULL)
return root;
if (key < root->key)
161
CS221L - DATA STRUCTURES AND ALGORITHMS
if (root == NULL)
return root;
162
CS221L - DATA STRUCTURES AND ALGORITHMS
if (getBalanceFactor(root->left) >= 0) {
return rightRotate(root);
} else {
root->left = leftRotate(root->left);
return rightRotate(root);
}
}
if (balanceFactor < -1) {
if (getBalanceFactor(root->right) <= 0) {
return leftRotate(root);
} else {
root->right = rightRotate(root->right);
return leftRotate(root);
}
}
return root;
}
163
CS221L - DATA STRUCTURES AND ALGORITHMS
int main() {
Node *root = NULL;
root = insertNode(root, 33);
root = insertNode(root, 13);
root = insertNode(root, 53);
root = insertNode(root, 9);
root = insertNode(root, 21);
root = insertNode(root, 61);
root = insertNode(root, 8);
root = insertNode(root, 11);
printTree(root, "", true);
root = deleteNode(root, 13);
cout << "After deleting " << endl;
printTree(root, "", true);
}
164
CS221L - DATA STRUCTURES AND ALGORITHMS
Practice Problems:
a) Draw and design the resulting BST after 5 is removed, but before any rebalancing takes
place. Label each node in the resulting tree with its balance factor. Replace a node with both
children using an appropriate value from the node's left child.
b) Now rebalance the tree that results from (a). Draw a new tree for each rotation that occurs
when rebalancing the AVL Tree (you only need to draw one tree that results from an RL or
LR rotation). You do not need to label these trees with balance factors.
165
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#10
Graph Algorithms
166
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#10
Graph Algorithms
167
CS221L - DATA STRUCTURES AND ALGORITHMS
In the graph,
V = {0, 1, 2, 3}
E = {(0,1), (0,2), (0,3), (1,2)}
G = {V, E}
• Directed: In a directed graph, all edges are unidirectional; they point in a single
direction.
168
CS221L - DATA STRUCTURES AND ALGORITHMS
Since it is an undirected graph, for edge (0,2), we also need to mark edge (2,0); making the
adjacency matrix symmetric about the diagonal.
Edge lookup(checking if an edge exists between vertex A and vertex B) is extremely fast in
adjacency matrix representation but we have to reserve space for every possible link between
all vertices(V x V), so it requires more space.
169
CS221L - DATA STRUCTURES AND ALGORITHMS
An adjacency list is efficient in terms of storage because we only need to store the values for
the edges. For a graph with millions of vertices, this can mean a lot of saved space.
C++ Code for Adjacency list representation of a graph
#include <iostream>
#include<list>
using namespace std;
class graph{
public:
list<int> *adjlist;
int n;
graph(int v){
adjlist=new list<int> [v];
n=v;
}
void print(){
for(int i=0;i<n;i++){
cout<<i<<"-->";
for(auto it:adjlist[i]){
cout<<it<<" ";
}
cout<<endl;
170
CS221L - DATA STRUCTURES AND ALGORITHMS
}
cout<<endl;
}
};
int main() {
graph g(5);
g.addedge(1,2,true);
g.addedge(4,2,true);
g.addedge(1,3,true);
g.addedge(4,3,true);
g.addedge(1,4,true);
g.print();
}
Output
171
CS221L - DATA STRUCTURES AND ALGORITHMS
172
CS221L - DATA STRUCTURES AND ALGORITHMS
It begins at the root of the graph and investigates all nodes at the current depth level before
moving on to nodes at the next depth level.
To maintain track of the child nodes that have been encountered but not yet inspected, more
memory, generally you require a queue.
Algorithm of breadth-first search
Step 1: Consider the graph you want to navigate.
Step 2: Select any vertex in your graph, say v1, from which you want to traverse the graph.
Step 3: Examine any two data structures for traversing the graph.
Visited array (size of the graph)
Queue data structure
Step 4: Starting from the vertex, you will add to the visited array, and afterward, you will v1's
adjacent vertices to the queue data structure.
Step 5: Now, using the FIFO concept, you must remove the element from the queue, put it
into the visited array, and then return to the queue to add the adjacent vertices of the removed
element.
Step 6: Repeat step 5 until the queue is not empty and no vertex is left to be visited.
173
CS221L - DATA STRUCTURES AND ALGORITHMS
Graph::Graph(int V)
{
this->V = V;
adj = new list<int>[V];
}
void Graph::BFS(int s)
{
// Mark all the vertices as not visited
bool *visited = new bool[V];
for(int i = 0; i < V; i++)
visited[i] = false;
174
CS221L - DATA STRUCTURES AND ALGORITHMS
while(!queue.empty())
{
// Dequeue a vertex from queue and print it
s = queue.front();
cout << s << " ";
queue.pop_front();
return 0;
}
175
CS221L - DATA STRUCTURES AND ALGORITHMS
To maintain track of the child nodes that have been encountered but not yet inspected, more
memory, generally a stack, is required.
Algorithm of depth-first search
Step 1: Consider the graph you want to navigate.
Step 2: Select any vertex in our graph, say v1, from which you want to begin traversing the
graph.
Step 3: Examine any two data structures for traversing the graph.
Visited array (size of the graph)
Stack data structure
Step 4: Insert v1 into the array's first block and push all the adjacent nodes or vertices of
vertex v1 into the stack.
Step 5: Now, using the FIFO principle, pop the topmost element and put it into the visited
array, pushing all of the popped element's nearby nodes into it.
Step 6: If the topmost element of the stack is already present in the array, discard it instead of
inserting it into the visited array.
Step 7: Repeat step 6 until the stack data structure isn't empty.
class Graph{
int v; // number of vertices
176
CS221L - DATA STRUCTURES AND ALGORITHMS
Graph::Graph(int v){
this -> v = v;
adj = new vector < int >[v];
}
177
CS221L - DATA STRUCTURES AND ALGORITHMS
// traverse its adjacency list and recursively call dfs_util for all of
its neighbours!
// (only if the neighbour has not been visited yet!)
for(vector < int > :: iterator itr = adj[s].begin(); itr !=
adj[s].end(); itr++)
if(!visited[*itr])
dfs_util(*itr, visited);
}
int main()
{
// create a graph using the Graph class we defined above
Graph g(4);
g.add_edge(0, 1);
g.add_edge(0, 2);
g.add_edge(1, 2);
g.add_edge(2, 0);
g.add_edge(2, 3);
g.add_edge(3, 3);
cout << "Following is the Depth First Traversal of the provided graph"
<< "(starting from vertex 0): ";
g.dfs();
// output would be: 0 1 2 3
return 0;
}
178
CS221L - DATA STRUCTURES AND ALGORITHMS
struct Graph{
int v;
bool **adj;
public:
Graph(int vcount);
void addEdge(int u,int v);
void deleteEdge(int u,int v);
vector<int> DFS(int s);
void DFSUtil(int s,vector<int> &dfs,vector<bool> &visited);
};
Graph::Graph(int vcount){
this->v = vcount;
this->adj=new bool*[vcount];
for(int i=0;i<vcount;i++)
this->adj[i]=new bool[vcount];
for(int i=0;i<vcount;i++)
for(int j=0;j<vcount;j++)
adj[i][j]=false;
}
179
CS221L - DATA STRUCTURES AND ALGORITHMS
180
CS221L - DATA STRUCTURES AND ALGORITHMS
Conclusion
Both BFS and DFS are graph traversal algorithms. The most significant difference between
the two is that the BFS algorithm uses a Queue to find the shortest path, while the DFS
algorithm uses a Stack to find the shortest path.
Practice Problems:
Implement the Breadth-First Search algorithm in C++ for a given graph represented as an
adjacency list. Assume the graph has n nodes numbered from 0 to n-1. Write a function bfs
that takes the adjacency list and the starting node as parameters and prints the order in which
the nodes are visited during BFS.
For example, given the following adjacency list for a graph with 5 nodes:
0: 1 2
1: 0 2 3
2: 0 1 4
3: 1 4
4: 2 3
If the starting node is 0, the function bfs should print: 0, 1, 2, 3, 4.
Your task is to complete the implementation of the bfs function in C++.
181
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#11
Hash Table and Hash Function
in Data Structures
182
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#11
Hash Table and Hash Function in Data Structures
a) Key: A Key can be anything string or integer which is fed as input in the hash function
the technique that determines an index or location for storage of an item in a data structure.
b) Hash Function: The hash function receives the input key and returns the index
of an element in an array called a hash table. The index is known as the hash index.
c) Hash Table: Hash table is a data structure that maps keys to values using a special
function called a hash function. Hash stores the data in an associative manner in an array
where each data value has its own unique index.
183
CS221L - DATA STRUCTURES AND ALGORITHMS
Step 1: We know that hash functions (which is some mathematical formula) are used to
calculate the hash value which acts as the index of the data structure where the value will be
stored.
Step 3: Therefore, the numerical value by summation of all characters of the string:
“ab” = 1 + 2 = 3,
“cd” = 3 + 4 = 7 ,
“efg” = 5 + 6 + 7 = 18
Step 4: Now, assume that we have a table of size 7 to store these strings. The hash function
that is used here is the sum of the characters in key mod Table size. We can compute
the location of the string in the array by taking the sum(string) mod 7.
184
CS221L - DATA STRUCTURES AND ALGORITHMS
The above technique enables us to calculate the location of a given string by using a simple
hash function and rapidly find the value that is stored in that location. Therefore the idea of
hashing seems like a great way to store (key, value) pairs of the data in a table.
12 12%10 = 2 23
10 10%10 = 0 34
6 6% 10 = 6 54
23 23 % 10 = 3 76
54 54 %10 = 4 75
81 81 %10 = 1 87
185
CS221L - DATA STRUCTURES AND ALGORITHMS
0 1 2 3 4 5 6 7 8 9
34 87 23 76 75 54
As we can see above, there are high chances of collision as there could be 2 or more keys that
compute the same hash code resulting in the same index of elements in the hash table. A
collision cannot be avoided in case of hashing even if we have a large table size. We can
prevent a collision by choosing the good hash function and the implementation method.
Though there are a lot of implementation techniques used for it like Linear probing, open
hashing, etc. We will understand and implement the basic Open hashing technique also called
separate chaining. In this technique, a linked list is used for the chaining of values. Every
entry in the hash table is a linked list. So, when the new entry needs to be done, the index is
computed using the key and table size. Once computed, it is inserted in the list corresponding
to that index. When there are 2 or more values having the same hash value/ index, both
entries are inserted corresponding to that index linked with each other. For example,
Where 2 is the index of the hash table retrieved using the hash function
12, 22, 32 are the data values that will be inserted linked with each other
Code:
#include <iostream>
#include <list>
using namespace std;
class HashMapTable
{
// size of the hash table
186
CS221L - DATA STRUCTURES AND ALGORITHMS
inttable_size;
// Pointer to an array containing the keys
list<int> *table;
public:
// creating constructor of the above class containing all
the methods
HashMapTable(int key);
// hash function to compute the index using table_size and
key
inthashFunction(int key) {
return (key % table_size);
}
// inserting the key in the hash table
void insertElement(int key);
// deleting the key in the hash table
void deleteElement(int key);
// displaying the full hash table
void displayHashTable();
};
//creating the hash table with the given table size
HashMapTable::HashMapTable(intts)
{
this->table_size = ts;
table = new list<int>[table_size];
}
// insert function to push the keys in hash table
void HashMapTable::insertElement(int key)
{
187
CS221L - DATA STRUCTURES AND ALGORITHMS
188
CS221L - DATA STRUCTURES AND ALGORITHMS
// Main function
intmain()
{
// array of all the keys to be inserted in hash table
intarr[] = {20, 34, 56, 54, 76, 87};
int n = sizeof(arr)/sizeof(arr[0]);
// table_size of hash table as 6
HashMapTableht(6);
for (inti = 0; i< n; i++)
ht.insertElement(arr[i]);
// deleting element 34 from the hash table
ht.deleteElement(34);
// displaying the final data of hash table
ht.displayHashTable();
return 0;
}
Output:
Explanation:
In the above code, an array is created for all the keys that need to be inserted in the has table.
Class and constructors are created for hashMapTable to calculate the hash function using the
189
CS221L - DATA STRUCTURES AND ALGORITHMS
formula mentioned above. The list is created as the pointer to the array of key values.
Specific functions are created for the insertion, deletion, and display of the hash table and
called from the main method. While insertion, if 2 or more elements have the same index,
they are inserted using the list one after the other.
• Division Method.
• Mid Square Method.
• Folding Method.
• Multiplication Method
190
CS221L - DATA STRUCTURES AND ALGORITHMS
• Should have a low load factor(number of items in the table divided by the size of
the table).
191
CS221L - DATA STRUCTURES AND ALGORITHMS
1) Separate Chaining
The idea is to make each cell of the hash table point to a linked list of records that have the
same hash function value. Chaining is simple but requires additional memory outside the
table.
Example: We have given a hash function and we have to insert some elements in the hash
table using a separate chaining method for collision resolution technique.
Hash function = key % 5,
Elements = 12, 15, 22, 25 and 37.
Let’s see step by step approach to how to solve the above problem:
Step 1: First draw the empty hash table which will have a possible range of hash values
from 0 to 4 according to the hash function provided.
192
CS221L - DATA STRUCTURES AND ALGORITHMS
Hash table
Step 2: Now insert all the keys in the hash table one by one. The first key to be inserted is
12 which is mapped to bucket number 2 which is calculated by using the hash function
12%5=2.
Step 3: Now the next key is 22. It will map to bucket number 2 because 22%5=2. But
bucket 2 is already occupied by key 12.
193
CS221L - DATA STRUCTURES AND ALGORITHMS
Step 4: The next key is 15. It will map to slot number 0 because 15%5=0.
Step 5: Now the next key is 25. Its bucket number will be 25%5=0. But bucket 0 is already
occupied by key 25. So separate chaining method will again handle the collision by creating a
linked list to bucket 0.
194
CS221L - DATA STRUCTURES AND ALGORITHMS
Hence In this way, the separate chaining method is used as the collision resolution technique.
2) Open Addressing
In open addressing, all elements are stored in the hash table itself. Each table entry contains
either a record or NIL. When searching for an element, we examine the table slots one by one
until the desired element is found or it is clear that the element is not in the table.
In linear probing, the hash table is searched sequentially that starts from the original location
of the hash. If in case the location that we get is already occupied, then we check for the next
location.
Algorithm:
Example: Let us consider a simple hash function as “key mod 5” and a sequence of keys
that are to be inserted are 50, 70, 76, 85, 93.
195
CS221L - DATA STRUCTURES AND ALGORITHMS
Step1: First draw the empty hash table which will have a possible range of hash values
from 0 to 4 according to the hash function provided.
Hash table
Step 2: Now insert all the keys in the hash table one by one. The first key is 50. It will map
to slot number 0 because 50%5=0. So insert it into slot number 0.
Step 3: The next key is 70. It will map to slot number 0 because 70%5=0 but 50 is already
at slot number 0 so, search for the next empty slot and insert it.
196
CS221L - DATA STRUCTURES AND ALGORITHMS
Step 4: The next key is 76. It will map to slot number 1 because 76%5=1 but
70 is already at slot number 1 so, search for the next empty slot and insert it.
Step 5: The next key is 93 It will map to slot number 3 because 93%5=3, So insert it into
slot number 3.
197
CS221L - DATA STRUCTURES AND ALGORITHMS
Example: Let us consider table Size = 7, hash function as Hash(x) = x % 7 and collision
resolution strategy to be f(i) = i2 . Insert = 22, 30, and 50
198
CS221L - DATA STRUCTURES AND ALGORITHMS
Hash table
Step 3: Inserting 50
199
CS221L - DATA STRUCTURES AND ALGORITHMS
Hash(25) = 50 % 7 = 1
In our hash table slot 1 is already occupied. So, we will search for slot 1+12, i.e. 1+1 = 2,
Again slot 2 is found occupied, so we will search for cell 1+22, i.e.1+4 = 5,
Now, cell 5 is not occupied so we will place 50 in slot 5.
The first hash function is h1(k) which takes the key and gives out a location on the hash
table. But if the new location is not occupied or empty then we can easily place our key.
But in case the location is occupied (collision) we will use secondary hash-function h2(k) in
combination with the first hash-function h1(k) to find the new location on the hash table.
200
CS221L - DATA STRUCTURES AND ALGORITHMS
Example:
Insert the keys 27, 43, 692, 72 into the Hash Table of size 7. where first hash-function is h1
(k) = k mod 7 and second hash-function is h2(k) = 1 + (k mod 5)
Step 1: Insert 27
27 % 7 = 6, location 6 is empty so insert 27 into 6 slot.
Step 2: Insert 43
43 % 7 = 1, location 1 is empty so insert 43 into 1 slot.
201
CS221L - DATA STRUCTURES AND ALGORITHMS
202
CS221L - DATA STRUCTURES AND ALGORITHMS
Step 4: Insert 72
72 % 7 = 2, but location 2 is already being occupied and this is a collision.
So we need to resolve this collision using double hashing.
hnew = [h1(72) + i * (h2(72)] % 7
= [2 + 1 * (1 + 72 % 5)] % 7
= 5 % 7
= 5,
203
CS221L - DATA STRUCTURES AND ALGORITHMS
204
CS221L - DATA STRUCTURES AND ALGORITHMS
• Hash is used for cache mapping for fast access to the data.
• Hash can be used for password verification.
• Hash is used in cryptography as a message digest.
• Rabin-Karp algorithm for pattern matching in a string.
• Calculating the number of different substrings of a string.
Practice Problems:
Linear probing is a collision resolving technique in Open Addressed Hash tables. In
this method, each cell of a hash table stores a single key–value pair. If a collision
occurs by mapping a new key to a cell of the hash table that is already occupied by
another key. This method searches the table for the following closest free location
and inserts the new key there.
Using the given algorithm below to add some data into the hash table, design a
C++ program to Implement Hash Tables with Linear Probing.
Begin
Declare Function Insert(int k, int v)
int hash_val = HashFunc(k)
intialize init = -1
intialize delindex = -1
while (hash_val != init and
(ht[hash_val]==DelNode::getNode() or ht[hash_val]
!= NULL and ht[hash_val]->k != k))
if (init == -1)
init = hash_val
205
CS221L - DATA STRUCTURES AND ALGORITHMS
if (ht[hash_val] == DelNode::getNode())
delindex = hash_val
hash_val = HashFunc(hash_val + 1)
if (ht[hash_val] == NULL || hash_val == init)
if(delindex != -1)
ht[delindex] = new HashTable(k, v)
else
ht[hash_val] = new HashTable(k, v)
if(init != hash_val)
if (ht[hash_val] != DelNode::getNode())
if (ht[hash_val] != NULL)
if (ht[hash_val]->k== k)
ht[hash_val]->v = v
else
ht[hash_val] = new HashTable(k, v)
End.
206
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab#12
Open Ended Lab
207
CS221L - DATA STRUCTURES AND ALGORITHMS
Lab 12
Open Ended Lab
An open-ended lab is where students are given the freedom to develop their own
experiments, instead of merely following the already set guidelines from a lab manual or
elsewhere.
Making labs open-ended pushes students to think for themselves and think harder. The
students here have to devise their own strategies and back them with explanations, theory and
logical justification. This not only encourages students to come up with their experiments, but
requires them to defend themselves and their experiment, if questioned.
Different lab classes may vary in their degrees of open-endedness. However, there are three
general areas that can be made open-ended:
Concept
In order to make this stage open-ended, the teacher may give the students a Problem
Statement with a purpose and not the procedure. The students would then have to come up
with their own experiments to back the theory or fulfil the purpose. This helps boost
confidence in students, as they can proudly say that they did the experiment on their own.
We use Schwab and Heron’s scale of laboratory openness. In the first level the teacher posed
a problem, which student then tried to answer by using different methods. In the second level
the teacher posed a problem, but this time the students had to develop a method themselves.
In the third level of inquiry the students had to both pose the problem and develop a suitable
method.
Level
Our open-ended lab conforms to level 2 of Schwab/Herron Levels of Laboratory Openness.
208
CS221L - DATA STRUCTURES AND ALGORITHMS
I. REFERENCES
Text Books:
Reference Books:
• Data Structures and Algorithms Made Easy: Data Structure and Algorithmic
• Easy Learning Data Structures & Algorithms C++ by Yng Hu, 2019
THE END
209
CS221L - DATA STRUCTURES AND ALGORITHMS
210