1 Computational Thinking and Problem Solving

A structured guide to computational thinking, algorithm design, programming, testing, and refinement, with examples showing how complex problems become precise computational solutions.

The Computational Problem-Solving Perspective

Computer science studies computation: how information can be represented, processed, stored, communicated, and used to solve problems. It includes algorithms, languages, data structures, computer systems, artificial intelligence, networks, and interactions between people and technology.

A computational solution has three connected parts:

  • A problem: a clearly stated task or question.

  • A : a useful description of the input, relevant information, and desired output.

  • A process: a precise method, or , that transforms the input into the output.

For example, finding the shortest route between two locations becomes a computational problem when locations, roads, distances, and rules are represented as data and a method is designed to calculate a route.

The goal is not merely to operate a computer or write code. Computational problem solving asks which problems can be solved computationally, how solutions can be designed, and how efficiently and reliably they work.

Takeaway: A computational solution connects a clearly defined problem to a suitable and a precise process.

Core Skills of Computational Thinking

Computational thinking is a systematic way to approach problems so that a person—or a computer following instructions—can solve them. It is useful even when no computer is involved: planning a journey, organizing books, testing a hypothesis, or distributing tasks can all require computational thinking.

The main skills reinforce one another:

  • focuses attention on important information and hides unnecessary detail.

  • divides a complex task into manageable parts.

  • identifies similarities, repetitions, trends, and relationships.

  • develops a precise sequence of operations.

  • Evaluation and refinement test a solution, reveal weaknesses, and improve it.

For example, may divide a large task into repeated subproblems. can then reveal that those subproblems share a structure. can hide irrelevant details, making an easier to design and reuse.

Takeaway: Computational thinking is a connected set of habits for understanding structure, representing information, designing procedures, and improving solutions.

Modeling with

simplifies a complicated system by preserving details relevant to a particular purpose and hiding details that are not needed. A subway map, for example, may show stations, connections, and line changes while omitting buildings, trees, and exact street distances.

appears at several levels of computing:

  • A file icon represents a more complicated collection of data and operations.

  • A function hides its internal steps behind a meaningful name.

  • A data type describes permitted operations without requiring users to know how values are stored internally.

  • A language allows operations to be described without specifying every machine-level action.

Consider a weather application. To display a forecast, a useful model may contain only a location, current temperature, weather condition, and forecast time. The model does not need to include every satellite, sensor, network, database, and forecasting calculation involved in producing that information.

The correct depends on the purpose. A pilot, meteorologist, and traveler may need different representations of the same weather system.

Takeaway: A good is not simply a smaller description; it is a purposefully selected description that keeps what the task requires.

Breaking Problems into Manageable Parts

divides a complex problem into smaller subproblems that can be designed and tested separately. It turns a vague goal into specific responsibilities.

For a library checkout system, the broad task can be divided into these steps:

  1. Identify a book.

  2. Identify a borrower.

  3. Check whether the book is available.

  4. Record the checkout date.

  5. Calculate the due date.

  6. Update the book's availability.

  7. Display a confirmation.

A separately organized part of a system is a module. Modular design makes parts easier to understand, errors easier to locate, and components easier to reuse. It also allows different people to work on separate components and reduces the chance that a change in one component will damage unrelated components.

should be sensible. One enormous component is difficult to test and maintain, but an excessive number of tiny components can make the overall design difficult to follow.

Takeaway: Divide a problem according to meaningful responsibilities, then give each part a clear purpose and a way to be tested independently.

Finding Reusable Patterns

identifies repeated structures and relationships. It can reduce work because a known method may be adapted instead of designing a completely new solution.

For example, calculating the total price of products, total score of test answers, and total distance of road segments share the same structure:

  1. Start with a total of zero.

  2. Examine each value.

  3. Add the value to the total.

  4. Return the total.

The general structure can be reused with different data. Other examples include recognizing that a list is already sorted, finding duplicate customer records, noticing that a program repeats the same calculation for every item, or identifying a trend in temperature measurements.

must be applied carefully. Two problems may look similar while having different constraints or required outputs. A pattern is useful only when it represents a meaningful relationship in the problem.

Takeaway: Look for reusable structure, but verify that the same relationship and requirements truly apply.

Designing and Comparing Algorithms

turns a problem description into an ordered method. An should have several properties:

  • Correctness: it produces the required result for valid inputs.

  • Clarity: each step is precise and understandable.

  • Finiteness: it eventually stops.

  • Generality: it works for a relevant range of inputs rather than one example.

  • Efficiency: it uses reasonable amounts of time and memory.

