Programs are not read top-to-bottom
By default, a program runs line 1, line 2, line 3… Control flow is the
set of tools that breaks this: skip lines (decisions), repeat lines
(loops), jump elsewhere (functions — next page). Every feature of every app
reduces to these moves. A thermostat is one if. A spam filter is an if
with a fancy condition. A feed is a loop over posts.
Decisions: if / else if / else
# Python
temperature = 31
if temperature > 35:
print("Heat warning")
elif temperature > 25:
print("Warm day") # ← this runs (31 > 25)
else:
print("Pleasant")
// Java
int temperature = 31;
if (temperature > 35) {
System.out.println("Heat warning");
} else if (temperature > 25) {
System.out.println("Warm day");
} else {
System.out.println("Pleasant");
}
// C++
int temperature = 31;
if (temperature > 35) {
std::cout << "Heat warning\n";
} else if (temperature > 25) {
std::cout << "Warm day\n";
} else {
std::cout << "Pleasant\n";
}
Rules that apply in all three:
- Conditions are checked top to bottom; the first true branch runs,
the rest are skipped. (Order matters: test
> 35before> 25, or the heat warning becomes unreachable.) elseis the catch-all; it's optional.- Python marks the body by indentation; Java/C++ use
{ }braces (and indent anyway, for humans).
Conditions and logic operators
A condition is anything that evaluates to true/false — built from
comparisons (==, !=, <, <=, >, >=) and combined with
logical operators:
| Meaning | Python | Java / C++ | True when |
|---|---|---|---|
| both | and | && | both sides true |
| either | or | || | at least one true |
| flip | not | ! | the operand is false |
age = 20
has_id = True
if age >= 18 and has_id:
print("Entry allowed")
One subtlety worth knowing on day one: evaluation short-circuits. In
a and b, if a is false, b is never evaluated. This isn't trivia — it's
how real code guards against crashes:
if user is not None and user.is_admin: # safe: second check skipped if no user
Loops: doing things many times
for — when you know what you're iterating over
# Python — over a range of numbers...
for i in range(1, 6): # 1, 2, 3, 4, 5 (end is exclusive)
print(i)
# ...or directly over a collection (the more common case)
for item in ["bread", "milk", "eggs"]:
print(item)
// Java
for (int i = 1; i <= 5; i++) { // init; keep-going condition; step
System.out.println(i);
}
for (String item : new String[]{"bread", "milk", "eggs"}) {
System.out.println(item); // "for-each" form
}
// C++
for (int i = 1; i <= 5; i++) {
std::cout << i << "\n";
}
for (const std::string& item : {"bread", "milk", "eggs"}) {
std::cout << item << "\n"; // range-based for
}
Loop Conventions & Modern Syntax in DSA
When writing loops in DSA, you will frequently see specific conventions and shortcuts:
1. The Throwaway Variable (_ in Python)
In Python, if you need to repeat an action N times but do not actually use the loop counter, use a single underscore _ as the variable name. This tells other developers (and the interpreter) that the index variable is deliberately ignored.
# Create a list of size 5 filled with zeros
zeros = [0 for _ in range(5)]
# Repeat an action 3 times
for _ in range(3):
print("Hello")
2. C++ auto and Range-Based Loops
In C++, specifying container types (like std::unordered_map<std::string, std::vector<int>>::iterator) can be extremely verbose. C++ provides the auto keyword to let the compiler infer the type for you.
When iterating over collections, use the range-based for loop combined with auto and references:
for (auto x : vec): Copies each element (slow for large objects).for (auto& x : vec): Accesses each element by reference, allowing you to edit the element in place without copying.for (const auto& x : vec): Accesses by reference, but makes it read-only (highly efficient, the standard read-only iteration in C++).
std::vector<int> nums = {1, 2, 3};
// Read-only reference iteration (most efficient for viewing elements)
for (const auto& x : nums) {
std::cout << x << " ";
}
// Modify elements in place using references
for (auto& x : nums) {
x *= 2; // doubles each element in the vector
}
while — when you only know the stopping condition
# Python — keep asking until the answer is valid
answer = ""
while answer not in ("yes", "no"):
answer = input("Continue? (yes/no): ")
for = "do this N times / for each thing"; while = "keep going until
something changes." Any for can be rewritten as a while, but using the
one that matches your intent makes code readable.
break and continue
for item in inventory:
if item.damaged:
continue # skip this item, go to the next
if item.id == target:
print("found!")
break # stop the whole loop
The accumulator pattern
Half of all beginner programs are this shape — start with an empty result, fold each item in:
total = 0
for price in [250, 120, 180]:
total += price # total is the "accumulator"
print(total) # 550
Counting, summing, finding-the-max, building a list — all the same pattern. Recognize it now; in Level 3 it grows up to become dynamic programming.
Nesting, and your first taste of complexity
Control flow composes: loops inside loops, ifs inside loops.
# Every pair of students in a class (the "all pairs" shape)
for i in range(len(students)):
for j in range(i + 1, len(students)):
print(students[i], "vs", students[j])
With 30 students that inner line runs 435 times; with 1,000 students, ~500,000 times. A loop inside a loop multiplies work — for n items, roughly n × n = n² steps. This idea has a name, time complexity (written O(n²) — see the complexity cheat sheet), and it's the central obsession of Levels 2–4: most of DSA is the art of replacing an n² loop-in-loop with something smarter.
Common beginner mistakes
- The infinite loop — a
whilewhose condition never becomes false (classically: forgetting thei += 1). Your program hangs; Ctrl-C kills it. Everyone writes one this week. - Off-by-one errors — looping one time too many or too few. Know your
ends: Python's
range(1, 6)excludes 6; Java'si <= 5vsi < 5are different loops. The most common bug family in all of programming. =vs==in conditions — assignment vs comparison (last page); C++ compiles the wrong one silently.- Modifying a list while looping over it — items get skipped as the list shifts under you. Loop over a copy, or build a new list.
- Arrow code — five levels of nested ifs. Prefer guard clauses:
handle the bad cases with an early
return/continue, keep the happy path flat. (This is also a code-review comment you'll receive in your first job.)
Think it through
Most beginner programs are an accumulator loop plus a condition. Build the most common one from scratch — and meet the bug that bites everyone once. Answer each prompt before revealing.
PROBLEMReturn the largest number in a list using a single loop (no built-in max). nums = [12, -4, 9, -1, 0, 7] → 12. Now also think about [-5, -2, -9].
- 1
Restate & edges
“What am I tracking, and which input quietly breaks a naive version?”
- 2
The accumulator shape
“What's the loop body — and the one decision that fixes the negatives bug?”
unlocks after the stage above - 3
Handle the empty case first
“Before the loop, what about an empty list?”
unlocks after the stage above - 4
Code it
“Guard, seed from the first element, loop the rest, compare-and-update.”
unlocks after the stage above - 5
Trace & cost
“Cost, and trace the all-negatives case?”
unlocks after the stage above
Check yourself
1. In an if / elif / elif chain, which branch runs?
2. Why does `user is not None and user.is_admin` NOT crash when user is None?
3. In Python, `for i in range(1, 6)` prints which numbers?
4. A loop nested inside another loop, each over n items, does roughly how much work?
Interview perspective
Practice
Beginner
- Print the multiplication table of 7, formatted
7 x 3 = 21. - Loop through
[12, -4, 9, -1, 0, 7]and count negatives, then also track the largest value. (Two accumulators, one loop.) - Classic: print this with nested loops:
* ** *** ****
Intermediate
- FizzBuzz from memory, in two languages, without looking up.
- Guess-the-number: pick a random 1–100, loop reading guesses, print higher/lower, count attempts. (Touches while, if/elif, break.)
- Take a paragraph string and count how many words have more than 5 letters.
Advanced
- Without running it, determine exactly how many times
printexecutes; then verify:Pythonfor i in range(1, 11): for j in range(i, 11): print(i, j) - Refactor this into guard clauses so it nests at most one level:
Python
if user: if user.active: if user.balance > 0: process(user)
Next: Functions — naming your control flow and reusing it.