You are on page 1of 51

COM 124

Data Structures And Algorithms


by:

Ahmad Maccido
BSc, MSc, PhD(in view)

Department of Computer Engineering


Waziri Umaru Federal Polytechnic
Birnin Kebbi, Kebbi State
Course objectives
• Learn basic data structures and algorithms
• data structures – how data is organized
• algorithms – unambiguous sequence of steps to compute
something
• algorithm analysis – determining how long an algorithm will
take to solve a problem

• Become a better software developer


• "Data Structures + Algorithms = Programs“

2
What is data structure?
• A particular way of storing and organizing data in a
computer so that it can be used efficiently and effectively.
• Data structure is the logical or mathematical model of a
particular organization of data.
• A group of data elements grouped together under one
name.
• For example, an array of integers
Data Types & Data Structures
• Applications/programs read data, store data temporarily,
process it and finally output results.
• What is data? Numbers, Characters, etc.

Data Application/ Data


Program

4
Data Types & Data Structures
• Data is classified into data types. e.g. char, float, int, etc.
• A data type is (i) a domain of allowed values and (ii) a set of operations
on these values.
• Compiler signals an error if wrong operation is performed on data of a
certain type. For example, char x,y,z; z = x*y is not allowed.

5
Data Types & Data Structures
• Examples

Data Type Domain Operations


boolean 0,1 and, or, =, etc.
char ASCII =, <>, <, etc.
integer -maxint to +, _, =, ==, <>, <,
+maxint etc.

6
Types of Data Structures

7
Types of Data Structures
Arra
y

Linked List

Queue Stac
Tree
k
There are many, but we named a few. We’ll learn these
data structures in great detail!
Non-Primitive Data Structure

9
Static linear Data Structure
Static data structure: Static data structure has a fixed
memory size. It is easier to access the elements in a
static data structure.
An example of this data structure is an array.

10
Basic Terms of An Array Data Structure
In arrays, an element refers to a particular item that is stored.
Each element carries an index - a location with respect to a
base value.
The base value is the memory location of the first element of
the array.
We simply add offsets to this value which makes it easier for
us to use the reference and identify items.

Array length – the number of elements an array can store is


defined as the length of the array. It is the total space
allocated in memory while declaring an array.

11
Here are a few important properties of an array:

•Each entry in an array has the same data type and size,
which is 4 bytes.

•The array's elements are stored in contiguous memory


regions, with the first element placed in the smallest memory
address.

•Elements of the array can be accessed at random because


we can define the address of each element using the specified
base address and data element size.

•Arrays make good use of computer addressing logic because


the memory in most modern computers and external storage
devices is a one-dimensional array of words.

12
Why do we need arrays?
• It is simpler to sort and search for a value in an array
• Arrays are ideal for processing many values with ease
• Arrays are useful for storing a variety of values in a single variable. Most
applications in computer programming necessitate keeping a significant
amount of data of a similar type.
• To hold this much data, we must define a large number of variables. While
writing the programs, it would be quite tough to remember the names of all
the variables. Instead of naming each variable a different name, it’s simpler
to build an array and store all of the elements within it.
• Applications of Array
• We’ve already discussed everything about arrays in our previous article.
Here we’ll try to understand the applications of arrays in the programming
world using proper examples and images. Let's get started:

13
Pointers
• A pointer is a variable which stores the address of another variable.
• There are two main operations when working with pointers in C++:
1. The Address Operator => &
2. The Value Operator => *

14
LINKED LISTS
• Linked list is one of the fundamental data structures
• It can be used to implement other data structures.
• It consists of a sequence of nodes, each containing arbitrary
data fields and one or two links pointing to the next and/or
previous nodes.
• The principal benefit of a linked list over a conventional array
• It allows items to be traversed in a different order.
• Single node of the linked list can have data of multiple data
types,

15
NODE INSERTION:

16
NODE INSERTION:

17
NODE INSERTION:
• Consider a linked list made up of several nodes. If it is required
to insert a new node after a specific node in the linked list, that
specific node should be first searched in the linked list.
Following is a method to add a new node after a specific node
in the linked list:
• Initialize a variable which stores the data of the node to be
searched.
• Traverse the linked list (p = p->next inside a loop) from start to
NULL and compare data of every node with the data to be
searched (using an if condition).
• When that specific node is found, use references (pointers) to
help insert the new node
• Initialize data to variables of the new node.
• Check if the link is connected to all the nodes (including the
new node)

18
Stack ADT
• stack: a list with the restriction that insertions/deletions can
only be performed at the top/end of the list
• Last-In, First-Out ("LIFO")
• The elements are stored in order of insertion,
but we do not think of them as having indexes.
• The client can only add/remove/examine
the last element added (the "top").

• basic stack operations:


• push: Add an element to the top.
• pop: Remove the top element.
• peek: Examine the top element.

19
Applications of Stacks
• Programming languages:
• method calls are placed onto a stack (call=push, return=pop)
return var
method3 local vars
parameters
return var
method2 local vars
parameters
• Matching up related pairs of things: return var
method1 local vars
• find out whether a string is a palindrome parameters

• examine a file to see if its braces { } and other operators match

• Sophisticated algorithms:
• searching through a maze with "backtracking"
• many programs use an "undo stack" of previous operations

20
Class Stack
Stack<E>() constructs a new stack with elements of type E
push(value places given value on top of stack
)
pop() removes top value from stack and returns it;
throws EmptyStackException if stack is empty
peek() returns top value from stack without removing it;
throws EmptyStackException if stack is empty
size() returns number of elements in stack
isEmpty() returns
Stack<Integer> s = newif Stack<Integer>();
true stack has no elements
s.push(42);
s.push(-3);
s.push(17); // bottom [42, -3, 17] top

System.out.println(s.pop()); // 17

21
Labs: Primitive data type
• #include <iostream>
• #include <cstdio>
• #include <string>
• using namespace std;
• int main()
• {
• float a=34.9;
• string b="HELLO";
• float c=35.9;
• double d =12323.34;
• string msg ="HELLO ALL" ;
• cout << msg << endl;
• cout << b << endl ;
• cout<< c << endl;
• cout << a << endl;
• cout << d << endl;
• }
What is Pseudo-code?

• Pseudo-code is a short hand way of describing a