To find the largest value in a list, an can first handle the empty-list case, set a current largest value to the first item, compare each remaining item with it, replace the current largest value when a larger item is found, and return the final value. The procedure maintains an invariant: after each comparison, the stored value is the greatest value examined so far.

Different algorithms can solve the same problem with different efficiency. A search through an unsorted list may examine items one at a time. When a list is sorted, binary search can repeatedly discard half of the remaining items. Both methods can find an item, but their work grows differently as the list becomes larger.

When designing an , ask:

  • What information is available?

  • What result is required?

  • What assumptions are being made?

  • Will the method work for all relevant inputs?

  • How much time and memory will it use?

  • What happens for unusual or invalid cases?

Takeaway: A correct procedure is necessary, but a strong is also clear, finite, general, and appropriately efficient.

From a Problem Statement to a Solution

A disciplined process helps transform a vague goal into a tested solution.

  1. Define the problem. State precisely what must be solved, the required output, and the conditions that must be satisfied. “Make the schedule better” is vague; assigning every class to a room and time without conflicting room or teacher assignments is more precise.

  2. Identify inputs and outputs. Determine what information the solution receives and what result it must produce. For temperature conversion, the input is a Celsius temperature and the output is the equivalent Fahrenheit temperature. The conversion rule is Fahrenheit=Celsius×95+32Fahrenheit = Celsius \times \frac{9}{5} + 32.

  3. Choose a . Model the information in a form that exposes the relationships needed by the . A map may be represented as a graph, a collection of students as records, and an image as a grid of pixel values.

  4. Decompose the problem. Separate the task into subproblems with clear responsibilities.

  5. Recognize patterns and abstractions. Reuse established structures and hide details that do not affect the result.

  6. Design the . Express the logic in pseudocode, a flowchart, or another suitable notation before focusing on -language syntax.

  7. Test and refine. Use normal cases, boundary cases, and invalid cases. Trace the method manually or execute it with carefully selected data, then revise the , , or if necessary.

Takeaway: Good solutions emerge through an iterative process rather than from writing code immediately.

Implementing, Testing, and Refining Solutions

expresses an in a formal language that a computer can execute. It is an implementation step within problem solving, not a replacement for defining the problem or designing the method.

Common constructs correspond to algorithmic ideas:

  • Variables store values that may change.

  • Data types describe kinds of values and permitted operations.

  • Expressions calculate values.

  • Conditional statements select actions based on conditions.

  • Loops repeat actions.

  • Functions or procedures package reusable operations.

  • Data structures organize related values.

For example, a reusable temperature-conversion function can hide the calculation so that other parts of a program can call it without repeating its internal steps. This is an application of and modular design.

Programs serve two purposes: they give a computer executable instructions and communicate the solution to other programmers. Readable names, consistent formatting, helpful comments, modular organization, and tests make programs easier to verify and maintain.

A program can fail in different ways:

  • A syntax error violates the rules of the language.

  • A runtime error occurs while the program is executing.

  • A logic error allows execution to continue but produces an incorrect result.

investigates these failures through hypotheses, evidence, execution traces, assumption checks, and revisions to the or code.

Takeaway: implements and communicates an ; testing and determine whether the implementation actually satisfies the problem requirements.

An Integrated Example

Consider a certificate rule: a student qualifies when the average of three scores is at least 7070 and no individual score is below 5050.

The solution can be developed systematically:

  1. Define and represent: input three numerical scores; output either qualified or not qualified; retain the two conditions.

  2. Decompose: read the scores, check the minimum-score condition, calculate the average, check the average condition, and report the result.

  3. Recognize a pattern: checking whether every score meets a threshold is a repeated comparison over a collection.

  4. Apply : the program needs only the scores and qualification rules, not a complete model of the student or school.

  5. Design the decision procedure: if any score is below 5050, report not qualified; otherwise, if the average is at least 7070, report qualified; otherwise, report not qualified.

  6. Test: include scores well above both requirements, an average below 7070, a score below 5050 despite a high average, scores exactly on the boundaries, and missing or nonnumeric input.

This example shows how definition, , , , , design, , and testing work together. A solution is not complete merely because it works on one ordinary example; it must also address boundaries, invalid cases, and the stated requirements.

Final takeaway: Effective computational problem solving combines conceptual modeling with precise procedures and evidence-based refinement.