You already know what a data structure is and why choosing well matters. The next natural step is to get to know the catalog: which structures exist and how are they classified? This lesson is the map of the course: we will introduce the major families of structures (linear and nonlinear, static and dynamic, homogeneous and heterogeneous), see what role each will play in TaskFlow, and review the structures Python ships with out of the box, which will be our starting point. We won't go deep into any of them — each has its own module — but by the end you will be able to place any structure on the map and understand the itinerary we will follow.
Contents
- Classification 1: linear vs nonlinear
- Classification 2: static vs dynamic
- Classification 3: homogeneous vs heterogeneous
- The course catalog and its role in TaskFlow
- Python's built-in structures: our starting point
Classification 1: linear vs nonlinear
The first question you can ask of any structure is: how do its elements relate to one another?
- In a linear structure, the elements form a sequence: each element has (at most) one predecessor and one successor. It is the "one after another" relationship.
- In a nonlinear structure, an element can relate to several at once: hierarchies (a parent with several children) or networks (arbitrary connections between nodes).
graph TB
subgraph Linear
A1[Task 1] --> A2[Task 2] --> A3[Task 3] --> A4[Task 4]
end
subgraph Nonlinear: hierarchy
B1[Work] --> B2[Client A]
B1 --> B3[Client B]
B2 --> B4[Invoices]
B2 --> B5[Meetings]
end
subgraph Nonlinear: network
C1[Task A] --> C2[Task B]
C1 --> C3[Task C]
C2 --> C4[Task D]
C3 --> C4
end
All three patterns show up naturally in TaskFlow:
- The task board is linear: tasks come in order, one after another.
- The categories are hierarchical: "Work" contains "Client A", which contains "Invoices".
- The dependencies are a network: task D depends on B and C, which in turn depend on A.
Lists, stacks, and queues are linear (modules 2 to 4). Trees (hierarchies, module 6) and graphs (networks, module 7) are nonlinear. Hash tables (module 5) are a case apart: their elements maintain no ordering relationship with one another — neither sequence nor hierarchy; what defines them is the direct association between each key and its value.
The classification matters because it determines how the structure is traversed: a sequence is traversed from start to finish; a hierarchy or a network demands more elaborate traversal strategies (we'll see them in their modules).
Classification 2: static vs dynamic
The second question: can the structure's size change during execution?
- A static structure has a fixed size, decided when it is created. It occupies a block of memory of known size and neither grows nor shrinks.
- A dynamic structure grows and shrinks as elements are inserted or removed, adapting its memory usage at runtime.
| Aspect | Static | Dynamic |
|---|---|---|
| Size | Fixed at creation | Changes during execution |
| Memory | Reserved all at once, contiguous | Requested and released on the fly |
| Main advantage | Simplicity and very fast access | Flexibility: no need to predict the size |
| Typical risk | Running short or wasting space | Extra memory-management overhead |
| Classic example | Fixed-size array (C, Java) | Linked list, Python list |
The canonical example of a static structure is the fixed-size array, common in languages like C or Java: you request room for exactly 100 elements and that's what you get. In Python almost everything you will use is dynamic — a list grows without you worrying about a thing — but the distinction remains crucial for two reasons:
- Python's dynamic structures are built on top of static mechanisms underneath, and that "underneath" explains their costs (we'll see it in lesson 01-05 with arrays and memory).
- As soon as you step outside Python (databases, embedded systems, other languages), fixed sizes reappear.
For TaskFlow: the number of tasks is unpredictable and changes constantly, so we will need dynamic structures almost always. In contrast, something like the three possible statuses of a task (pending, in_progress, done) is a fixed set that never grows: a static, immutable structure (a tuple, as we'll see below) represents it better.
Classification 3: homogeneous vs heterogeneous
Third question: are all the elements of the same type?
- A homogeneous structure only admits elements of a single type: all integers, all strings...
- A heterogeneous structure mixes types: an integer next to a string next to an object.
# Homogeneous: task ids, all integers
pending_ids = [4, 8, 15, 16, 23]
# Heterogeneous: a task with fields of different types
task = {
"id": 42, # integer
"title": "Migrate server", # string
"priority": "high", # string
"completed": False, # boolean
"tags": ["infra", "urgent"], # another structure inside!
}In strictly typed languages (C, Java), arrays are homogeneous by obligation. Python is flexible: a list accepts any mixture. But the fact that you can mix doesn't mean you should: in professional practice, collections tend to stay homogeneous ("a list of tasks", "a set of ids") and heterogeneity is reserved for representing records with named fields, like the task dictionary in the example. This discipline makes the code predictable: if you know that pending_ids only contains integers, you can operate confidently on any of its elements.
Also notice the last line of the example: "tags" contains a list inside the dictionary. Structures compose with one another, and real applications — TaskFlow included — are always compositions: a list of dictionaries, a dictionary of lists, a tree whose nodes contain queues...
The course catalog and its role in TaskFlow
With the three classifications in hand, we can now present the complete catalog of structures we will study, each with the TaskFlow need it will solve:
| Structure | Family | The idea in one sentence | Use in TaskFlow | Module |
|---|---|---|---|---|
| List | Linear, dynamic | Sequence of elements in order | The task board | 2 |
| Stack | Linear, dynamic | Last in, first out (LIFO) | The "undo" of actions | 3 |
| Queue | Linear, dynamic | First in, first out (FIFO) | Processing notifications | 4 |
| Hash table | Associative, dynamic | Each key leads directly to its value | Instant lookup by id | 5 |
| Tree | Nonlinear (hierarchy), dynamic | Parent nodes with child nodes | Categories and subcategories | 6 |
| Graph | Nonlinear (network), dynamic | Nodes freely connected to one another | Dependencies between tasks | 7 |
Two observations about the table:
- The terms LIFO (Last In, First Out) and FIFO (First In, First Out) are the only new "jargon": picture them as the stack of plates and the supermarket line from lesson 01-01, and you'll have 90% of the intuition.
- The order of the modules is no accident: it goes from simplest to richest. Stacks and queues are built from ideas in lists; trees generalize the idea of "an element pointing to others"; graphs generalize trees. Each module builds on the previous one, just as TaskFlow will grow piece by piece.
The complete journey, seen as an itinerary:
graph LR
L[Lists<br/>M2] --> P[Stacks<br/>M3] --> C[Queues<br/>M4] --> H[Hash tables<br/>M5] --> A[Trees<br/>M6] --> G[Graphs<br/>M7]
Remember that this lesson is only the map: the precise definition of each structure, its operations, implementations, and costs are developed in its corresponding module.
Python's built-in structures: our starting point
Python ships with four data structures that we will use constantly, both in their own right and to build the structures in the catalog. It's worth being clear about the role of each:
| Structure | Syntax | Ordered? | Mutable? | Duplicates? | Typical use |
|---|---|---|---|---|---|
list |
[1, 2, 3] |
Yes (by position) | Yes | Yes | Sequences that change |
tuple |
(1, 2, 3) |
Yes (by position) | No | Yes | Fixed records, constants |
dict |
{"a": 1} |
By insertion | Yes | Keys no | Key → value associations |
set |
{1, 2, 3} |
No | Yes | No | Membership and uniqueness |
("Mutable" means it can be modified after creation; "ordered", that its elements maintain a defined order.)
Let's see them in action with TaskFlow data:
# list: the board draft — ordering and constant changes
board = ["Design logo", "Write report", "Send invoice"]
board.append("Call client") # grows dynamically
# tuple: the possible statuses — a FIXED set nobody should touch
STATUSES = ("pending", "in_progress", "done")
# STATUSES.append("other") -> AttributeError: tuples don't change
# dict: a task as a heterogeneous record with named fields
task = {"id": 7, "title": "Send invoice", "status": "pending"}
print(task["title"]) # access by key, not by position
# set: unique tags used in the project — no duplicates
tags = {"urgent", "client", "urgent"}
print(tags) # {'urgent', 'client'} — the duplicate vanishesPoints worth highlighting in the example:
board.append(...)shows the dynamic nature oflist: it grows without declaring a size.STATUSESas a tuple is the correct static, immutable choice for data that must not change; if someone tries to modify it, Python raises an error, protecting the program. The all-caps naming convention signals "this is a constant".- The
setremoved the duplicate"urgent"automatically: uniqueness is part of its contract. - These four structures are, in the terms of lesson 01-01, highly polished implementations of certain ADTs:
listof a dynamic sequence,dictof an associative table,setof a mathematical set. In the coming modules we will use them both directly and as "building material" to implement stacks, queues, trees, and graphs.
What about the structures Python doesn't ship with (linked lists, trees, graphs)? We will build them ourselves with classes, exactly as we did with ListStack in lesson 01-01. That's where much of the course's value lies: not just using structures, but knowing how to make them.
Common Mistakes and Tips
- Using
listfor everything. It's the number one vice of the Python beginner: the list is so convenient it becomes a universal hammer. Before typing[], ask yourself: do I need order? (if not, maybeset), do I access by name? (maybedict), is the data fixed? (maybetuple). - Confusing the syntax of
dictandset. Both use curly braces:{"a": 1}is a dictionary (it haskey: value),{"a", "b"}is a set (values only). And watch out: a bare{}creates an empty dictionary; for an empty set you must writeset(). - Believing the classifications are rigid compartments. They are axes of analysis, not exclusive drawers: the same structure can be described along all three axes at once (a Python
listis linear, dynamic, and potentially heterogeneous), and hash tables don't quite fit on the linear/nonlinear axis. - Tip: when you come across a new structure in any language or library (a
deque, aDataFrame, a JavaTreeMap...), place it along the three axes of this lesson and figure out which ADT it answers to. It's the fastest way to "read" an unfamiliar structure.
Exercises
Exercise 1: classifying structures
Classify each scenario along the axes we've seen (linear/nonlinear; and where it makes sense, static/dynamic and homogeneous/heterogeneous):
- The months of the year in a calendar application.
- A company's organizational chart.
- An office's print queue.
- The friendship connections of a social network.
Exercise 2: choosing the built-in structure
For each TaskFlow need, choose the most suitable Python built-in structure (list, tuple, dict, or set) and justify it in one sentence:
- The days of the week on which reminders can be scheduled (Monday to Sunday, fixed).
- The ids of the tasks the user has marked as favorites (no repeats, no relevant order).
- The mapping between each user and their list of projects.
- The history of task titles viewed, in order, with possible repeats.
Exercise 3: composing structures
Write in Python the representation of a mini TaskFlow board with these requirements: there must be three fixed status columns (pending, in_progress, done); each column holds its tasks in order; each task has an id, a title, and a set of tags with no duplicates. Create the board with at least two tasks and write one line of code that adds a tag to an existing task. State which built-in structure you used at each level and why.
Solutions
Solution 1:
- Months of the year: linear (an ordered sequence), static (there are always 12), and homogeneous (all strings). In Python, a tuple would be the natural fit.
- Organizational chart: nonlinear, hierarchical (each person has a manager and may have several reports): the shape of a tree. Dynamic (the workforce changes).
- Print queue: linear and dynamic; arrival order is the essential relationship (FIFO). Homogeneous (they are all print jobs).
- Friendships: nonlinear, a network (each person connects to many others with no hierarchy): the shape of a graph. Dynamic.
Solution 2:
tuple: a fixed, ordered collection that must not be modified:DAYS = ("monday", ..., "sunday").set: guaranteed uniqueness and fast membership; order doesn't matter:favorites = {4, 8, 15}.dict: key → value association, with the user as key and their project list as value:{"anna": ["web", "app"]}(notice: adictcontaining alist— structure composition).list: an ordered, dynamic sequence with duplicates allowed: exactly the list's contract.
Solution 3:
board = {
"pending": [
{"id": 1, "title": "Design logo", "tags": {"design", "client"}},
{"id": 2, "title": "Send invoice", "tags": {"admin"}},
],
"in_progress": [],
"done": [],
}
# Add a tag to the task with id 1 (first one in "pending"):
board["pending"][0]["tags"].add("urgent")Level-by-level justification: a dict for the columns (access by status name); a list per column (tasks keep an order and the collection grows and shrinks); a dict per task (a heterogeneous record with named fields); a set for the tags (automatic uniqueness). Four built-in structures composing to model a real domain. Note: the three status keys are fixed, but a dict is the practical option for access by name; the immutability of "there are only three statuses" is something we will enforce with other techniques later on.
Conclusion
You now have the complete map: structures are classified by how their elements relate (linear like lists, stacks, and queues; nonlinear like trees and graphs; associative like hash tables), by whether their size is fixed or variable (static vs dynamic), and by whether they mix types (homogeneous vs heterogeneous). You know what role each will play in TaskFlow and you have Python's four built-in structures — list, tuple, dict, set — as both starting material and building material.
But the map is missing one dimension: the numbers. We said the hash table looks things up "instantly" and the list "scans everything"... how do we express that precisely, so we can compare structures rigorously? That is the purpose of the next lesson: Big O notation, the universal language for talking about efficiency that we will use for the entire rest of the course.
Data Structures Course
Module 1: Introduction to Data Structures
- What Are Data Structures?
- The Importance of Data Structures in Programming
- Types of Data Structures
- Algorithmic Complexity and Big O Notation
- Arrays and Memory: the Foundation of Data Structures
Module 2: Lists
Module 3: Stacks
- Introduction to Stacks
- Basic Stack Operations
- Stack Implementation
- Stack Applications
- Stack Exercises
Module 4: Queues
- Introduction to Queues
- Basic Queue Operations
- Circular Queues
- Priority Queues
- Double-Ended Queues (Deques)
- Queue Exercises
Module 5: Hash Tables and Dictionaries
- Introduction to Hash Tables
- Hash Functions and Collision Resolution
- Dictionaries and Sets in Practice
- Hash Table Exercises
Module 6: Trees
- Introduction to Trees
- Binary Trees
- Tree Traversals
- Binary Search Trees
- AVL Trees
- B-Trees
- Heaps
- Tree Exercises
Module 7: Graphs
- Introduction to Graphs
- Graph Representation
- Graph Search Algorithms
- Shortest Path Algorithms
- Minimum Spanning Trees
- Graph Applications
- Graph Exercises
