Suggest an editImprove this articleRefine the answer for “What types of algorithms exist by structure?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)- 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.Shown above the full answer for quick recall.Answer (EN)Image## 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 | Type | Key idea | JS constructs | Where used | |---|---|---|---| | Linear | A sequence of steps | Sequential expressions | Formatting, aggregation | | Branching | Choosing a branch by condition | if/else, switch, ?: | Validation, routing | | Iterative | Repeating until a condition/over a range | for, while, do...while, for...of | Iterating collections, search, aggregation | | Recursive | Self-application to subproblems | Functions that call themselves | Trees, graphs, divide and conquer | | Combined | Mixing structures | A combination of the above | Real-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.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.