Data Structures & Algorithms

Chapter 1
Foundations of Data Structures and Algorithms

Bachelors Program in Full Stack Development
Data Structures & Algorithms   •   Bachelor

Foundations of Data Structures and Algorithms

Introduction

Every software system transforms information. A web application stores user records, validates requests, searches products, schedules tasks, and returns results. These activities depend on two foundational choices: how information is represented and how operations on that information are performed. Data structures address representation and organization; algorithms describe systematic procedures for solving problems.

A data structure is not merely a container such as an array or linked list. It is a design that combines stored values, relationships among values, and permitted operations. An algorithm is not merely code. It is a finite, precise, and effective method for producing a result from specified inputs. Understanding the distinction between an abstract problem and its implementation is essential for writing reliable, efficient, and maintainable software.

This chapter establishes the mathematical, conceptual, and engineering foundations required for later study of arrays, lists, trees, graphs, hashing, sorting, searching, and algorithm analysis.

Learning Objectives

By the end of this chapter, you should be able to:

  1. Distinguish data, information, data structures, algorithms, and programs.
  2. Define abstract data types, interfaces, implementations, and invariants.
  3. Explain how specifications differ from implementations and evaluations.
  4. Apply basic ideas from sets, logic, relations, functions, and mathematical induction.
  5. Describe memory representation, addresses, references, and value encoding.
  6. Identify computational models and explain why performance depends on assumptions.
  7. State correctness, termination, and complexity requirements for algorithms.
  8. Evaluate design alternatives using correctness, efficiency, usability, and maintainability.

1. Data, Information, and Representation

Data consists of recorded symbols or values. A number such as 42, a character such as A, and a sequence of coordinates are all data. Information is data interpreted within a context. The value 42 may represent an age, a temperature, or an identifier depending on its meaning.

A computer stores data as finite patterns of bits. A bit has two possible states, conventionally 0 and 1. A group of eight bits is a byte. If an unsigned integer uses w bits, it can represent 2w distinct patterns, usually the integers 0 through 2w - 1. This range assumes that every bit pattern is used for an unsigned value; signed encodings and language-specific representations may use the patterns differently.

Representation affects operations. An integer may be stored in binary, a character in an encoding such as UTF-8, and a record as several adjacent fields. The abstract value remains conceptually distinct from its physical representation. For example, the abstract string “cat” can be represented by different byte sequences under different encodings.

A data structure organizes data so that required operations can be performed. An array emphasizes indexed access and contiguous storage. A linked list emphasizes sequential connections between nodes. A hash table emphasizes average fast lookup through a mapping from keys to positions. No structure is universally best; suitability depends on operations, constraints, and workload.

2. Algorithms and Programs

An algorithm is a finite sequence of unambiguous instructions that transforms input into output and satisfies a specified problem. Common properties include:

  • Input: zero or more externally supplied values.
  • Output: one or more results.
  • Definiteness: each step is precisely interpretable.
  • Finiteness: execution terminates for every input within the stated domain.
  • Effectiveness: each step can be carried out by an available computational process.
  • Correctness: the output satisfies the problem specification.

A program is an implementation of one or more algorithms in a programming language. The same algorithm may have implementations in JavaScript, Python, Java, or C. Conversely, two programs may produce the same outputs while using different algorithms and data structures.

Consider finding the largest value in a nonempty sequence. A direct algorithm is:

largest ← first element
for each remaining element x:
    if x > largest:
        largest ← x
return largest

For a sequence of length n, the algorithm examines each element once. Its running time is proportional to n, commonly written Θ(n). It uses constant additional storage, Θ(1), excluding the input sequence. The assumptions matter: the sequence must be nonempty, comparison must be defined, and accessing the next element must have a stated cost.

3. Specifications, Implementations, and Evaluation

A specification states what a component must do without prescribing how it does it. For a queue, a specification might state that insertion occurs at the rear and removal occurs at the front. It does not require an array, linked list, or circular buffer.

