You are on page 1of 30

UNIT 1

What is an Algorithm?
Algorithms are rules or instructions that are formulated in a finite, sequential
order to solve problems and get the required results. They give the pseudocode
for problems and can be implemented in several languages as they are not
language specific.

Qualities of Good Algorithms


1. Input and output should be defined precisely
2. The steps need to be finite, clear and understandable
3. Algorithms should be most effective among many different ways to solve a
problem.
4. An algorithm shouldn't include computer code. Instead, the algorithm
should be written in such a way that it can be used in different programming
languages.

How do you Write Algorithms?


Algorithms are generally written as a combination of user-understandable
language and some common programming languages. They are commonly
written down in steps however, it is not always necessary to do so. There are no
distinct rules to formulate algorithms, but you will need to keep the following
points in mind:

1. Figure out what is the exact problem


2. Determine where you need to start
3. Determine where you need to stop
4. Formulate the intermediate steps
5. Review your steps

For example, if you have to formulate an algorithm to check if a student has


passed in an exam or not, you can follow the given steps:
Step 1: START

Step 2: Declare two variables x, y

Step 3: Store the marks obtained by the student in x

Step 4: Store the minimum passing score in y

Step 5: Check if x is greater than or equal to y.

If yes, then return “Pass” else return “Fail”

Step 6: STOP

However, you can manipulate the steps according to your preference. For
instance, you can assign the values to the variables in step 2 itself rather than
taking steps 3 and 4. This way, a single problem can have multiple solutions and
it depends on the problem and the programmer to choose the most feasible and
reliable solution.

Algorithm Examples

Algorithm 1: Add two numbers entered by the user


Step 1: Start

Step 2: Declare variables num1, num2 and sum.

Step 3: Read values num1 and num2.

Step 4: Add num1 and num2 and assign the result to sum.

sum←num1+num2

Step 5: Display sum

Step 6: Stop
Algorithm 2: Find the largest number among three
numbers
Step 1: Start

Step 2: Declare variables a,b and c.

Step 3: Read variables a,b and c.

Step 4: If a > b

If a > c

Display a is the largest number.

Else

Display c is the largest number.

Else

If b > c

Display b is the largest number.

Else

Display c is the greatest number.

Step 5: Stop

Programming is all about data structures and algorithms. Data structures are
used to hold data while algorithms are used to solve the problem using that
data.

Data structures and algorithms (DSA) goes through solutions to standard


problems in detail and gives you an insight into how efficient it is to use each
one of them. It also teaches you the science of evaluating the efficiency of an
Data structures in Python:

Built-in Data-structures:

Lists: Stores indexed elements that are changeable and can contain duplicate
items

Tuples: Stores indexed, unchangeable elements that can have duplicate copies

Dictionaries: Store key-value pairs that are changeable

Sets: Contains unordered, unique elements that are mutable

User-defined Data-structures:

Arrays: Similar to Lists, but store single type of elements

Stack: Linear LIFO (Last-In-First-Out) Data structure

Queues: Linear FIFO (First-In-First-Out) data structure


Trees: Non-Linear data structures having a root and nodes

Linked Lists: Linear data structures that are linked with pointers

Graphs: Store a collection of points or nodes along with edges

Hash Maps: In Python, Hash Maps are the same as Dictionaries

Linear vs Non-Linear data structure

What is Data structure?


A data structure is a technique of storing and organizing the data in such a way that
the data can be utilized in an efficient manner.A data structure is designed in such a
way that it can work with various algorithms. A data structure is classified into two
categories:

o Linear data structure

o Non-linear data structure

What is the Linear data structure?


A linear data structure is a structure in which the elements are stored sequentially,
and the elements are connected to the previous and the next element. As the
elements are stored sequentially, so they can be traversed or accessed in a single
run. The implementation of linear data structures is easier as the elements are
sequentially organized in memory. The data elements in an array are traversed one
after another and can access only one element at a time.

The types of linear data structures are Array, Queue, Stack, Linked List.

