Introduction To DSA
Introduction To DSA
AND ALGORITHM
Abrahem P. Anqui
Subject Details
■ Course Description
– An overview of data structure concepts, arrays, stack, queues, trees, and graphs.
Discussion of various implementations of these data objects, programming styles, and run-
time representations. The course also examines algorithms for sorting, searching, and
some graph algorithms. Algorithm analysis and efficient code design is discussed.
■ Learning Outcome
– Explain and utilize linked lists, stacks, queues, and trees.
– Incorporate algorithmic design know-how and data structures to create reliable and
structured programs.
– Describe the design and performance of various searching and sorting algorithms.
– Use advanced object-oriented concepts such as abstract base classes, friend classes, and
operator overloading in the implementation of data structures.
Introduction to Data Structures and
Algorithm
What Are Data Structures and Algorithms
Good For?
■ A data structure is an arrangement of data in a computer’s
memory (or sometimes on a disk). Data structures include arrays,
linked lists, stacks, binary trees, and hash tables, among others.
■ Algorithms manipulate the data in these structures in various
ways, such as searching for a particular data item and sorting the
data.
Overview of Data Structure
■ Data Structure is a systematic way to organize data in order to use it
efficiently. The following terms are the foundation terms of a data structure.
– Interface − Each data structure has an interface. The interface
represents the set of operations that a data structure supports. An
interface only provides the list of supported operations, the type of
parameters they can accept, and the return type of these operations.
– Implementation − Implementation provides the internal representation of
a data structure. The implementation also provides the definition of the
algorithms used in the operations of the data structure.
Characteristics of a Data Structure
■ Algorithms tell the programmers how to code the program. Alternatively, the algorithm can be written
as −
■ There are multiple ways to solve a problem using a computer program. For
instance, there are several ways to sort items in an array. You can use
merge sort, bubble sort, insertion sort, etc. All these algorithms have their own
pros and cons. An algorithm can be thought of as a procedure or formula to
solve a particular problem. The question is, which algorithm to use to solve a
specific problem when there exist multiple solutions to the problem?
■ For instance, if there is a linear relationship between the input and the step taken
by the algorithm to complete its execution, the Big-O notation used will be O(n).
Similarly, the Big-O notation for quadratic functions is O(n^2)
The following are some of the most common
Big-O functions:
To get an idea of how Big-O notation in is
calculated, let's take a look at some
examples of constant, linear, and quadratic
complexity.
Constant Complexity (O(C))
def constant_algo(items):
■ The complexity of an algorithm is said to be
constant if the steps required to complete result = items[0] * items[0]
the execution of an algorithm remain print()
constant, irrespective of the number of
inputs. The constant complexity is denoted
by O(c) where c can be any constant constant_algo([4, 5, 6, 8])
number.
■ Let's write a simple algorithm in Python that In the above script, irrespective of the input size, or the
finds the square of the first item in the list number of items in the input list items, the algorithm
and then prints it on the screen. performs only 2 steps: Finding the square of the first
element and printing the result on the screen. Hence,
the complexity remains constant.
Constant Complexity (O(C))
If you draw a line plot with the varying size of the items input on the x-axis and the number of steps on the y-
axis, you will get a straight line. To visualize this, execute the following script:
y = [2, 2, 2, 2, 2, 2]
plt.plot(x, y, 'b')
plt.xlabel('Inputs')
plt.ylabel('Steps')
plt.title('Constant Complexity')
plt.show()
Linear Complexity (O(n))
■ The complexity of an algorithm is said to be def linear_algo(items):
linear if the steps required to complete the for item in items:
execution of an algorithm increase or
decrease linearly with the number of inputs. print(item)
Linear complexity is denoted by O(n).
■ In this example, let's write a simple program linear_algo([4, 5, 6, 8])
that displays all items in the list to the
console: The complexity of the linear_algo function is linear in the
above example since the number of iterations of the
for-loop will be equal to the size of the input items array.
For instance, if there are 4 items in the items list, the for-
loop will be executed 4 times, and so on.
Linear Complexity (O(n))
■ The plot for linear complexity with inputs on x-axis and # of steps on the x-axis is as follows:
plt.plot(x, y, 'b')
plt.xlabel('Inputs')
plt.ylabel('Steps')
plt.title('Linear Complexity')
plt.show()
Another point to note here is that in case of a huge number of inputs the constants become insignificant. For instance,
take a look at the following script:
We can further verify and visualize this by plotting the inputs on x-
def linear_algo(items): axis and the number of steps on y-axis as shown below:
for item in items:
print(item) import matplotlib.pyplot as plt
import numpy as np
for item in items:
print(item) x = [2, 4, 6, 8, 10, 12]
plt.plot(x, y, 'b')
In the script above, there are two for- plt.xlabel('Inputs')
loops that iterate over the input items list. plt.ylabel('Steps')
Therefore the complexity of the algorithm plt.title('Linear Complexity')
becomes O(2n), however in case of
infinite items in the input list, the twice of
infinity is still equal to infinity, therefore
we can ignore the constant 2 (since it is
ultimately insignificant) and the
complexity of the algorithm remains
O(n).
Quadratic Complexity (O(n^2))
def quadratic_algo(items):
■ The complexity of an algorithm is said to be
quadratic when the steps required to execute an for item in items:
algorithm are a quadratic function of the number for item2 in items:
of items in the input. Quadratic complexity is print(item, ' ' ,item)
denoted as O(n^2). Take a look at the following
example to see a function with quadratic
complexity:
quadratic_algo([4, 5, 6, 8])
In the script above, you can see that we have an outer loop that iterates through all
the items in the input list and then a nested inner loop, which again iterates through
all the items in the input list. The total number of steps performed is n * n, where n is
the number of items in the input array.
Quadratic Complexity (O(n^2))
■ The following graph plots the number of inputs vs the steps for an algorithm with quadratic complexity.
■ In the previous examples, we saw that only one function was being performed on the input. What if
multiple functions are being performed on the input? Take a look at the following example.
def complex_algo(items):
In the script above several tasks are being performed, first, a string is
printed 5 times on the console using the print statement. Next, we print the
for i in range(5): O(5)
input list twice on the screen and finally, another string is being printed
print("Python is awesome")
three times on the console. To find the complexity of such an algorithm,
we need to break down the algorithm code into parts and try to find the
for item in items:
complexity of the individual pieces.
print(item) O(n)
for item in items: Let's break our script down into individual parts. In the first part
print(item) O(n) we have:
complex_algo([4, 5, 6, 8]) The complexity of this part is O(5). Since five constant steps are
being performed in this piece of code irrespective of the input.
Next, we have: To find the overall complexity, we simply have to add these
for item in items: individual complexities. Let's do so:
print(item)
O(5) + O(n) + O(n) + O(3)
We know the complexity of above piece of code is
O(n).
Simplifying above we get:
Similarly, the complexity of the following piece of
code is also O(n)
O(8) + O(2n)
for item in items:
print(item)
We said earlier that when the input (which has length n in
this case) becomes extremely large, the constants become
Finally, in the following piece of code, a string is being
insignificant i.e. twice or half of the infinity still remains
printed three times, hence the complexity is O(3)
infinity. Therefore, we can ignore the constants. The final
complexity of the algorithm will be O(n).
print("Big O")
print("Big O")
print("Big O")
Worst vs Best Case Complexity
■ Usually, when someone asks you about the complexity of the algorithm he is asking you
about the worst case complexity. To understand the best case and worse case
complexity, look at the following script:
In the script above, we have a function that takes a number and a list
def search_algo(num, items):
of numbers as input. It returns true if the passed number is found in
for item in items:
the list of numbers, otherwise it returns None. If you search 2 in the
if item == num:
list, it will be found in the first comparison. This is the best case
return True
complexity of the algorithm that the searched item is found in the
else:
first searched index. The best case complexity, in this case, is O(1).
pass
On the other hand, if you search 10, it will be found at the last
nums = [2, 4, 6, 8, 10]
searched index. The algorithm will have to search through all the
items in the list, hence the worst case complexity becomes O(n).
print(search_algo(2, nums))
Space Complexity
■ In addition to the time complexity, where you count the number of steps required to complete
the execution of an algorithm, you can also find space complexity which refers to the number of
spaces you need to allocate in the memory space during the execution of a program.
Problem Separate Odd and Even Number based on user’s input then add all even and all
odd.
Answer
■ Algo with Complexity ■ Code (Java)
Declare variables value, sumE, sumO Import java.util.Scanner;
Get value from user
For i in value:
if i modulus 2 = 0
print i
sumE = sumE + i
Print sumE
For in value:
if i modulus 2 not equal to 0
print i
sumO = sumO + i
Print sumO
O(n)