An implementation is a concrete representation and set of procedures that realizes the specification. An evaluation assesses whether the implementation satisfies functional and non-functional requirements.

LevelCentral questionExample
SpecificationWhat behavior is required?dequeue removes the oldest item
InterfaceHow can a client request behavior?queue.dequeue()
ImplementationHow is behavior realized?Circular array with two indices
EvaluationDoes it work adequately?Correctness, time, space, reliability

Evaluation commonly considers:

  • Correctness: Does the result satisfy the specification?
  • Time complexity: How does execution cost grow with input size?
  • Space complexity: How much additional memory is required?
  • Robustness: Does the component handle invalid or extreme inputs?
  • Maintainability: Can developers understand and modify it safely?
  • Security: Can hostile input cause disclosure, corruption, or denial of service?

A fast implementation that returns incorrect answers is not successful. Likewise, a correct implementation may be unsuitable if it exceeds memory limits or violates latency requirements.

4. Abstract Data Types and Interfaces

An abstract data type (ADT) defines a collection of values and operations, together with the meaning of those operations. It hides representation details. Typical ADTs include stacks, queues, maps, sets, and priority queues.

A stack supports operations such as:

  • push(x): place value x on top;
  • pop(): remove and return the top value;
  • peek(): inspect the top value without removing it;
  • isEmpty(): report whether the stack contains no values.

Its defining rule is last-in, first-out (LIFO). An array-based stack and a linked-node stack are different implementations of the same ADT if they provide equivalent observable behavior.

An interface is the client-visible contract through which operations are requested. It may include method names, parameter types, return values, exceptions, preconditions, and postconditions. A strong interface minimizes unnecessary exposure of representation. This is an application of abstraction and information hiding.

The distinction is important in full-stack development. A browser-facing API may expose operations such as addItem and removeItem, while the server may use a database index, cache, or in-memory map. Clients should depend on the contract rather than on private storage details.

5. Invariants and Correctness

An invariant is a property that remains true at designated points during execution. Invariants are central to reasoning about data structures and loops.

For a stack represented by an array A and integer top, one possible invariant is:

  • top equals the number of stored elements;
  • valid elements occupy positions 0 through top − 1;
  • positions at or beyond top are not logically part of the stack.

A correct implementation must preserve this invariant after initialization and after every public operation.

Loop correctness is often established using three ideas:

  1. Initialization: the invariant is true before the first iteration.
  2. Maintenance: one iteration preserves the invariant.
  3. Termination: when the loop ends, the invariant plus the termination condition implies the result.

For the largest-element algorithm, an invariant after processing the first k elements is: largest equals the maximum of those k elements. It is true for k = 1. When the next value is processed, assigning the greater of the current maximum and the new value preserves the claim. When all n values are processed, largest is the maximum of the complete sequence.

Correctness may be:

  • Partial: if the algorithm terminates, its output is correct.
  • Total: it terminates and its output is correct for every permitted input.

Termination must be addressed separately. A loop can preserve a correct invariant forever if its control variable never reaches the stopping condition.

6. Discrete Mathematical Foundations

6.1 Logic

A proposition is a statement that is either true or false. If P and Q are propositions, common operators include:

  • conjunction: P ∧ Q, true only when both are true;
  • disjunction: P ∨ Q, true when at least one is true;
  • negation: ¬P, true when P is false;
  • implication: P → Q, false only when P is true and Q is false;
  • equivalence: P ↔ Q, true when both have the same truth value.

The implication P → Q does not assert that P is true. This distinction prevents a common error in algorithm reasoning. A precondition may be required for a theorem without being satisfied by every possible input.

6.2 Sets

A set is a collection of distinct objects. If A = {1, 2, 3}, then 2 ∈ A, while 4 ∉ A. The cardinality of A, written |A|, is 3. Important operations include union A ∪ B, intersection A ∩ B, difference A − B, and Cartesian product A × B.