o Array: An array consists of data elements of a same data type. For example,
if we want to store the roll numbers of 10 students, so instead of creating 10
integer type variables, we will create an array having size 10. Therefore, we
can say that an array saves a lot of memory and reduces the length of the
code.

o Stack: It is linear data structure that uses the LIFO (Last In-First Out) rule in
which the data added last will be removed first. The addition of data element
in a stack is known as a push operation, and the deletion of data element
form the list is known as pop operation.

o Queue: It is a data structure that uses the FIFO rule (First In-First Out). In
this rule, the element which is added first will be removed first. There are two
terms used in the queue front end and rear The insertion operation
performed at the back end is known ad enqueue, and the deletion operation
performed at the front end is known as dequeue.
o Linked list: It is a collection of nodes that are made up of two parts, i.e.,
data element and reference to the next node in the sequence.

What is a Non-linear data structure?


A non-linear data structure is also another type of data structure in which the data
elements are not arranged in a contiguous manner. As the arrangement is
nonsequential, so the data elements cannot be traversed or accessed in a single run.
In the case of linear data structure, element is connected to two elements (previous
and the next element), whereas, in the non-linear data structure, an element can be
connected to more than two elements.

Trees and Graphs are the types of non-linear data structure.

o Tree

It is a non-linear data structure that consists of various linked nodes. It has a


hierarchical tree structure that forms a parent-child relationship. The diagrammatic
representation of a tree data structure is shown below:

For example, the posts of employees are arranged in a tree data structure like
managers, officers, clerk. In the above figure, A represents a
manager, B and C represent the officers, and other nodes represent the clerks.
o Graph

A graph is a non-linear data structure that has a finite number of vertices and
edges, and these edges are used to connect the vertices. The vertices are used to
store the data elements, while the edges represent the relationship between the
vertices. A graph is used in various real-world problems like telephone networks,
circuit networks, social networks like LinkedIn, Facebook. In the case of facebook, a
single user can be considered as a node, and the connection of a user with others is
known as edges.

Linear Data structure Non-Linear Data structure

Basic In this structure, the In this structure, the


elements are arranged elements are arranged
sequentially or linearly and hierarchically or non-
attached to one another. linear manner.

Types Arrays, linked list, stack, Trees and graphs are the
queue are the types of a types of a non-linear data
linear data structure. structure.

implementation Due to the linear Due to the non-linear


organization, they are easy organization, they are
to implement. difficult to implement.

Traversal As linear data structure is a The data items in a non-


single level, so it requires a linear data structure
single run to traverse each cannot be accessed in a
data item. single run. It requires
multiple runs to be
traversed.

Arrangement Each data item is attached Each item is attached to


to the previous and next many other items.
items.

Levels This data structure does In this, the data elements


not contain any hierarchy, are arranged in multiple
and all the data elements levels.
are organized in a single
level.

Memory utilization In this, the memory In this, memory is utilized


utilization is not efficient. in a very efficient manner.

Time complexity The time complexity of The time complexity of


linear data structure non-linear data structure
increases with the increase often remains same with
in the input size. the increase in the input
size.

Applications Linear data structures are Non-linear data structures


mainly used for developing are used in image
the software. processing and Artificial
Intelligence.
 

Difference between Linear and Non-linear Data Structures:


Stack Data Structure
Stack is a linear data structure which follows a particular order in which the operations are
performed. The order may be LIFO(Last In First Out)

A stack is a useful data structure in programming. It is just like a pile of plates kept on top of

each other.

Stack representation
similar to a pile of plate

A real-world stack allows operations at one end only. For example, we can place or
remove a card or plate from the top of the stack only. At any given time, we can only
access the top element of a stack.
This feature makes it LIFO data structure. LIFO stands for Last-in-first-out. Here,
the element which is placed (inserted or added) last, is accessed first. In stack
terminology, insertion operation is called PUSH operation and removal operation is
called POP operation.
Stack Representation
The following diagram depicts a stack and its operations −

