Skip to main content

What types of algorithms exist by structure?

Short answer

  • Linear (sequential) - steps execute strictly one after another.
  • Branching - one of the execution branches is chosen based on a condition.
  • Iterative (looping) - a block of actions repeats while a condition holds or over a given range.
  • Recursive - the algorithm calls itself until a base case is reached (more often viewed as an organizational technique, but singled out separately).
  • Combined - combine the listed control structures within a single solution.

In detail

Structured programming distinguishes three basic control structures: sequence, branching, and loops. Recursion is a key technique that is often considered separately. Real-world algorithms usually combine several structures.

1) Linear (sequential)

Execute step by step, without branching or repetition. Applicable when the order of actions is fixed and does not depend on conditions.

  • Advantages: simplicity, predictability, easy verifiability.
  • When to use: formatting data, computing aggregates, preparing values before validation.
  • Typical mistakes: extra steps, duplicated code, missing handling of edge cases.
javascript
function normalizeName(name) { return name.trim().toLowerCase().replace(/\s+/g, ' '); } function avg(nums) { if (!nums.length) return 0; let sum = 0; for (const n of nums) sum += n; return sum / nums.length; } const raw = " Alice Bob "; const normalized = normalizeName(raw); const mean = avg([10, 20, 30]); console.log({ normalized, mean: mean.toFixed(2) });

2) Branching

Choosing one of the alternatives based on a condition. Main constructs: if/else, switch/case, the ternary operator.

  • if / else - a universal choice based on conditions.
  • switch - convenient for discrete values.
  • The ternary ? : - for simple conditional assignments.
javascript
function grade(score) { if (score < 0 || score > 100) return "invalid"; // guard case if (score >= 90) return "A"; if (score >= 75) return "B"; if (score >= 60) return "C"; if (score >= 40) return "D"; return "F"; } console.log([95, 76, 12, 101].map(grade));
  1. Watch for completeness of conditions (handle edge cases).
  2. Order checks from more strict to less strict (or the other way, but consistently).
  3. Avoid if-else "staircases" when a lookup table/map can replace them.

3) Iterative (looping)

Executing a block of code multiple times. Kinds: for, while, do...while, as well as iterable forms (for...of) and higher-order methods (forEach, map) - they logically implement repetition too.

  • for - a known number of iterations or iterating over a collection.
  • while - while a condition is true; do...while - at least one iteration.
  • break/continue - controlling the flow inside a loop.
javascript
function sumUntilLimit(arr, limit) { let sum = 0; for (const n of arr) { if (sum + n > limit) break; // early exit sum += n; } return sum; } console.log(sumUntilLimit([5, 3, 8, 2], 10)); // 8
  1. Define an invariant - what remains true on every iteration.
  2. Watch how counters/conditions change to avoid infinite loops.
  3. Use early exits (break/return) to avoid unnecessary iterations.

Recursive algorithms

Recursion is a way of solving problems by breaking them into subproblems of the same type with a base case. It is especially convenient for trees, graphs, and divide-and-conquer splits.

javascript
const tree = { value: 1, children: [ { value: 2, children: [] }, { value: 3, children: [ { value: 4, children: [] } ] } ] }; function dfs(node, visit) { if (!node) return; // base case visit(node.value); for (const child of node.children || []) { dfs(child, visit); // recursive step } } dfs(tree, v => console.log(v)); // 1, 2, 3, 4
  • Be sure to define a base case and progress toward it, otherwise you get a stack overflow.
  • Tail recursion can be optimized by a compiler/engine, but not everywhere (in JS - there is no guarantee).
  • An iterative version using an explicit stack/queue often saves the call stack and gives better control over memory.
javascript
function dfsIter(root, visit) { if (!root) return; const stack = [root]; while (stack.length) { const node = stack.pop(); visit(node.value); const children = node.children || []; for (let i = children.length - 1; i >= 0; i--) { stack.push(children[i]); } } } dfsIter(tree, v => console.log(v)); // 1, 2, 3, 4

Combined algorithms

In practice, algorithms usually combine sequential steps, branching, and loops. Example: form validation - a linear pass over the fields (a loop) with rule checks (branching) and preprocessing (a sequence).

javascript
function validateForm(fields) { const errors = []; for (const f of fields) { // loop const value = String(f.value ?? "").trim(); // linear preprocessing if (f.required && value === "") { // branching errors.push(`${f.name}: required`); continue; } if (f.type === "email") { const ok = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value); if (!ok) errors.push(`${f.name}: invalid email`); } else if (f.type === "age") { const age = Number(value); if (!Number.isInteger(age) || age < 0 || age > 120) { errors.push(`${f.name}: invalid age`); } } } return errors; } console.log( validateForm([ { name: "email", type: "email", required: true, value: " user@example.com " }, { name: "age", type: "age", required: false, value: "200" } ]) );

Quick summary table

TypeKey ideaJS constructsWhere used
LinearA sequence of stepsSequential expressionsFormatting, aggregation
BranchingChoosing a branch by conditionif/else, switch, ?:Validation, routing
IterativeRepeating until a condition/over a rangefor, while, do...while, for...ofIterating collections, search, aggregation
RecursiveSelf-application to subproblemsFunctions that call themselvesTrees, graphs, divide and conquer
CombinedMixing structuresA combination of the aboveReal-world applications and services

What you might be asked in an interview

  • Give examples of a linear, a branching, and a looping algorithm, and their time/memory complexity.
  • When is recursion preferable to iteration, and vice versa? How to rewrite recursive code iteratively.
  • Draw a flowchart of an algorithm with branching and loops for a given problem.
  • Where would you add early exits (guard clauses), and why does that simplify the code.

Tip: before writing code, sketch pseudocode, note the base cases and invariants - this reduces the number of mistakes.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.