Algorithms & Data Structures
Bachelor in Computer Science and Artificial Intelligence (BCSAI) · IE University · the tools for solving computational problems.
An algorithm is a well-defined computational procedure that takes some value, or set of values, as input and produces some value, or set of values, as output. This course builds a strong understanding of the data structures and algorithms available when solving a problem with a computer program — and of how to compare which one is best for the problem at hand.
To make these concepts stick, the course leans on practice and group work as the main learning and grading vehicles, just as in real software engineering.
Learning objectives
By the end of the course, students should be able to:
- Understand the basic concepts and fundamentals of algorithms and apply relevant discrete mathematics concepts (sets, series, sums) and the main problem-solving techniques.
- Analyze algorithm complexity using Big-O notation to evaluate time and space efficiency.
- Implement and apply fundamental data structures — arrays, lists, stacks, queues, trees, heaps, hash tables, and graphs — and understand how they help solve real-life problems.
- Design and analyze classic algorithms using strategies such as divide-and-conquer, greedy, dynamic programming, and backtracking.
- Master sorting and searching techniques, including Merge Sort, Quick Sort, and Binary Search.
- Understand and implement key graph algorithms, such as BFS, DFS, Dijkstra's, and Bellman-Ford's.
- Develop problem-solving skills by modeling, implementing, testing, and optimizing algorithmic solutions in code.
Methodology & assessment
A collaborative, active, applied method: theory sessions paired with practice sessions where students implement algorithms themselves. Three of the 30 sessions are Continuous Evaluation, held after modules 3, 6 and 7.
Learning activities (time weighting)
Estimated 35h lectures · 10h discussions · 55h group work · 50h individual study = 150h.
Final grade (evaluation criteria)
Three 80-minute timed coding tests during class (sessions 14, 24, 29), each implementing a specific algorithm over the material of the preceding modules (2–3, 4–6, and 7).
In teams of 3–4, implement a board game of your choice (kicked off in session 6, presented in sessions 27–28), applying the course's algorithms and data structures.
A comprehensive test in session 30 with theoretical and practical questions on all topics from session 1 to session 26.
Active, ongoing engagement in discussions and problem-solving throughout every session.
Workload & pass rules: 6 ECTS ≈ 150 hours total. The final grade is the weighted sum of the four components above. Attendance and conduct follow IE University's official Attendance, Code of Conduct and Ethics policies; a re-sit/re-take policy applies per university rules. AI policy: GenAI may be used only to research and enhance content learned in class, with explicit acknowledgement — it is prohibited for producing code in graded assignments, resolving gradable assignments, and resolving exercises/homework; misuse is academic misconduct.
Program — 7 modules, 30 sessions
Every numbered session below comes straight from the syllabus. Where a topic has a live demo on the main page, follow the ▸ link.
The course opens by framing the discipline: an algorithm is a precise procedure that maps inputs to outputs, and a data structure is the way we lay that input out in memory. Before writing a single line of code we need a language to compare candidate solutions — asymptotic analysis — so that "which algorithm is best?" becomes a question we can answer quantitatively rather than by intuition.
- Define an algorithm formally and recognise the classes of problems algorithms solve.
- Reason about cost using asymptotic notation independently of hardware or language.
- Distinguish best-, average- and worst-case behaviour, and time vs. space cost.
Introduction to the course; understand the methodologies and tools used throughout. Get a proper definition of what an algorithm is and the kind of problems algorithms solve.
- Course methodology, tools and grading vehicles — how theory, practice sessions and group work fit together over the 30 sessions.
- Definition of an algorithm — a finite, deterministic, well-defined procedure mapping input to output; correctness vs. efficiency as separate concerns.
Introduction to asymptotic notation as a means to describe the efficiency of an algorithm, capturing the order of growth of both time and space as a function of input size n.
- Asymptotic notation — Big-O (upper bound), Ω (lower bound) and Θ (tight bound); why we drop constants and lower-order terms.
- Order of growth — comparing constant, logarithmic, linear, linearithmic, quadratic and exponential cost as n grows.
The largest module builds the core toolkit. We start from the two most basic linear stores — arrays and linked lists — and the elementary O(n²) sorts, then introduce recursion and the divide-and-conquer paradigm that unlocks O(log n) search and O(n log n) sorting. By the end, students can pick the right sort or search for a given memory and access pattern and justify it with a complexity argument.
- Explain how arrays and linked lists differ in memory layout, indexing and insertion cost.
- Implement and analyse insertion, bubble, quick and merge sort, and binary search.
- Apply divide-and-conquer and recurrence reasoning to decompose problems.
- Choose between competing sorts/searches based on stability, memory and input shape.
Understand how simple linear data structures store data in memory, and how the distribution of that data impacts how items can be rearranged and looked up. Arrays give contiguous, index-addressable storage; linked lists scatter nodes joined by pointers.
- Arrays — contiguous memory enabling O(1) random access by index, but O(n) insertion/deletion from shifting.
- Linked lists — pointer-joined nodes giving O(1) insert/delete at a known position but O(n) access and linear search.
Foundations of sorting a collection of items; implement your first sorting algorithms. Both are simple, in-place, comparison-based sorts that are quadratic in the worst case.
- Insertion Sort — grow a sorted prefix one element at a time; O(n²) worst case but O(n) on nearly-sorted input.
- Bubble Sort — repeatedly swap adjacent out-of-order pairs until no swaps remain; always O(n²) comparisons.
How linked lists can be a good alternative to arrays when memory efficiency matters; when each structure is better suited. Linked lists grow without reallocation but lose locality of reference.
- Linked lists for memory-efficient storage — dynamic growth without pre-sized buffers; singly vs. doubly linked variants.
- Array vs. linked-list trade-offs — random access & cache locality (array) vs. cheap splicing & unbounded growth (list).
Kick-off of the capstone: from here until session 27, groups implement a board game of their choice, applying the algorithms and data structures learned in the course.
- Board game coding assignment details — scope, deliverables and timeline of the term-long project.
- Rubrics and grading methodology — how the project is evaluated.
- Set up the groups — teams of 3–4 members.
- Practice — a coding challenge mirroring the Continuous Evaluations to come.
Recursion as a tool to enhance the expressiveness of an algorithm; the Divide and Conquer strategy that splits a large problem into independent subproblems, solves them recursively, and combines the results.
- Recursion fundamentals — base case vs. recursive case; the call stack; how a problem refers to a smaller instance of itself.
- Divide and Conquer — divide into subproblems, conquer recursively, combine; cost captured by recurrences solved with the Master Theorem.
Binary search uses Divide and Conquer to efficiently look up elements in a sorted collection by halving the search interval each step; implement it for any collection of data.
- Binary search — compare to the midpoint and discard half the range each step; O(log n) on sorted input.
- Generalizing — the same halving idea applies to any monotonic predicate, not just equality lookup.
Dives deeper into Quicksort — another example of Divide and Conquer, used to sort a collection of linear data by partitioning around a pivot and recursing on each side.
- Quicksort — choose a pivot, partition smaller/larger elements around it, recurse; in-place with small constants.
- Pivots — average O(n log n), but a poor pivot degrades to O(n²); randomisation mitigates this.
Merge Sort as a good alternative to Quicksort for Divide-and-Conquer sorting; recursively split the list in half, sort each half, and merge the two sorted halves. Understand the differences and when to use each.
- Merge Sort — guaranteed O(n log n) and stable, but needs O(n) auxiliary space.
- Merge Sort vs. Quicksort — merge sort for stability/guaranteed bounds & linked lists; quicksort for in-place speed on arrays.
Having mastered raw arrays and lists, this module layers abstract data types on top of them. Stacks and queues constrain access order to make certain problems trivial, and multidimensional arrays generalise indexing to grids and matrices. The module closes the first assessable block with a timed Continuous Evaluation over modules 2–3.
- Implement stacks and queues over arrays and linked lists with O(1) core operations.
- Select LIFO vs. FIFO discipline to match a problem's ordering requirements.
- Reason about row-major memory layout and access cost for 2-D and n-D arrays.
- Solve combined linear-structure problems under time pressure.
Linear structures built on top of arrays and linked lists that impose ordering restrictions, useful when insertion order affects extraction order. They expose a deliberately narrow interface so the discipline is guaranteed.
- Stack (LIFO) — last-in, first-out; push/pop/peek in O(1). Drives recursion, undo, and expression evaluation.
- Queue (FIFO) — first-in, first-out; enqueue/dequeue in O(1). Drives scheduling and breadth-first traversal.
Solve more complex problems combining the techniques and data structures learned so far, with instructor guidance and student-proposed problems.
- Combined linear-structure problems — e.g. balanced-bracket checking, sliding windows, and using a stack/queue inside a larger algorithm.
Arrays with more than one dimension; how they are stored in memory (typically row-major, flattened into one contiguous block) and the efficiency of typical read/update operations.
- Memory layout — multidimensional indices mapped to one linear offset; row-major vs. column-major and its effect on cache behaviour.
- Read/update efficiency — element access stays O(1); iteration order matters for performance. Use cases: matrices, grids, images, game boards.
A coding task to complete in 80 minutes, covering all material from modules 2 and 3 (sorting, searching, recursion, arrays, lists, stacks, queues).
- Solved individually during class time.
- Graded on correctness and performance — both that it works and that it meets the expected complexity.
A short but pivotal module: it leaves ordered, position-based structures behind and introduces hashing, which trades ordering for near-constant-time lookup. The hash table underpins sets, dictionaries and caches and is one of the most-used structures in practice.
- Explain what makes a good hash function (uniform, fast, deterministic).
- Describe collision-resolution strategies (chaining, open addressing) and the role of load factor.
- Reason about average O(1) vs. worst-case O(n) hash-table operations.
Entering non-linear data structures: hashtables enable fast item retrieval based on hash functions, which map a key to a bucket index so insert, lookup and delete avoid scanning the whole collection.
- Hash functions — deterministic maps from keys to indices that should spread keys uniformly across buckets.
- Collisions — distinct keys landing in the same bucket, resolved by chaining (lists per bucket) or open addressing (probing); load factor governs performance.
Trees are the first hierarchical (non-linear) structures: a root branching into children, with no cycles. The module covers how to lay a tree out, the two canonical ways to visit every node (BFS and DFS), the ordered Binary Search Tree, and the heap — a tree tuned for always retrieving the highest-priority element. These structures power search, scheduling and the pathfinding to come in module 6.
- Describe tree terminology (root, parent, child, leaf, depth, height).
- Implement breadth-first and depth-first traversal and choose between them.
- Build a Binary Search Tree and reason about why balance determines its cost.
- Use a heap / priority queue to retrieve extreme elements efficiently.
Trees as graph-like structures (a connected, acyclic graph with a root): how a tree is arranged and how an algorithm visits all its nodes recursively.
- Tree anatomy — root, parent/child, leaves, subtrees, depth and height; the recursive definition of a tree.
- Traversal — visiting every node exactly once in O(n); pre-/in-/post-order variants of depth-first walking.
Breadth First and Depth First, the most common traversal techniques; implement both and know when to use each. BFS explores level by level; DFS dives down one branch before backtracking.
- Breadth First Search (BFS) — level-order using a queue; finds the shallowest/closest node first.
- Depth First Search (DFS) — explore deep first using a stack or recursion; natural for full enumeration and detecting structure.
A deeper look at a commonly used tree: the Binary Search Tree, which keeps elements ordered so search mirrors binary search.
- BST ordering invariant — every key in the left subtree < node < every key in the right subtree.
- Operations — search, insert and delete in O(h) where h is height: O(log n) if balanced, O(n) if degenerate.
Entirely dedicated to problems where trees are the right data structure, with instructor guidance and student-proposed problems.
- Tree-based problem solving — traversal, height/balance checks, and recursive divide-and-conquer over tree shapes.
Tree-like structures where items are arranged by priority or weight; a (binary) heap keeps the highest- or lowest-priority element at the root for instant access. How they work and when to use them.
- Heap property — every parent dominates its children (max-heap or min-heap); stored compactly in an array.
- Priority queue — insert and extract-min/max in O(log n), peek in O(1); the engine behind Dijkstra and scheduling.
Graphs generalise trees by allowing any node to relate to any other, with edges that may be directed and/or weighted — the natural model for maps, networks, dependencies and game states. The module covers traversal, the two flagship shortest-path algorithms (Dijkstra and Bellman-Ford), and DFS-based techniques for cycle detection and ordering dependencies. It closes with the second Continuous Evaluation spanning modules 4–6.
- Represent graphs as adjacency lists/matrices and choose by density.
- Apply BFS/DFS to connectivity, reachability and cycle detection.
- Compute shortest paths with Dijkstra and know when Bellman-Ford is required.
- Produce a topological order of a Directed Acyclic Graph.
Graphs hold many (possibly directional and/or weighted) relations among elements. What a graph is, what problems it suits, how to represent and traverse it, and how to find the shortest path between two nodes.
- Graph definitions — vertices and edges; directed vs. undirected, weighted vs. unweighted; adjacency list (sparse) vs. matrix (dense).
- Traversal & shortest path — BFS gives the fewest-edges path on unweighted graphs.
- Dijkstra's algorithm — greedy single-source shortest path on non-negative weights using a priority queue.
Dijkstra's limitations (it fails with negative-weight edges) and how algorithms like Bellman-Ford come to the rescue by relaxing every edge repeatedly. Plus two DFS-based tools for directed graphs.
- Bellman-Ford — relax all edges V−1 times; handles negative weights and detects negative cycles.
- Cycle detection — using Depth First search and node colouring / recursion-stack tracking.
- Topological sort — a linear ordering of a DAG so every edge points forward; the basis of dependency resolution and scheduling.
Entirely dedicated to problems where graphs are the right data structure, with instructor guidance and student-proposed problems.
- Graph-based problem solving — modelling a problem as nodes and edges, then picking the right traversal or shortest-path tool.
A coding task to complete in 80 minutes, covering all material from modules 4, 5 and 6 (hashing, trees, heaps, graphs).
- Solved individually during class time.
- Graded on correctness and performance.
The final module steps up from data structures to high-level algorithm design strategies for hard optimisation problems: greedy methods that commit to a locally best choice, and dynamic programming that systematically reuses subproblem answers. It also introduces the idea of intractability (NP-completeness) and approximation. The term ends with group presentations, the last Continuous Evaluation, and the comprehensive final exam.
- Recognise when a greedy choice is provably optimal versus only approximate.
- Identify NP-complete problems and the role of approximation algorithms.
- Spot overlapping subproblems and optimal substructure and design a DP solution.
- Implement DP both top-down (memoization) and bottom-up (tabulation).
Tackling the "impossible" — problems with no known fast (polynomial) solution, the NP-complete class. Greedy algorithms make the locally optimal choice at each step; for hard problems, approximation algorithms trade exactness for speed.
- Greedy strategy — commit to the best immediate choice; optimal only when the problem has the greedy-choice property and optimal substructure.
- NP-complete problems — no known polynomial algorithm; verifying a solution is easy but finding one seems exponential.
- Approximation algorithms — fast methods that return a provably near-optimal answer.
Solving complex problems by breaking them into simpler subproblems, solving each once, and storing the results for reuse — turning exponential recomputation into polynomial work.
- Overlapping subproblems — the same subproblems recur, so caching (memoization) avoids recomputation.
- Optimal substructure — an optimal solution is composed of optimal solutions to its subproblems.
- Top-down vs. bottom-up — recursion with a memo table vs. iterative tabulation; e.g. Fibonacci O(2ⁿ) → O(n), 0/1 knapsack in O(nW).
The first half of the groups give 10–15 minute presentations of their board-game results, defending their engineering choices to the class.
- Why they chose the board game
- What algorithms they used and why
- What data structures they used and why
- What problems they hit and how they solved them
The remaining half of the groups give their 10–15 minute presentations on the same four points (board-game choice, algorithms, data structures, and problems solved).
- Board-game choice, algorithms, data structures and problems solved
A coding task to complete in 80 minutes, covering all material from module 7 (greedy and dynamic programming).
- Solved individually during class time.
- Graded on correctness and performance.
A test exercising understanding of all topics covered from session 1 to session 26 — both theoretical and practical questions.
- Comprehensive theory + practice across all seven modules.
- Covers sessions 1–26 (presentations and CE sessions are assessed separately).
Key concepts
A quick reference to the vocabulary used throughout the program — complexity classes, structures and strategies.
O(1) — cost independent of input size (e.g. array index, hash lookup average).O(log n) — cost grows by a constant each time n doubles (e.g. binary search).O(n) — cost proportional to input size (e.g. a single scan).O(n log n) — the bound of efficient comparison sorts (merge/quick sort).O(n²) — cost grows with the square of n (e.g. bubble/insertion sort).O(2ⁿ) — cost doubles with each added element; brute-force search of hard problems.Bibliography
Recommended reading, annotated with how each text supports the course.