Data Structures and Algorithms CE 373 Study Notes
Data Structures and Algorithms: CE 373
Course Introduction
Lecturer: Vincent M. Nofong, Ph.D.
Department: Computer Science and Engineering
Institution: University of Mines and Technology, Tarkwa - Ghana
Date: January 27, 2026
The course aims to introduce students to data structures and algorithms, focusing on the design of effective or "good" data structures and algorithms.
Key Definitions
Data Structure: A systematic way of organizing and accessing data.
Algorithm: A step-by-step unambiguous procedure for performing some task within a finite amount of time.
Importance of the Course
Data structures and algorithms are foundational to computing. To classify some of them as "good," precise methods of analysis are necessary.
Algorithm Analysis
Why Analyze Algorithms?
Several algorithms exist for the same problem; for instance, sorting can be accomplished using multiple methods, including:
Insertion Sort
Selection Sort
Quick Sort
Algorithm analysis aids in determining the most efficient algorithm based on time and space consumption.
Criteria for Judging Algorithms
Correctness: Does the algorithm provide a solution to the problem within a finite number of steps?
Efficiency: What are the resource requirements (in terms of memory and time) to execute the algorithm?
Goals of Algorithm Analysis
The primary goal is to compare algorithms in terms of runtime and additional factors like memory and developer effort.
What is Runtime Analysis?
Runtime analysis involves determining how processing time increases as the size of the problem size increases. The input size can vary based on the problem type, including:
Size of an array
Polynomial degree
Number of elements in a matrix
Vertices and edges in a graph
Comparing Algorithms
Experimental Analysis
Although algorithms can be compared using their runtimes experimentally, this approach has challenges:
Hardware/Software Dependency: Runtimes can only be directly compared if tests are conducted in identical environments.
Limited Test Inputs: Experiments can only account for a limited set of inputs resulting in potentially significant overlooked runtimes.
Full Implementation Requirement: A complete implementation of an algorithm is needed to analyze its running time experimentally.
Advanced Analysis Techniques
To analyze efficiency without experimental analysis, we can:
Conduct analysis based on high-level descriptions of the algorithms.
Define a set of primitive operations (e.g., assigning values, performing arithmetic operations, comparing numbers, accessing array elements, method calls, and returns).
Count the executed primitive operations to establish a runtime measure.
Measuring Operation Counts as a Function of Input Size
To understand algorithm runtime growth, associate a function with each algorithm to characterize primitive operation counts as a function of input size . This allows comparisons across three analysis types:
Worst Case: Identifies the input type that results in maximum execution time.
Best Case: Identifies input for minimum execution time.
Average Case: Predicted runtime based on running the algorithm multiple times with various inputs generated from a specified distribution.
Determining Which Case to Use
Average-case analysis is complex as it requires defining the probability distribution of input sets, which is often difficult.
Worst-case analysis is simpler as it only necessitates finding the worst-case input. This method often ensures that algorithms perform well under all input scenarios.
Asymptotic Analysis
Understanding the expressions for best, average, and worst cases involves identifying upper and lower bounds of algorithm runtime. This is expressed using functions that correlate the input size to values that determine growth rates.
Notations Used in Asymptotic Analysis
Big-O Notation (O): Indicates that function is growth-wise less than or equal to function multiplied by a constant factor, in the asymptotic sense as approaches infinity.
Definition: For functions and :
f(n) ext{ is } O(g(n)) ext{ if there exists a } c > 0 ext{ and an } n0 ext{ such that } f(n) ext{ is less than or equal to } c imes g(n) ext{ for } n ext{ greater than or equal to } n0.
Examples of Big-O Notation
The function is .
The function is .
The function is .
Properties of Big-O Notation
Allows the neglecting of constant factors and lower-order terms in order to focus on the main factors impacting growth rate.
Example: is as justifying leads to a constant factor of 15, starting from .
Additional Observations Regarding Big-O Notation
For polynomial functions of degree , where (with ad > 0):
when
Big-Omega Notation (Ω)
Provides an asymptotic measure indicating that a function grows at a rate that is greater than or equal to another function.
Definition: For functions and :
f(n) ext{ is } Ω(g(n)) ext{ if } g(n) ext{ is } O(f(n)), ext{ implying existence of } c > 0 ext{ and } n_0 ext{ where } f(n) ext{ is greater than or equal to } c imes g(n).
Big-Omega Examples
For , we observe it is because for .
The expression is also .
Big-Theta Notation (Θ)
Represents an asymptotic measure that indicates a function's growth rate matches another, up to constant factors.
Definition:
Big-Theta Examples
For the function , it is since:
Functions for Comparative Analysis
Common Growth Rate Functions in algorithm analysis include:
Constant Function:
Logarithm Function: for some constant b > 1
Linear Function:
N-Log-N Function:
Quadratic Function:
Cubic Function and Other Polynomials: Cubic Functions: . Polynomials:
Determining Runtime Complexity of Algorithms
Sequence of Statements
If each statement is simple, the time complexity for each is constant, leading to an overall complexity of:
If-then-Else Statements
The worst-case execution time is defined as:
Example: For two sequences where one is and the other is , the overall worst-case time for the if-else statement is .
Loops
The total time complexity of loops can be evaluated as:
For constant loops:
For linear iterations:
For nested loops:
Nested Loops
The total complexity for nested loops simplifies to:
Consecutive Statements
For consecutive statements, total time complexity can be determined as:
Example:
Other Time Complexities
O(log n): Relevant if loop variables double or halve
every iteration.O(log log n): Applies when loop variables vary exponentially.
Examples of Time Complexity
If a loop doubles its control variable starting at 1, the number of iterations can be categorized as:
If after the -th iteration the variable equals (i.e., ), then:
Taking logs on both sides yields: , hence .
Space Complexity of Algorithms
Definition: Space complexity quantifies the amount of memory required by an algorithm, accounting for:
All variables (global and local)
Dynamic data structures
Stack contents during recursion
Constants and Linear Space Complexity
If a constant number of variables are necessary for execution, the space complexity is:
If an algorithm requires declaring an array of size , the complexity denotes:
Complexity Calculations
Space complexity can be trickier than time complexity, as different variables/data structures may not be needed simultaneously. Global variables persist in memory, while local variables and stack data are only present during method execution.