Sets model collections such as user identifiers or visited vertices. Unlike sequences, ordinary sets do not assign significance to order or duplicate occurrences. Choosing a set when order matters would lose required information.

6.3 Relations and Functions

A binary relation from set A to set B is a subset of A × B. A relation may represent “is connected to,” “precedes,” or “has permission to access.” Relations can be reflexive, symmetric, antisymmetric, or transitive.

A function f: A → B assigns exactly one element of B to every element of A. The set A is the domain and B is the codomain. A function may be injective, surjective, or bijective. Hashing often behaves like a function from keys to table positions, although collisions mean distinct keys can map to the same position.

6.4 Induction and Recurrence

Mathematical induction proves a proposition for all integers n ≥ n₀ by showing:

  1. a base case at n₀;
  2. an inductive step showing that truth for k implies truth for k + 1.

For recursive algorithms, a related technique is structural induction: prove correctness for the smallest structure, then prove that correct solutions for smaller structures imply correctness for a larger structure.

A recurrence describes cost recursively. For binary search on a sorted array, the search interval is approximately halved at each step. Its comparison count satisfies a recurrence of the form:

T(n) = T(⌊n/2⌋) + c, n > 1

where c is a constant cost for one comparison and related bookkeeping. Repeated halving gives T(n) = Θ(log n), assuming constant-time indexed access and a suitable cost model.

7. Memory Representation

Main memory can be modeled as a sequence of addressable locations. An address identifies a location; the contents at that location store bits. A variable name is a language-level reference to a value or location, but the exact behavior depends on the language.

An array stores elements in a logical sequence. In a simple contiguous representation, the address of element i can be modeled as:

address(A[i]) = base(A) + i × s

where base(A) is the address of the first element, i is a zero-based index, and s is the size in bytes of each element. This formula assumes fixed-size elements and contiguous storage. It explains why indexed access is generally constant time in such an array. It does not apply directly to variable-size objects or non-contiguous structures.

A linked structure stores nodes containing data and one or more references. Nodes need not be adjacent in memory. Following a reference may require a memory access, and poor locality can make a theoretically efficient operation slower in practice.

Memory management strategies include manual allocation, automatic garbage collection, stack allocation, heap allocation, and ownership systems. Their details differ across languages. Errors such as dangling references, double frees, memory leaks, and accidental retention can affect correctness and security.

8. Computational Models and Complexity

A computational model states what operations are considered primitive and what they cost. The common RAM-style model treats arithmetic on bounded machine words, comparisons, assignments, and indexed array access as constant-time operations. This is an abstraction, not a universal physical law.

Asymptotic notation describes growth as input size increases:

  • O(g(n)) is an upper-bound class;
  • Ω(g(n)) is a lower-bound class;
  • Θ(g(n)) is a tight asymptotic class.

For example, if an algorithm performs 3n + 7 elementary operations, its complexity is Θ(n). Constants matter in real systems, but asymptotic notation focuses on growth. It does not guarantee correctness, measure exact runtime, or capture every hardware effect such as cache behavior, branch prediction, input distribution, or network latency.

Best-case, worst-case, and average-case analyses answer different questions. A linear search has best-case time Θ(1) when the first item matches, and worst-case time Θ(n) when the item is absent or last. Average-case analysis requires a probability model for inputs; it should not be claimed without stating that model.

Amortized analysis evaluates a sequence of operations rather than each operation independently. Dynamic-array insertion is usually constant amortized time when capacity grows geometrically, although an individual resizing operation can take linear time. The result depends on the resizing policy and the cost model.

9. A Design Framework for Data-Structure Problems

A disciplined process helps avoid premature coding:

  1. Clarify the problem. Identify inputs, outputs, constraints, invalid cases, and required operations.
  2. Write the specification. State preconditions, postconditions, and observable behavior.
  3. Choose an abstraction. Decide whether the problem requires a sequence, set, map, graph, stack, queue, or another ADT.
  4. Identify invariants. State properties that must remain true.
  5. Select an implementation. Compare alternatives using expected operations, scale, memory, and concurrency needs.
  6. Prove or test correctness. Use reasoning, tests, assertions, and boundary cases.
  7. Analyze resources. Estimate time, space, I/O, and operational costs.
  8. Measure responsibly. Benchmark representative workloads without confusing one machine’s result with a general theorem.

