0% found this document useful (0 votes)
30 views19 pages

Summer of Science End-Term Report: Data Structures and Algorithms

This document provides a 3-paragraph summary of the end-term report submitted by Alok Kumar on data structures and algorithms: 1) It discusses time complexity and different complexity classes like constant, logarithmic, linear, quadratic, and polynomial time. An example O(n^3) maximum subarray sum algorithm is provided. 2) Recursion is defined as a process where a function calls itself directly or indirectly. Properties of recursion like base case, recursive case, ensuring termination, and combining solutions are explained. 3) Types of recursion like tail and head recursion are defined with examples. Tail recursion is when the recursive call is the last statement, and head recursion is when the recursive call

Uploaded by

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

Summer of Science End-Term Report: Data Structures and Algorithms

This document provides a 3-paragraph summary of the end-term report submitted by Alok Kumar on data structures and algorithms: 1) It discusses time complexity and different complexity classes like constant, logarithmic, linear, quadratic, and polynomial time. An example O(n^3) maximum subarray sum algorithm is provided. 2) Recursion is defined as a process where a function calls itself directly or indirectly. Properties of recursion like base case, recursive case, ensuring termination, and combining solutions are explained. 3) Types of recursion like tail and head recursion are defined with examples. Tail recursion is when the recursive call is the last statement, and head recursion is when the recursive call

Uploaded by

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

Summer Of Science

End-Term Report
Data Structures and Algorithms

Name - Alok Kumar


210070006

Mentor - Ankit
3 August 2023

Academic Report 1


DSA
1. Time Complexity
The efficiency of algorithms is important in competitive programming.
Usually, it is easy to design an algorithm that solves the problem slowly, but
the real challenge is to invent a fast algorithm.
The time complexity of an algorithm estimates how much time the
algorithm will use for some input. The idea is to represent the efficiency as a
function whose parameter is the size of the input.
1.1 Calculation Rules
The time complexity of an algorithm is denoted O(···) where the three
dots represent some function. Usually, the variable n denotes the input size.
Some properties:
Loops: - If there are k nested loops, the time complexity is O(nk).
Order: - A time complexity does not tell us the exact number of times the
code inside a loop is executed, but it only shows the order of magnitude.
Phases: If the algorithm consists of consecutive phases, the total time
complexity is the largest time complexity of a single phase. The reason for
this is that the slowest phase is usually the bottleneck of the code.
Recursion:- The time complexity of a recursive function depends on the
number of times the function is called and the time complexity of a single
call. The total time complexity is the product of these values.
1.2 Complexity Classes
O(1): The running time of a constant-time algorithm does not depend on
the input size.
O(log n) A logarithmic algorithm often halves the input size at each
step.
O( n ) A square root algorithm is slower than O(log n) but faster than
O(n).
O(n) A linear algorithm goes through the input a constant number of
times. This is often the best possible time complexity.
O(nlogn) This time complexity often indicates that the algorithm sorts
the input, because the time complexity of efficient sorting algorithms is
O(nlogn).
O(n2) A quadratic algorithm often contains two nested loops.

Academic Report 2

An algorithm is polynomial if its time complexity is at most O(nk)


where k is a constant. All the above time complexities except O(2n) and
O(n!) are polynomial. In practice, the constant k is usually small, and
therefore a polynomial time complexity roughly means that the algorithm is
efficient.
An Example:
The following code implements the Maximum Subarray sum algorithm:
int best = 0;
for (int a = 0; a < n; a++) {
for (int b = a; b < n; b++) {
int sum = 0;
for (int k = a; k <= b; k++) {
sum += array[k];
}

best = max(best,sum);
}
}
cout << best << "\n";

The time complexity of the algorithm is O(n3), because it consists of


three nested loops that go through the input.

2. Recursion
The process in which a function calls itself directly or indirectly is called
recursion and the corresponding function is called a recursive function.
Using a recursive algorithm, certain problems can be solved quite easily.
A task that can be defined with its similar subtask, recursion is one of the
best solutions for it. For example; The Factorial of a number.
Properties:
• Performing the same operations multiple times with different inputs.
• In every step, we try smaller inputs to make the problem smaller.
• Please condition is needed to stop the request otherwise infinite Loop
will occur.
Steps for implementing Recursion:
1. Define a base case: Identify the simplest case for which the solution
is known or trivial. This is the stopping condition for the recursion.