A stack can be implemented by means of Array, Structure, Pointer, and Linked List.
Stack can either be a fixed size one or it may have a sense of dynamic resizing.
Here, we are going to implement stack using arrays, which makes it a fixed size
stack implementation.

Basic Operations
Stack operations may involve initializing the stack, using it and then de-initializing it.
Apart from these basic stuffs, a stack is used for the following two primary
operations −
 push() − Pushing (storing) an element on the stack.
 pop() − Removing (accessing) an element from the stack.
When data is PUSHed onto stack.
To use a stack efficiently, we need to check the status of stack as well. For the
same purpose, the following functionality is added to stacks −
 peek() − get the top data element of the stack, without removing it.
 isFull() − check if stack is full.
 isEmpty() − check if stack is empty.
At all times, we maintain a pointer to the last PUSHed data on the stack. As this
pointer always represents the top of the stack, hence named top. The top pointer
provides top value of the stack without actually removing it.
Working of Stack Data Structure
The operations work as follows:

1. A pointer called  TOP  is used to keep track of the top element in the stack.
2. When initializing the stack, we set its value to -1 so that we can check if the stack
is empty by comparing  TOP == -1 .

3. On pushing an element, we increase the value of  TOP  and place the new element in
the position pointed to by  TOP .
4. On popping an element, we return the element pointed to by  TOP  and reduce its
value.
5. Before pushing, we check if the stack is already full

6. Before popping, we check if the stack is already empty

Applications of Stack Data Structure


Although stack is a simple data structure to implement, it is very powerful.
The most common uses of a stack are:

 To reverse a word - Put all the letters in a stack and pop them out.
Because of the LIFO order of stack, you will get the letters in reverse
order.
 In browsers - The back button in a browser saves all the URLs you
have visited previously in a stack. Each time you visit a new page, it
is added on top of the stack. When you press the back button, the
current URL is removed from the stack, and the previous URL is
accessed.

Queue
A queue is a useful data structure in programming. It is similar to the ticket
queue outside a cinema hall, where the first person entering the queue is the
first person who gets the ticket.

Queue follows the First In First Out (FIFO) rule - the item that goes in first is the
item that comes out first.

FIFO Representation of Queue

In the above image, since 1 was kept in the queue before 2, it is the first to be
removed from the queue as well. It follows the FIFO rule.
In programming terms, putting items in the queue is called enqueue, and
removing items from the queue is called dequeue.

Basic Operations of Queue

A queue is an object (an abstract data structure - ADT) that allows the

following operations:

 Enqueue: Add an element to the end of the queue


 Dequeue: Remove an element from the front of the queue
 IsEmpty: Check if the queue is empty
 IsFull: Check if the queue is full

 Peek: Get the value of the front of the queue without removing it

Working of Queue
Queue operations work as follows:

 two pointers  FRONT  and  REAR


 FRONT  track the first element of the queue

 REAR  track the last element of the queue

 initially, set value of  FRONT  and  REAR  to -1


Enqueue Operation
 check if the queue is full

 for the first element, set the value of  FRONT  to 0
 increase the  REAR  index by 1
 add the new element in the position pointed to by  REAR
Dequeue Operation
 check if the queue is empty

 return the value pointed by  FRONT


 increase the  FRONT  index by 1
 for the last element, reset the values of  FRONT  and  REAR  to -1
Enqueue and Dequeue Operations

Limitations of Queue
As you can see in the image below, after a bit of enqueuing and dequeuing, the
size of the queue has been reduced.

Limitation of a queue

And we can only add indexes 0 and 1 only when the queue is reset (when all the
elements have been dequeued).

After  REAR  reaches the last index, if we can store extra elements in the empty
spaces (0 and 1), we can make use of the empty spaces. This is implemented by
a modified queue called the circular queue.

There are four different types of queues:

 Simple Queue

 Circular Queue

 Priority Queue

 Double Ended Queue


Simple Queue
In a simple queue, insertion takes place at the rear and removal occurs at the
front. It strictly follows the FIFO (First in First out) rule.