10. Illustrative Case: Product Search in an Online Store

Background. An online store must search products by an exact product identifier and also display products in sorted price order.

Problem. A simple unsorted array supports storage and iteration, but exact lookup may require scanning every record. With one million products, repeated scans create avoidable latency.

Analysis. The system has two distinct access patterns. Exact identifier lookup benefits from a map or database index. Sorted display benefits from an ordered index or a sorting procedure. A single structure need not serve every purpose.

Approach. The service maintains a map from product ID to product record for direct lookup. It separately maintains an index ordered by price, updated when prices change. The interface specifies that an unknown ID returns a documented “not found” result and that price ordering is stable for equal prices.

Outcome. The abstraction separates client behavior from storage choices. The map can be implemented with hashing, while the ordered index may use a balanced search tree or database index. Evaluation includes correctness tests for duplicate IDs, missing products, price updates, and empty results, together with latency and memory measurements under realistic workloads.

Learning points. Requirements should drive structure selection. Lookup complexity, update complexity, memory overhead, ordering guarantees, and operational simplicity must be evaluated together. Caching may reduce latency but introduces consistency and invalidation concerns; it is an optimization, not a substitute for a correct source of truth.

11. Challenges, Ethics, and Contemporary Practice

Data structures and algorithms influence accessibility, cost, privacy, and fairness. A poorly designed algorithm may deny service to legitimate users, expose sensitive records, or amplify biased data. Developers should minimize collected data, protect identifiers, validate untrusted input, and document assumptions.

Security is algorithmically relevant. Hash-table implementations must consider adversarial collision patterns; authentication systems must use appropriate password-hashing algorithms rather than general-purpose hashes; input sizes should be bounded where worst-case behavior can enable denial of service.

Modern systems also use distributed data structures, persistent storage, parallel processors, specialized hardware, and approximate algorithms. AI systems depend heavily on data pipelines, indexing, graphs, vector search, and optimization procedures. Their sophistication does not eliminate the need for specifications, invariants, complexity analysis, testing, and human accountability.

Best practice is to select the simplest structure that satisfies documented requirements, make invariants explicit, measure representative workloads, and revisit choices when scale or access patterns change.

Chapter Summary

Data structures organize information and algorithms transform it. An abstract data type specifies values and operations while hiding representation; an interface exposes the usable contract; an implementation realizes that contract; and evaluation measures correctness, resources, and quality. Invariants support rigorous reasoning about loops and data structures, while induction supports proofs over finite and recursive structures. Sets, relations, functions, and logic provide a mathematical language for modeling software problems. Memory representation explains array indexing, references, locality, and storage costs. Computational models make complexity claims meaningful, but asymptotic notation does not replace correctness testing or practical measurement. Effective design begins with requirements and specifications, proceeds through abstraction and invariant identification, and ends with justified implementation and evaluation.

Key Terms

Data: Recorded symbols or values.

Information: Data interpreted in a meaningful context.

Data structure: An organization of data and relationships supporting operations.

Algorithm: A finite, precise procedure for solving a specified problem.

Abstract data type: A specification of values and operations independent of representation.

Interface: The client-visible contract for using a component.

Implementation: A concrete realization of a specification.

Specification: A statement of required behavior.

Invariant: A property preserved at designated execution points.

Precondition: A condition required before an operation begins.

Postcondition: A condition guaranteed after an operation completes.

Correctness: Conformance of results to the specification.

Complexity: Resource growth as input size changes.

Computational model: Assumptions about primitive operations and their costs.

Set: A collection of distinct elements.

Relation: A subset of a Cartesian product.

Function: A mapping assigning one codomain value to each domain element.

Induction: A proof method using a base case and an inductive step.