Academic Report 3

2. Define a recursive case: Define the problem in terms of smaller


subproblems. Break the problem down into smaller versions of itself, and
call the function recursively to solve each subproblem.
3. Ensure the recursion terminates: Make sure that the recursive
function eventually reaches the base case, and does not enter an infinite
loop.
4. Combine the Solution.
Types of Recursion:
1. Tail Recursion: If a recursive function calling itself and that recursive
call is the last statement in the function then it’s known as Tail
Recursion.
Eg:- void fint n)
{
if (n > 0) {
cout << n << " ";

// Last statement in the function


fun(n - 1);
}
}
2. Head Recursion: If a recursive function calling itself and that
recursive call is the first statement in the function then it’s known as
Head Recursion.
void fun(int n)
{
if (n > 0) {

// First statement in the function


fun(n - 1);

cout << " "<< n;


}}

Academic Report 4

3. Tree Recursion: If a recursive function calling itself for one time then
it’s known as Linear Recursion. Otherwise if a recursive function calling
itself for more than one time then it’s known as Tree Recursion.
void fun(int n)
{
if (n > 0)
{
cout << " " << n;

// Calling once
fun(n - 1);

// Calling twice
fun(n - 1);
}
}

3. BackTracking:
A backtracking algorithm begins with an empty solution and extends
the solution step by step. The search recursively goes through all different
ways how a solution can be constructed.
So basically, the idea behind the backtracking technique is that it
searches for a solution to a problem among all the available options.
Initially, we start the backtracking from one possible option and if the
problem is solved with that selected option then we return the solution else
we backtrack and select another option from the remaining available options.
There also might be a case where none of the options will give you the
solution and hence we understand that backtracking won’t give any solution
to that particular problem.
Eg: consider the problem of calculating the number of ways n queens
can be placed on an n × n chessboard so that no two queens attack each other.
void search(int y) {
if (y == n) {
count++;

Academic Report 5

return; }

for (int x = 0; x < n; x++) {


if (column[x] || diag1[x+y] || diag2[x-y+n-1]) continue;
column[x] = diag1[x+y] = diag2[x-y+n-1] = 1;
search(y+1);
column[x] = diag1[x+y] = diag2[x-y+n-1] = 0;
}}

The search begins by calling search(0). The size of the board is n × n, and the
code calculates the number of solutions to count. The code assumes that the rows
and columns of the board are numbered from 0 to n − 1. When the function
search is called with parameter y, it places a queen on row y and then calls itself
with parameter y + 1. Then, if y = n, a solution has been found and the variable
count is increased by one.

4. More Data Structures


4.1 Arrays
An array is a collection of items of same data type stored at contiguous
memory locations.
This makes it easier to calculate the position of each element by simply
adding an offset to a base value, i.e., the memory location of the first element
of the array (generally denoted by the name of the array). The base value is
index 0 and the difference between the two indexes is the offset.
In C language, the array has a fixed size meaning once the size is given
to it, it cannot be changed i.e. you can’t shrink it nor can you expand it. The
reason was that for expanding if we change the size we can’t be sure ( it’s not
possible every time) that we get the next memory location to us for free.
Types of Indexing:
• Zero-based indexing: the first element of the air is indexed by a
subscript of 0.
• One-based: indexing the first element of the area is indexed by 1
• N-based: indexing the peace index of an airy can be freely chosen.
Array Initialisation:
1. Passing no value within these initialiser: int arr[5] = {};
2. Bypassing specific values within the initialiser;
3. Bypassing specific values within the initialiser but not declaring the
size.

Academic Report 6