Simple Queue Representation

Circular Queue
In a circular queue, the last element points to the first element making a circular
link.

Fig: Circular Queue Representation

The main advantage of a circular queue over a simple queue is better memory
utilization. If the last position is full and the first position is empty, we can insert
an element in the first position. This action is not possible in a simple queue.

Circular queue avoids the wastage of space in a regular queue implementation


using arrays.
Fig: Limitation of the regular Queue

As you can see in the above image, after a bit of enqueuing and dequeuing, the
size of the queue has been reduced.

The indexes 0 and 1 can only be used after the queue is reset when all the
elements have been dequeued.

Priority Queue
A priority queue is a special type of queue in which each element is associated
with a priority and is served according to its priority. If elements with the same
priority occur, they are served according to their order in the queue.

Generally, the value of the element itself is considered for assigning the priority.

For example, The element with the highest value is considered as the highest
priority element. However, in other cases, we can assume the element with the
lowest value as the highest priority element. In other cases, we can set priorities
according to our needs.
Removing Highest Priority Element

Difference between Priority Queue and Normal Queue


In a queue, the first-in-first-out rule is implemented whereas, in a priority
queue, the values are removed on the basis of priority. The element with the
highest priority is removed first.
Implementation of Priority Queue
Priority queue can be implemented using an array, a linked list, a heap data
structure, or a binary search tree. Among these data structures, heap data
structure provides an efficient implementation of priority queues.

Deque (Double Ended Queue)


In a double ended queue, insertion and removal of elements can be performed
from either from the front or rear. Thus, it does not follow the FIFO (First In First
Out) rule.

Deque Representation

Types of Deque
 Input Restricted Deque
In this deque, input is restricted at a single end but allows deletion at both the
ends.
 Output Restricted Deque
In this deque, output is restricted at a single end but allows insertion at both the
ends.
Linked list Data Structure
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:

In simple words, a linked list consists of nodes where each node contains a data
field and a reference(link) to the next node in the list.

A linked list data structure includes a series of connected nodes. Here, each
node store the data and the address of the next node. For example,

Fig: Linked list Data Structure

You have to start somewhere, so we give the address of the first node a special
name called  HEAD .
Also, the last node in the linked list can be identified because its next portion
points to  NULL .
You might have played the game Treasure Hunt, where each clue includes the
information about the next clue. That is how the linked list operates.
Representation of Linked List

Now see how each node of the linked list is represented. Each node consists:

 A data item

 An address of another node

In just a few steps, we have created a simple linked list with three nodes.

Linked list Representation

The power of a linked list comes from the ability to break the chain and rejoin it.
E.g. if you wanted to put an element 4 between 1 and 2, the steps would be:

 Create a new struct node and allocate memory to it.

 Add its data value as 4

 Point its next pointer to the struct node containing 2 as the data value

 Change the next pointer of "1" to the node we just created.

Doing something similar in an array would have required shifting the positions
of all the subsequent elements.
Types of Linked List
There are three common types of Linked List.

1. Singly Linked List


2. Doubly Linked List
3. Circular Linked List

Singly Linked List


It is the most common. Each node has data and a pointer to the next node.

Singly linked list

Doubly Linked List


We add a pointer to the previous node in a doubly-linked list. Thus, we can go in
either direction: forward or backward.

Doubly linked list

Circular Linked List


A circular linked list is a variation of a linked list in which the last element is
linked to the first element. This forms a circular loop.

Cir
cular linked list
A circular linked list can be either singly linked or doubly linked.

 for singly linked list, next pointer of last item points to the first item

 In the doubly linked list,  prev  pointer of the first item points to the last item as
well.

Linked List Representation


Linked list can be visualized as a chain of nodes, where every node points to the
next node.

As per the above illustration, following are the important points to be considered.
 Linked List contains a link element called first.
 Each link carries a data field(s) and a link field called next.
 Each link is linked with its next link using its next link.
 Last link carries a link as null to mark the end of the list.