Amortized analysis: Analysis of average cost over a sequence of operations.

Memory representation: The physical encoding and organization of values in storage.

Review Questions

Short Answer Questions

  1. What is the difference between an abstract data type and an implementation?
  2. State three properties commonly expected of an algorithm.
  3. What is an invariant, and why is it useful?
  4. Explain why a computational model is needed for complexity analysis.
  5. Distinguish a set from a sequence.

Long Answer Questions

  1. Explain the relationship among specification, interface, implementation, and evaluation using a queue as an example.
  2. Describe how mathematical induction can support the correctness proof of a recursive algorithm.
  3. Compare an array-based structure with a linked structure, including access, memory, and locality considerations.
  4. Explain best-case, worst-case, average-case, and amortized analysis, giving an example of each where appropriate.
  5. Discuss how abstraction and information hiding improve the maintainability of full-stack systems.

Analytical / Application Questions

  1. A service performs one million exact product-ID searches on an unsorted sequence. Propose a more suitable ADT and implementation, state the assumptions behind your choice, and discuss update and memory trade-offs.
  2. Design a loop invariant for an algorithm that counts the number of positive values in an array. Explain initialization, maintenance, and termination.
  3. A dynamic array doubles its capacity whenever it becomes full. Explain why an individual insertion can be linear while the amortized insertion cost can be constant under the usual RAM model and geometric-growth assumptions.

Multiple Choice Questions with Answers

Question 1

Which statement best defines an abstract data type?

A. A specification of values and operations independent of representation

B. A contiguous block of physical memory

C. A programming language compiler

D. A benchmark report containing runtime measurements

Correct Answer: A. A specification of values and operations independent of representation

Question 2

For a contiguous zero-based array of fixed-size elements, which expression models the address of element i?

A. base(A) + i × s

B. base(A) ÷ i × s

C. i − base(A) + s

D. base(A) + s ÷ i

Correct Answer: A. base(A) + i × s

Question 3

Which property is part of the standard proof method for loop correctness?

A. The invariant is initialized, maintained, and combined with termination

B. The loop must use recursion

C. Every iteration must allocate memory

D. The input must be randomly ordered

Correct Answer: A. The invariant is initialized, maintained, and combined with termination

Question 4

A binary-search recurrence T(n) = T(⌊n/2⌋) + c, with constant c, has which asymptotic solution under the stated model?

A. Θ(1)

B. Θ(log n)

C. Θ(n)

D. Θ(n²)

Correct Answer: B. Θ(log n)

Question 5

Which operation order characterizes a stack?

A. First-in, first-out

B. Last-in, first-out

C. Random-in, first-out

D. Priority-in, last-out

Correct Answer: B. Last-in, first-out

Question 6

What does a precondition specify?

A. A condition that must hold before an operation begins

B. The exact hardware instruction used by an operation

C. The average runtime measured after deployment

D. A property that must hold only after program termination

Correct Answer: A. A condition that must hold before an operation begins

Question 7

If an algorithm performs 3n + 7 elementary operations, what is its asymptotic time complexity?

A. Θ(1)

B. Θ(log n)

C. Θ(n)

D. Θ(n²)

Correct Answer: C. Θ(n)

Question 8

Which statement about asymptotic notation is correct?

A. Θ notation describes exact runtime on every machine

B. Θ notation describes growth within constant factors under stated assumptions

C. Θ notation proves that an algorithm is correct

D. Θ notation captures all cache and network effects exactly

Correct Answer: B. Θ notation describes growth within constant factors under stated assumptions

Question 9

Which structure is most directly designed to support membership testing without requiring element order?

A. Set

B. Queue

C. Stack

D. Sequence

Correct Answer: A. Set

Question 10

An unsorted array contains 8 distinct values, and a linear search checks for a value known to be at the final position. How many elements must the search inspect?

A. 1

B. 4

C. 7

D. 8

Correct Answer: D. 8

Data Structures & Algorithms
Chapter 1 of 15