4.2 Vectors:
Vectors are the same as dynamic arrays with the ability to resize itself
automatically when an element is inserted or deleted, with their storage being
handled automatically by the container. Vector elements are placed in
contiguous storage so that they can be accessed and traversed using iterators.
In vectors, data is inserted at the end. Inserting at the end takes differential
time, as sometimes the array may need to be extended. Removing the last
element takes only constant time because no resizing happens. Inserting and
erasing at the beginning or in the middle is linear in time.
The Time Complexity for different Operations in Vectors are:
Random access – constant O(1)
Insertion or removal of elements at the end – constant O(1)
Insertion or removal of elements – linear in the distance to the end of the
vector O(N)
Knowing the size – constant O(1)
Resizing the vector- Linear O(N)
Different Syntax are:
size() – Returns the number of elements in the vector.
max_size() – Returns the maximum number of elements that the vector
can hold.
capacity() – Returns the size of the storage space currently allocated to
the vector expressed as number of elements.
resize(n) – Resizes the container so that it contains ‘n’ elements.
empty() – Returns whether the container is empty.
shrink_to_fit() – Reduces the capacity of the container to fit its size and
destroys all elements beyond the capacity.
reserve() – Requests that the vector capacity be at least enough to
contain n elements.
assign() – It assigns new value to the vector elements by replacing old
ones
push_back() – It push the elements into a vector from the back
pop_back() – It is used to pop or remove elements from a vector from
the back.
insert() – It inserts new elements before the element at the specified
position

Academic Report 7

erase() – It is used to remove elements from a container from the


specified position or range.
swap() – It is used to swap the contents of one vector with another vector
of same type. Sizes may differ.
clear() – It is used to remove all the elements of the vector container
emplace() – It extends the container by inserting new element at position
emplace_back() – It is used to insert a new element into the vector
container, the new element is added to the end of the vector.
4.3 Strings:
Strings are defined as an array of characters. The difference between a
character array and a string is the string is terminated with a special character
‘\0’.
Eg: “Alok”
in C, a string can be referred to either using a character pointer or as a
character array. When strings are declared as character arrays, they are stored
like other types of arrays in C. For example, if str[] is an auto variable than
the string is stored in the stack segment, if it’s a global or static variable then
stored in the data segment, etc.
Functions:
getline() : This function is used to store a stream of characters as entered
by the user in the object memory.
push_back(): This function is used to input a character at the end of the
string.
pop_back() : this function is used to delete the last character from the
string.
capacity() : This function returns the capacity allocated to the string,
which can be equal to or more than the size of the string.
resize() : This function changes the size of the string, the size can be
increased or decreased.
length() : This function finds the length of the string.
begin()
end()

Academic Report 8

5. Linked List:
A linked list is a linear data structure, in which the elements are not
stored at contiguous memory locations. The elements in a linked list are
linked using pointers as shown in the below image:

Fig 1
Here the pointers are Head and Next in case of singly linked list. The
next pointer of the last element points to null. The head point points to the
first element of the linked list.
Following are the types of linked list:
Singly linked list: It is the simplest type of linked list in which every
node contains some data and a pointer to the next node of the same data
type.
The node contains a pointer to the next node means that the node stores
the address of the next node in the sequence. A single linked list allows the
traversal of data only in one way. The format is shown above in fig 1.
Its structure: class Node {
public:
int data;
Node* next;
};

Doubly linked list: A doubly linked list or a two-way linked list is a


more complex type of linked list that contains a pointer to the next as well as
the previous node in sequence.
Therefore, it contains three parts of data, a pointer to the next node, and a
pointer to the previous node. This would enable us to traverse the list in the
backward direction as well. The format is shown below.

Academic Report 9

Its structure is : struct Node {


int data;
// Pointer to next node in DLL
struct Node* next;
// Pointer to the previous node in DLL
struct Node* prev;
};
Circular Linked List: A circular linked list is that in which the last node
contains the pointer to the first node of the list.
While traversing a circular linked list, we can begin at any node and
traverse the list in any direction forward and backward until we reach the
same node we started. Thus, a circular linked list has no beginning and no
end. Below is the image for the same:

Structure: class Node {


public:
int data;
// Pointer to next node in CLL
Node* next;
};

Academic Report 10

6. Stacks:
Stack is a linear data structure that follows a particular order in which the
operations are performed. The order may be LIFO(Last In First Out) or
FILO(First In Last Out). LIFO implies that the element that is inserted last,
comes out first and FILO implies that the element that is inserted first, comes
out last.

