Control Flow

if/else decisions, for and while loops, and the logic operators that combine them — the patterns behind every program ever written.

programmingconditionalsloopslogic

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
# Python
temperature = 31
if temperature > 35:
    print("Heat warning")
elif temperature > 25:
    print("Warm day")        # ← this runs (31 > 25)
else:
    print("Pleasant")
Java
// 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++
// 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 > 35 before > 25, or the heat warning becomes unreachable.)
  • else is 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:

MeaningPythonJava / C++True when
bothand&&both sides true
eitheror||at least one true
flipnot!the operand is false
Python
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:

Python
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
# 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
// 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++
// 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.

Python
# 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++).
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
# 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

Python
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:

Python
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.

Python
# 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 while whose condition never becomes false (classically: forgetting the i += 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's i <= 5 vs i < 5 are 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.

Think it through: Find the largest number in a listBeginner — accumulator + condition0/5 stages

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. 1

    Restate & edges

    What am I tracking, and which input quietly breaks a naive version?

  2. 2

    The accumulator shape

    What's the loop body — and the one decision that fixes the negatives bug?

    unlocks after the stage above
  3. 3

    Handle the empty case first

    Before the loop, what about an empty list?

    unlocks after the stage above
  4. 4

    Code it

    Guard, seed from the first element, loop the rest, compare-and-update.

    unlocks after the stage above
  5. 5

    Trace & cost

    Cost, and trace the all-negatives case?

    unlocks after the stage above

Check yourself

Check yourself0/4 answered

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

  1. Print the multiplication table of 7, formatted 7 x 3 = 21.
  2. Loop through [12, -4, 9, -1, 0, 7] and count negatives, then also track the largest value. (Two accumulators, one loop.)
  3. Classic: print this with nested loops:
    *
    **
    ***
    ****
    

Intermediate

  1. FizzBuzz from memory, in two languages, without looking up.
  2. Guess-the-number: pick a random 1–100, loop reading guesses, print higher/lower, count attempts. (Touches while, if/elif, break.)
  3. Take a paragraph string and count how many words have more than 5 letters.

Advanced

  1. Without running it, determine exactly how many times print executes; then verify:
    Python
    for i in range(1, 11):
        for j in range(i, 11):
            print(i, j)
    
  2. 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.