computer program
• Rather than using the specific syntax of a computer
language, more general wording is used
• It is a mixture of NL and PL expressions, in a
systematic way
• Using pseudo-code, it is easier for a non-
programmer to understand the general workings of
the program
Pseudo-code: General Guidelines
• Use PLs construct that are consistent with
modern high level languages, e.g. C++, Java,
...
• Use appropriate comments for clarity
• Be simple and precise
Components of Pseudo-code
• Expressions
● Standard mathematical symbols are used
o Left arrow sign (←) as the assignment operator in assignment statements
(equivalent to the = operator in Java)
o Equal sign (=) as the equality relation in Boolean expressions (equivalent to the "=
=" relation in Java)
o For example
Sum ← 0
Sum ← Sum + 5

What is the final value of sum?


Components of Pseudo-code (cont.)
• Decision structures (if-then-else logic)

● if condition then
true-actions
[else

false-actions]
● We use indentation to indicate what actions should be included in the true-
actions and false-actions
● For example

if marks > 50 then


print “Congratulation, you are passed!”
else
print “Sorry, you are failed!”
end if

What will be the output if marks are equal to 75?


Components of Pseudo-code (cont.)
• Loops (Repetition)
• Pre-condition loops
o While loops
• while condition do actions
• We use indentation to indicate what actions should be included in
the loop actions
• For example
while counter < 5 do
print “Welcome to CS204!”
counter ← counter + 1
end while

What will be the output if counter is initialised to 0, 7?


Components of Pseudo-code (cont.)
• Loops (Repetition)
• Pre-condition loops
o For loops
• for variable-increment-definition do actions
• For example
for counter ← 0; counter < 5; counter ← counter + 2 do
print “Welcome to CS204!”
end for

What will be the output?


Components of Pseudo-code (cont.)
• Loops (Repetition)
● Post-condition loops
o Do loops
• do actions while condition
• For example
do
print “Welcome to CS204!”
counter ← counter + 1
while counter < 5

What will be the output, if counter was initialised to 10?

The body of a post-condition loop must execute at least once


Components of Pseudo-code (cont.)
• Method declarations
• Return_type method_name (parameter_list)
method_body
• For example
• integer sum ( integer num1, integer num2)
• start
• result ← num1 + num2
• end
• Method calls
● object.method (args)
● For example
mycalculator.sum(num1, num2)
Components of Pseudo-code (cont.)
• Method returns
● return value
● For example
integer sum ( integer num1, integer num2)
start
result ← num1 + num2
return result
end
Components of Pseudo-code (cont.)
• Comments
• /* Multiple line comments go here. */
• // Single line comments go here
• Some people prefer braces {}, for comments
• Arrays
● A[i] represents the ith cell in the array A.
● The cells of an n-celled array A are indexed from A[0] to A[n −
1] (consistent with Java).
Algorithm Design: Practice
● Example 1: Determining even/odd number
● A number divisible by 2 is considered an even number, while a
number which is not divisible by 2 is considered an odd number.
Write pseudo-code to display first N odd/even numbers.

● Example 2: Computing Weekly Wages


● Gross pay depends on the pay rate and the number of hours
worked per week. However, if you work more than 40 hours, you
get paid time-and-a-half for all hours worked over 40. Write the
pseudo-code to compute gross pay given pay rate and hours
worked
Even/ Odd Numbers

Input range
for num←0; num<=range; num←num+1 do
if num % 2 = 0 then
print num is even
else
print num is odd
endif
endfor
Algorithm Design: Practice
• Example 1: Determining even/odd number
• A number divisible by 2 is considered an even number, while
a number which is not divisible by 2 is considered an odd
number. Write pseudo-code to display first N odd/even
numbers.

• Example 2: Computing Weekly Wages


● Gross pay depends on the pay rate and the number of hours
worked per week. However, if you work more than 40 hours,
you get paid time-and-a-half for all hours worked over 40.
Write the pseudo-code to compute gross pay given pay rate and
hours worked
Even/ Odd Numbers
Input range
for num←0; num<=range; num←num+1 do
if num % 2 = 0 then
print num is even
else
print num is odd
endif
endfor
Computing weekly wages

Input hours_worked, pay_rate


if hours_worked <= 40 then
gross_pay ← pay_rate x hours_worked
else
basic_pay ← pay_rate x 40
over_time ← hours_worked – 40
over_time_pay ← 1.5 x pay_rate x over_time
gross_pay ← basic_pay + over_time_pay
endfor
print gross_pay
Algorithm
and
Algorithm Analysis
Algorithm
An Algorithm is a sequence of steps that describe how a
problem can be solved.
Every computer program that ends with a result is
basically based on an Algorithm.
• An algorithm is a procedure used for solving a problem or
performing a computation.
• Algorithms act as an exact list of instructions that conduct
specified actions step by step in either hardware- or software-
based routines.
Factor to Classify Algorithm
An Algorithm is a procedure to solve a particular problem in a
finite number of steps for a finite-sized input.
The algorithms can be classified in various ways.
They are:

1. Implementation Method
2. Design Method
3. Design Approaches
4. Other aspect
Why Algorithm Classification?

• The classification of algorithms is important for several


reasons:
• Organization: Algorithms can be very complex and by
classifying them, it becomes easier to organize, understand, and
compare different algorithms.
• Problem Solving: Different problems require different
algorithms, and by having a classification, it can help identify
the best algorithm for a particular problem.
• Performance Comparison: By classifying algorithms, it is
possible to compare their performance in terms of time and
space complexity, making it easier to choose the best algorithm
for a particular use case.
• Reusability: By classifying algorithms, it becomes easier to re-
Classification by Implementation Method:
There are primarily three main categories into which an
algorithm can be named in this type of classification.
They are:
• Recursion or Iteration: A recursive algorithm is an algorithm
which calls itself again and again until a base condition is
achieved whereas iterative algorithms use loops and/or data
structures like stacks, queues to solve any problem.
• Exact or Approximate: Algorithms that are capable of finding
an optimal solution for any problem are known as the exact
algorithm. For all those problems, where it is not possible to
find the most optimized solution, an approximation algorithm
is used. Approximate algorithms are the type of algorithms that
find the result as an average outcome of sub outcomes to a
problem.
• Serial or Parallel or Distributed Algorithms: In serial
Classification by Design Method
Greedy Algorithms: In the greedy method, at each step, a decision is made to choose the local optimum, without thinking about the future consequences.

Divide and Conquer: This involves dividing the problem into sub-problem, recursively solving them, and then recombining them for the final answer.

Dynamic Programming: The approach of Dynamic programming is similar to divide and conquer. The difference is that whenever we have recursive
function calls with the same result, instead of calling them again we try to store the result in a data structure in the form of a table and retrieve the results
from the table. Thus, the overall time complexity is reduced. “Dynamic” means we dynamically decide, whether to call a function or retrieve values
from the table.

Linear Programming: In Linear Programming, there are inequalities in terms of inputs and maximizing or minimizing some linear functions of inputs.

Reduction(Transform and Conquer): This solve a difficult problem by transforming it into a known problem for which we have an optimal solution.
Basically, the goal is to find a reducing algorithm whose complexity is not dominated by the resulting reduced algorithms.

Backtracking: This technique is very useful in solving combinatorial problems that have a single unique solution. Where we have to find the correct
combination of steps that lead to fulfillment of the task. Such problems have multiple stages and there are multiple options at each stage. This approach
is based on exploring each available option at every stage one-by-one. While exploring an option if a point is reached that doesn’t seem to lead to the
solution, the program control backtracks one step, and starts exploring the next option. In this way, the program explores all possible course of actions
and finds the route that leads to the solution.

Branch and Bound: This technique is very useful in solving combinatorial optimization problem that have multiple solutions and we are interested in find
the most optimum solution. In this approach, the entire solution space is represented in the form of a state space tree. As the program progresses each
state combination is explored, and the previous solution is replaced by new one if it is not the optimal than the current solution.
Classification by Design Approaches
• Top-Down Approach: In the top-down approach, a large problem is divided into small sub-
problem. and keep repeating the process of decomposing problems until the complex problem
is solved.
• Bottom-up approach: The bottom-up approach is also known as the reverse of top-down
approaches.
In approach different, part of a complex program is solved using a programming language and
then this is combined into a complete program.
Classification by other aspect
Apart from classifying the algorithms into the above broad categories, the algorithm can be
classified into other broad categories like:

• Randomized Algorithms: Algorithms that make random choices for faster solutions are
known as randomized algorithms.
Example: Randomized Quicksort Algorithm.
• Classification by complexity: Algorithms that are classified on the basis of time taken to get a
solution to any problem for input size. This analysis is known as time complexity analysis.
Example: Some algorithms take O(n), while some take exponential time.
• Classification by Research Area: In CS each field has its own problems and needs efficient
algorithms.
Example: Sorting Algorithm, Searching Algorithm, Machine Learning etc.
• Branch and Bound Enumeration and Backtracking: These are mostly used in Artificial
Intelligence.
Analysis of Algorithms
Algorithm analysis provides theoretical estimation for the required
resources of an algorithm to solve a specific computational problem.
It is the determination of the amount of time and space resources required
to execute it.
Efficiency or running time of an algorithm is related to input length,
number of steps, these known as time complexity, and a volume of
memory known as space complexity.
In a not shell, analysis of algorithm can be of these forms:
1. Algorithms and Complexities
2. Asymptotic analysis
3. Asymptotic notations
4. Amortized analysis
5. Space Complexity
6. Pseudo Polynomial Type
Algorithms and Complexities
The complexity of an algorithm computes the amount of time and
spaces required by an algorithm for an input of size (n).
The complexity of an algorithm can be divided into two types. The time
complexity and the space complexity.
1. Time Complexity of an Algorithm: This is defined as the process
of determining a formula for total time required towards the execution
of that algorithm.
This calculation is totally independent of implementation and
programming language.
2. Space Complexity of an Algorithm: Space complexity is defining
as the process of defining a formula for prediction of how much
memory space is required for the successful execution of the
algorithm.
The memory space is generally considered as the primary memory.
Asymptotic Analysis
Asymptotic analysis, determine the performance of the algorithm based on the input size. it usually find the relation between the running time and
the input size.
For the space complexity, the goal is to get how much space in the main memory is occupied to complete the algorithm.
Asymptotic Behavior
For a function f(n) the asymptotic behavior is the growth of f(n) as n gets large.
Our task is to find how much time it will take for a large value of the input.
For example,
f(n) = c * n + k as linear time complexity.
f(n) = c *(n*n) + k is quadratic time complexity.
Ideally, the analysis of algorithms can be divided into three different cases. Viz:
Best Case − Here the lower bound of the running time is calculated. It describes the behavior of an algorithm under optimal conditions.
Average Case − In this case, we calculate the region between the upper and lower bound of the running time of algorithms.
In this case, the number of executed operations are not minimum and not maximum.
Worst Case − In this case we calculate the upper bound of the running time of algorithms. In this case, a maximum number of operations are
executed.
Asymptotic Notations
Asymptotic notations are used to represent the complexities of algorithms for asymptotic analysis.
These notations are mathematical tools to represent the complexities.
There are three notations that are commonly used.
Big Oh Notation
• Big-Oh (O) notation g

We write f(n) = O(g(n)), If there are positive constantsn0 and c such that, to the right of n0 the f(n)
always lies on or below c*g(n).
• O(g(n)) = { f(n) : There exist positive constant c and n0 such that 0 ≤ f(n) ≤ c g(n), for all n ≥
n0}
Asymptotic Notations
Big Omega Notation
Big-Omega (Ω) notation gives a lower bound for a function f(n) to within a constant factor.

We write f(n) = Ω(g(n)), If there are positive constantsn0 and c such that, to the right of n0 the f(n)
always lies on or above c*g(n).
Ω(g(n)) = { f(n) : There exist positive constant c and n0 such that 0 ≤ c g(n) ≤ f(n), for all n ≥ n0}
Asymptotic Notations
Big Theta Notation
Big-Theta(Θ) notation gives bound for a function f(n) to within a constant factor.

We write f(n) = Θ(g(n)), If there are positive constantsn0 and c1 and c2 such that, to the right of n0
the f(n) always lies between c1*g(n) and c2*g(n) inclusive.
Θ(g(n)) = {f(n) : There exist positive constant c1, c2 and n0 such that 0 ≤ c1 g(n) ≤ f(n) ≤ c2 g(n),
for all n ≥ n0}

You might also like