It can be implemented through an array or linked lists. Some of its main


operations are: push(), pop(), top(), isEmpty(), size(), etc.
Stack Operations:
void push(int data): When this operation is performed, an element is
inserted into the stack.
int pop(): When this operation is performed, an element is removed
from the top of the stack and is returned.
int top(): This operation will return the last inserted element that is at the
top without removing it.
int size(): This operation will return the size of the stack i.e. the total
number of elements present in the stack.
int isEmpty(): This operation indicates whether the stack is empty or
not.
int isFull(): This operation indicates whether the stack is full or not

Academic Report 11

Types of Stacks:
Register Stack: This type of stack is also a memory element present in
the memory unit and can handle a small amount of data only. The height of
the register stack is always limited as the size of the register stack is very
small compared to the memory.
Memory Stack: This type of stack can handle a large amount of memory
data. The height of the memory stack is flexible as it occupies a large amount
of memory data.
7. Queues:
A Queue is defined as a linear data structure that is open at both ends
and the operations are performed in First In First Out (FIFO) order. We
define a queue to be a list in which all additions to the list are made at one
end, and all deletions from the list are made at the other end. The element
which is first pushed into the order, the operation is first performed on that.

FIFO Principle of Queue:


• A Queue is like a line waiting to purchase tickets, where the first
person in line is the first person served. (i.e. First come first serve).
• Position of the entry in a queue ready to be served, that is, the first
entry that will be removed from the queue, is called the front of the
queue(sometimes, head of the queue), similarly, the position of the last
entry in the queue, that is, the one most recently added, is called the
rear (or the tail) of the queue.
• Characteristics of Queue:
• Queue can handle multiple data.

Academic Report 12

• We can access both ends.


• They are fast and flexible.
Queue Representation:
Like stacks, Queues can also be represented in an array: In this
representation, the Queue is implemented using the array. Variables used in
this case are
• Queue: the name of the array storing queue elements.
• Front: the index where the first element is stored in the array
representing the queue.
• Rear: the index where the last element is stored in an array
representing the queue.
• Structure: void showq(queue<int> gq)
{
queue<int> g = gq;
while (!g.empty()) {
cout << '\t' << g.front();
g.pop();
}
cout << '\n';
}

Academic Report 13

POPOST MID-TERM
8. TREEs
A tree data structure is a hierarchical structure that is used to represent
and organize data in a way that is easy to navigate and search. It is a
collection of nodes that are connected by edges and has a hierarchical
relationship between the nodes.
The topmost node of the tree is called the root, and the nodes below it
are called the child nodes. Each node can have multiple child nodes, and
these child nodes can also have their own child nodes, forming a recursive
structure.

8.1 Basic Terms:


1. Parent Node: The node which is a predecessor of a node is called the
parent node of that node.
2. The node which is the immediate successor of a node is called the
child node of that node
3. The topmost node of a tree or the node which does not have any
parent node is called the root node.
8.2 Representation:
struct Node
{
int data;
struct Node *first_child;
struct Node *second_child;
struct Node *third_child;

Academic Report 14



.
.
.
struct Node *nth_child;
};
Types of Trees:
1. Binary
2. Multinary
The data in a tree are not stored in a sequential manner i.e., they are not
stored linearly. Instead, they are arranged on multiple levels or we can say it
is a hierarchical structure. For this reason, the tree is considered to be a non-
linear data structure.
Traversal:
Preorder Traversal – perform Traveling a tree in a pre-order manner in
the data structure.
In order Traversal – perform Traveling a tree in an in-order manner.
Post-order Traversal –perform Traveling a tree in a post-order manner.
8.3 Properties of Tree Data Structure:
1. Number of edges: An edge can be defined as the connection between
two nodes. If a tree has N nodes then it will have (N-1) edges.
2. Depth of a node: The depth of a node is defined as the length of the
path from the root to that node.
3. Height of a node: The height of a node can be defined as the length
of the longest path from the node to a leaf node of the tree.
4. Height of the Tree: The height of a tree is the length of the longest
path from the root of the tree to a leaf node of the tree.
5. Degree of a Node: The total count of subtrees attached to that node is
called the degree of the node. The degree of a leaf node must be 0. The
degree of a tree is the maximum degree of a node among all the nodes in
the tree.
8.4 Advantages of Trees:
Tree offer Efficient Searching Depending on the type of tree, with
average search times of O(log n) for balanced trees like AVL.
Trees provide a hierarchical representation of data, making it easy to
organize and navigate large amounts of information.