Types of Linked List


Following are the various types of linked list.
 Simple Linked List − Item navigation is forward only.
 Doubly Linked List − Items can be navigated forward and backward.
 Circular Linked List − Last item contains link of the first element as next and
the first element has a link to the last element as previous.

Basic Operations
Following are the basic operations supported by a list.
 Insertion − Adds an element at the beginning of the list.
 Deletion − Deletes an element at the beginning of the list.
 Display − Displays the complete list.
 Search − Searches an element using the given key.
 Delete − Deletes an element using the given key.

Insertion Operation
Adding a new node in linked list is a more than one step activity. We shall learn this
with diagrams here. First, create a node using the same structure and find the
location where it has to be inserted.

Imagine that we are inserting a node B (NewNode), between A (LeftNode)


and C (RightNode). Then point B.next to C −
NewNode.next −> RightNode;
It should look like this −

Now, the next node at the left should point to the new node.
LeftNode.next −> NewNode;

This will put the new node in the middle of the two. The new list should look like this

Similar steps should be taken if the node is being inserted at the beginning of the
list. While inserting it at the end, the second last node of the list should point to the
new node and the new node will point to NULL.

Deletion Operation
Deletion is also a more than one step process. We shall learn with pictorial
representation. First, locate the target node to be removed, by using searching
algorithms.

The left (previous) node of the target node now should point to the next node of the
target node −
LeftNode.next −> TargetNode.next;

This will remove the link that was pointing to the target node. Now, using the
following code, we will remove what the target node is pointing at.
TargetNode.next −> NULL;
We need to use the deleted node. We can keep that in memory otherwise we can
simply deallocate memory and wipe off the target node completely.

Reverse Operation
This operation is a thorough one. We need to make the last node to be pointed by
the head node and reverse the whole linked list.

First, we traverse to the end of the list. It should be pointing to NULL. Now, we shall
make it point to its previous node −

We have to make sure that the last node is not the last node. So we'll have some
temp node, which looks like the head node pointing to the last node. Now, we shall
make all left side nodes point to their previous nodes one by one.

Except the node (first node) pointed by the head node, all nodes should point to
their predecessor, making them their new successor. The first node will point to
NULL.
We'll make the head node point to the new first node by using the temp node.

Hashing
Hashing is a technique of mapping a large set of arbitrary data to tabular
indexes using a hash function. It is a method for representing dictionaries for
large datasets.

Why Hashing is Needed?


After storing a large amount of data, we need to perform various operations on
these data.
Lookups are inevitable for the datasets. Linear search and binary
search perform lookups/search with time complexity of  O(n)  and  O(log
n)  respectively. As the size of the dataset increases, these complexities also

become significantly high which is not acceptable.


We need a technique that does not depend on the size of data. Hashing allows
lookups to occur in constant time i.e.  O(1) .
Hash Function
A hash function is used for mapping each element of a dataset to indexes in the
table.

Hash Table
The Hash table data structure stores elements in key-value pairs where

 Key- unique integer that is used for indexing the values


 Value - data that are associated with keys.

Key and Value in Hash table

Hashing (Hash Function)


In a hash table, a new index is processed using the keys. And, the element
corresponding to that key is stored in the index. This process is called hashing.
Let  k  be a key and  h(x)  be a hash function.
Here,  h(k)  will give us a new index to store the element linked with  k .
Hash table Representation

Hash Collision
When the hash function generates the same index for multiple keys, there will
be a conflict (what value to be stored in that index). This is called a hash
collision.
We can resolve the hash collision using one of the following techniques.

 Collision resolution by chaining

 Open Addressing: Linear/Quadratic Probing and Double Hashing

Algorithm Classes:

Class Description
Divides the problem into sub-parts and
Divide and Conquer
solves each one separately
Divides the problem into sub-parts,
Dynamic Programming remembers the results of the sub-parts
and applies it to similar ones
Involves taking the easiest step while
Greedy Algorithms solving a problem without worrying about
the complexity of the future steps

You might also like