Academic Report 15




The recursive nature of trees makes them easy to traverse and


manipulate using recursive algorithms.
8.5 Need for Trees:
One reason to use trees might be because you want to store information
that naturally forms a hierarchy.
Trees (with some ordering e.g., BST) provide moderate access/search
(quicker than Linked List and slower than arrays).
Trees provide moderate insertion/deletion (quicker than Arrays and
slower than Unordered Linked Lists).
Like Linked Lists and unlike Arrays, Trees don’t have an upper limit on
the number of nodes as nodes are linked using pointers.
9. Hashing:
Hashing is a technique or process of mapping keys, and values into the
hash table by using a hash function. It is done for faster access to elements.
The efficiency of mapping depends on the efficiency of the hash function
used.
Let a hash function H(x) maps the value x at the index x%10 in an
Array. For example if the list of values is [11,12,13,14,15] it will be stored at
positions {1,2,3,4,5} in the array or Hash table respectively.

9.1 Need for Hashing DS


Now we are looking for a data structure that can store the data and
search in it in constant time, i.e. in O(1) time. This is how Hashing data
structure came into play. With the introduction of the Hash data structure, it

Academic Report 16

is now possible to easily store data in constant time and retrieve them in
constant time as well.
9.2 Components of Hashing:
There are majorly three components of hashing:
1. 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.
2. 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.
3. 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.
COLLISION:
The hashing process generates a small number for a big key, so there is a
possibility that two keys could produce the same value. The situation where
the newly inserted key maps to an already occupied, and it must be handled
using some collision handling technology.
9.3 Advantages of hashing in data structure:
1. Key-value support: Hashing is ideal for implementing key-value
data structures.
2. Fast data retrieval: Hashing allows for quick access to elements
with constant-time complexity.
3. Efficiency: Insertion, deletion, and searching operations are highly
efficient.
4. Memory usage reduction: Hashing requires less memory as it
allocates a fixed space for storing elements.
5. Security and encryption: Hashing is essential for secure data
storage and integrity verification.

Academic Report 17

10. Graphs:
A Graph is a non-linear data structure consisting of vertices and edges.
The vertices are sometimes also referred to as nodes and the edges are lines
or arcs that connect any two nodes in the graph. More formally a Graph is
composed of a set of vertices( V ) and a set of edges( E ). The graph is
denoted by G(E, V).

10.1 Components of a graph:


Vertices: Vertices are the fundamental units of the graph. Sometimes,
vertices are also known as vertex or nodes. Every node/vertex can be labeled
or unlabelled.
Edges: Edges are drawn or used to connect two nodes of the graph. It
can be ordered pair of nodes in a directed graph. Edges can connect any two
nodes in any possible way. There are no rules. Sometimes, edges are also
known as arcs. Every edge can be labeled/unlabelled.

10.2 Some types of Graphs:


1. Undirected Graphs: A graph in which edges have no direction, i.e.,
the edges do not have arrows indicating the direction of traversal.
2. Directed Graphs: A graph in which edges have a direction, i.e., the
edges have arrows indicating the direction of traversal.
3. Bipartite Graphs: A graph in which the vertices can be divided into
two disjoint sets such that every edge connects a vertex in one set to a
vertex in the other set.

Academic Report 18

4. Finite Graphs: A graph is said to be finite if it has a finite number of


vertices and a finite number of edges. A finite graph is a graph with a
finite number of vertices and edges.
5. Trivial Graph: A graph is said to be trivial if a finite graph contains
only one vertex and no edge. A trivial graph is a graph with only one
vertex and no edges. It is also known as a singleton graph or a single
vertex graph.
6. Null Graph: A graph of order n and size zero is a graph where there
are only isolated vertices with no edges connecting any pair of vertices.A
null graph is a graph with no edges.

Academic Report 19

You might also like