On this page:
How Do You Actually Tell Computers What to Do? Data Types and Their Operations Selection: Making Decisions Iteration: Repeating Actions Functions Static and Dynamic Data Structures Arrays and Lists Stacks Queues Big O Notation Sorting Algorithms Recursion File Processing Putting It All TogetherYou have an idea. Maybe a game. Maybe a tool that solves a problem. Maybe an app that makes life easier.
How do you make it real?
You write a program. Give the computer precise instructions. Tell it exactly what to do, step by step.
But computers are incredibly literal. They do exactly what you tell them. Not what you meant. What you actually said.
This is programming—the art and science of writing instructions computers can follow. It requires precision. Logic. Problem-solving. Creativity.
Understanding programming changes everything. You start to see the logic behind every app, every website, every software system. You recognize patterns. You build solutions from scratch.
This isn't just for computer scientists. Programming is a fundamental literacy of the digital age—useful in countless fields from science to business to art.
Let's explore how programs actually work.
Why Data Types Matter
Computers store different kinds of information differently.
A number isn't stored the same way as text. True/false isn't stored like a list.
Data types tell the computer: How to store the value, What operations are valid, How much memory to allocate.
Integers (int)
Definition: Whole numbers without decimal points, positive or negative.
Examples: -5, 0, 42, 1000
Operations: Addition: 5 + 3 = 8, Subtraction: 10 - 4 = 6, Multiplication: 6 * 7 = 42, Division (integer): 17 / 5 = 3 (truncated), Modulo (remainder): 17 % 5 = 2, Power: 2 ** 3 = 8
Use cases: Counting items, indexing arrays, IDs
Floating-Point Numbers (float)
Definition: Numbers with decimal points.
Examples: 3.14, -0.5, 2.0, 9.99
Operations: Same as integers, but keep decimals: 5.5 + 2.3 = 7.8, 10.0 / 3.0 = 3.333...
Caution: Floating-point arithmetic can be imprecise due to how computers represent decimals. 0.1 + 0.2 = 0.30000000000000004 (not exactly 0.3!)
Use cases: Scientific calculations, measurements, money (though special types are better for money)
Booleans (bool)
Definition: Values that are either True or False.
Examples: True, False
Operations: AND: True AND True = True, True AND False = False; OR: True OR False = True, False OR False = False; NOT: NOT True = False, NOT False = True
Use cases: Conditions, flags, yes/no questions
Characters and Strings (char, string)
Character: Single letter, digit, or symbol. Examples: 'a', 'Z', '5', '@'
String: Sequence of characters. Examples: "Hello", "Python", "user@email.com"
Operations: Concatenation: "Hello" + " World" = "Hello World", Repetition: "Ha" * 3 = "HaHaHa", Length: length("Hello") = 5, Indexing: "Hello"[0] = 'H', Slicing: "Hello"[1:4] = "ell"
Use cases: Text, names, messages, user input
Type Conversion
Sometimes need to convert between types:
Integer to String: str(42) = "42"
String to Integer: int("42") = 42
Float to Integer: int(3.9) = 3 (truncates)
Integer to Float: float(5) = 5.0
Be careful: int("Hello") → ERROR! Can't convert text to number; int("3.14") → ERROR! Use float() first, then int().
Definition: Selection structures allow programs to execute different code based on conditions.
Basic syntax: if condition: # execute this code if condition is True
Example: age = 18; if age >= 18: print("You can vote")
Execute one block if True, another if False: if condition: # execute if True; else: # execute if False
Example: temperature = 25; if temperature > 30: print("It's hot"); else: print("It's not hot")
Multiple conditions: if condition1: # execute if condition1 is True; elif condition2: # execute if condition1 is False but condition2 is True; elif condition3: # execute if condition1 and condition2 are False but condition3 is True; else: # execute if all conditions are False
Example: Grade classification. score = 85; if score >= 90: grade = 'A'; elif score >= 80: grade = 'B'; elif score >= 70: grade = 'C'; elif score >= 60: grade = 'D'; else: grade = 'F'; print(f"Your grade is {grade}") # Output: Your grade is B
IF statements inside IF statements: age = 20; has_license = True; if age >= 18: if has_license: print("You can drive"); else: print("You need a license"); else: print("You're too young to drive")
Comparison Operators: == (equal to), != (not equal to), > (greater than), < (less than), >= (greater than or equal to), <= (less than or equal to)
Logical Operators: AND (both conditions must be True), OR (at least one condition must be True), NOT (reverses the condition)
Definition: Iteration structures execute code repeatedly, either a fixed number of times or until a condition is met.
Execute code a specific number of times:
Range-based: for i in range(5): print(i) # Output: 0, 1, 2, 3, 4
Range with start and end: for i in range(1, 6): print(i) # Output: 1, 2, 3, 4, 5
Range with step: for i in range(0, 10, 2): print(i) # Output: 0, 2, 4, 6, 8
Iterating through collections: fruits = ["apple", "banana", "orange"]; for fruit in fruits: print(fruit) # Output: apple, banana, orange
Execute code while condition is True: while condition: # execute this code; # must eventually make condition False (or break)
Example: Count to 5: count = 1; while count <= 5: print(count); count = count + 1 # Output: 1, 2, 3, 4, 5
Example: User input validation: password = ""; while password != "secret": password = input("Enter password: "); print("Access granted")
Warning: Infinite loops run forever if condition never becomes False! # INFINITE LOOP - Don't run! while True: print("This never stops")
BREAK: Exit loop immediately. Example: for i in range(10): if i == 5: break; print(i) # Output: 0, 1, 2, 3, 4 (stops at 5)
CONTINUE: Skip rest of current iteration, start next. Example: for i in range(5): if i == 2: continue; print(i) # Output: 0, 1, 3, 4 (skips 2)
Loops inside loops: for i in range(3): for j in range(2): print(f"i={i}, j={j}")
Output: i=0,j=0; i=0,j=1; i=1,j=0; i=1,j=1; i=2,j=0; i=2,j=1
Use case: Multiplication table: for i in range(1,4): for j in range(1,4): print(f"{i} x {j} = {i*j}")
Definition: A function is a reusable block of code that performs a specific task, can accept inputs (parameters), and can return outputs.
Why Functions? Reusability: Write once, use many times; Organization: Break program into logical pieces; Abstraction: Hide complexity behind simple interface; Maintenance: Fix bugs in one place.
Basic syntax: def function_name(parameters): # function body; return result
Example: Calculate area of rectangle: def calculate_area(length, width): area = length * width; return area; result = calculate_area(5, 3); print(result) # Output: 15
Parameters: Variables in function definition; Arguments: Values passed when calling function. def greet(name, age): # name and age are parameters; message = f"Hello {name}, you are {age} years old"; return message; output = greet("Alice", 25) # "Alice" and 25 are arguments
Functions can return values: def add(a, b): return a + b; result = add(5, 3) # result = 8
Functions can return nothing (None): def print_message(text): print(text); # no return statement → returns None; result = print_message("Hello") # result is None
Functions can return multiple values: def get_min_max(numbers): minimum = min(numbers); maximum = max(numbers); return minimum, maximum; min_val, max_val = get_min_max([3, 7, 2, 9, 1]) # min_val = 1, max_val = 9
Variables defined inside functions are local: def my_function(): x = 10 # local variable; print(x); my_function() # prints 10; print(x) # ERROR! x doesn't exist outside function
Global variables accessible everywhere: x = 10 # global variable; def my_function(): print(x) # can read global; my_function() # prints 10; print(x) # prints 10
Definition: Data structures with fixed size determined at creation. Arrays (in languages like Java, C++): int[] numbers = new int[5]; // Array of 5 integers. Size is fixed - can't add more elements.
Advantages: Fast access (direct indexing), Predictable memory usage, Simple implementation
Disadvantages: Fixed size (can't grow), Wasted space if not fully used, Must know size in advance
Definition: Data structures that can grow or shrink during program execution. Lists (in Python): numbers = [] # Empty list; numbers.append(5) # [5]; numbers.append(10) # [5, 10]; numbers.append(15) # [5, 10, 15] (Can keep adding elements)
Advantages: Flexible size, No wasted space, Don't need to know size in advance
Disadvantages: Slightly slower (overhead for dynamic allocation), More complex implementation
Definition: An array is a collection of elements of the same type stored in contiguous memory locations, accessed by index.
Creating arrays: numbers = [10, 20, 30, 40, 50]; names = ["Alice", "Bob", "Carol"]
Accessing elements (0-indexed): numbers[0] # 10 (first element); numbers[2] # 30 (third element); numbers[-1] # 50 (last element)
Modifying elements: numbers[1] = 25 # numbers is now [10, 25, 30, 40, 50]
Common operations: len(numbers) # 5; append (add to end): numbers.append(60) # [10, 25, 30, 40, 50, 60]; insert at position: numbers.insert(2, 99) # [10, 25, 99, 30, 40, 50, 60]; remove by value: numbers.remove(30) # [10, 25, 99, 40, 50, 60]; remove by index: del numbers[2] # [10, 25, 40, 50, 60]; check if exists: 40 in numbers # True; 100 in numbers # False
Arrays of arrays. 2D array (matrix): matrix = [[1,2,3],[4,5,6],[7,8,9]]; Accessing elements: matrix[0][0] = 1; matrix[1][2] = 6; matrix[2][1] = 8
Use cases: Grids, game boards, tables, images (pixels)
Definition: A stack is a Last-In-First-Out (LIFO) data structure where elements are added and removed from the same end (the top). Think of: Stack of plates. Add plate on top. Remove plate from top.
Stack Operations
PUSH: Add element to top: stack = []; stack.append(10) # [10]; stack.append(20) # [10, 20]; stack.append(30) # [10, 20, 30]
POP: Remove and return top element: top = stack.pop() # top = 30, stack = [10, 20]; top = stack.pop() # top = 20, stack = [10]
PEEK: Look at top without removing: top = stack[-1] # top = 10, stack unchanged
IS_EMPTY: Check if stack is empty: len(stack) == 0 # False (has 1 element)
Stack Applications
Function calls: Computer uses stack to track function calls (main() calls function1(), function1() calls function2(), function2() completes → pop from stack, function1() completes → pop from stack, back to main())
Undo functionality: Each action pushed to stack, undo pops
Expression evaluation: Converting infix to postfix notation
Browser history: Back button pops from history stack
Definition: A queue is a First-In-First-Out (FIFO) data structure where elements are added at one end (rear) and removed from the other end (front). Think of: Line at store. First person in line is first served.
Queue Operations
ENQUEUE: Add element to rear: queue = []; queue.append(10) # [10]; queue.append(20) # [10, 20]; queue.append(30) # [10, 20, 30]
DEQUEUE: Remove and return front element: front = queue.pop(0) # front = 10, queue = [20, 30]; front = queue.pop(0) # front = 20, queue = [30]
PEEK: Look at front without removing: front = queue[0] # front = 30, queue unchanged
Queue Applications
Print queue: Documents wait to be printed in order received
Task scheduling: OS manages processes in queue
Breadth-first search: Graph traversal algorithm
Customer service: Serve customers in order of arrival
Definition: Big O notation describes the performance of an algorithm by expressing how runtime or space requirements grow as input size increases.
Different algorithms have different efficiencies. Sorting 10 items? All algorithms are fast. Sorting 1,000,000 items? Big differences!
Big O helps us: Compare algorithms, Predict performance, Choose the right approach
O(1) - Constant Time
Runtime doesn't depend on input size. Example: Array access. numbers[5] # Always takes same time, regardless of array size. Graph: Flat line.
O(log n) - Logarithmic Time
Runtime grows slowly as input size increases. Example: Binary search. 1,000 items → ~10 operations; 1,000,000 items → ~20 operations. Graph: Slowly increasing curve.
O(n) - Linear Time
Runtime grows proportionally to input size. Example: Linear search. for item in list: if item == target: return True. Worst case: Check every element. 1,000 items → 1,000 operations; 1,000,000 items → 1,000,000 operations. Graph: Straight diagonal line.
O(n log n) - Linearithmic Time
Efficient sorting algorithms. Example: Merge sort, Quick sort. 1,000 items → ~10,000 operations; 1,000,000 items → ~20,000,000 operations. Graph: Curve steeper than O(log n) but flatter than O(n²).
O(n²) - Quadratic Time
Runtime grows with square of input size. Example: Bubble sort (nested loops). for i in range(len(list)): for j in range(len(list)): # Compare elements. 1,000 items → 1,000,000 operations; 1,000,000 items → 1,000,000,000,000 operations. Graph: Steep exponential curve.
O(2ⁿ) - Exponential Time
Runtime doubles with each added input. Example: Recursive Fibonacci (naive implementation). Extremely slow for large inputs. Graph: Nearly vertical curve.
Comparing Complexity
For n = 1,000:
O(1): 1 operation
O(log n): ~10 operations
O(n): 1,000 operations
O(n log n): ~10,000 operations
O(n²): 1,000,000 operations
O(2ⁿ): More than atoms in universe!
Rule: Prefer lower complexity for large datasets.
Idea: Repeatedly swap adjacent elements if they're in wrong order.
Algorithm: def bubble_sort(arr): n = len(arr); for i in range(n): for j in range(0, n-i-1): if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j]
How it works: Pass 1: Largest element "bubbles" to end; Pass 2: Second largest bubbles to second-to-last position; Continue until sorted
Example: [5, 2, 8, 1, 9] → Pass 1: [2, 5, 1, 8, 9]; Pass 2: [2, 1, 5, 8, 9]; Pass 3: [1, 2, 5, 8, 9]
Time Complexity: O(n²), Space Complexity: O(1), When to use: Small datasets, educational purposes
Idea: Find minimum element, swap with first position. Repeat for remaining elements.
Algorithm: def selection_sort(arr): n = len(arr); for i in range(n): min_idx = i; for j in range(i+1, n): if arr[j] < arr[min_idx]: min_idx = j; arr[i], arr[min_idx] = arr[min_idx], arr[i]
Example: [29, 10, 14, 37, 13] → Find min (10), swap: [10, 29, 14, 37, 13]; Find min of rest (13), swap: [10, 13, 14, 37, 29]; Find min of rest (14), already in place; Find min of rest (29), swap: [10, 13, 14, 29, 37]
Time Complexity: O(n²), Space Complexity: O(1)
Idea: Build sorted array one element at a time by inserting each element in correct position. Like sorting playing cards in your hand.
Algorithm: def insertion_sort(arr): for i in range(1, len(arr)): key = arr[i]; j = i - 1; while j >= 0 and arr[j] > key: arr[j + 1] = arr[j]; j -= 1; arr[j + 1] = key
Time Complexity: O(n²) worst case, O(n) best case (already sorted), Space Complexity: O(1), When to use: Small datasets, nearly sorted data
Idea: Divide array in half, recursively sort each half, merge sorted halves.
Algorithm: def merge_sort(arr): if len(arr) <= 1: return arr; mid = len(arr) // 2; left = merge_sort(arr[:mid]); right = merge_sort(arr[mid:]); return merge(left, right)
def merge(left, right): result = []; i = j = 0; while i < len(left) and j < len(right): if left[i] <= right[j]: result.append(left[i]); i += 1; else: result.append(right[j]); j += 1; result.extend(left[i:]); result.extend(right[j:]); return result
Example: [38,27,43,3,9,82,10] → Divide, recursively sort, merge
Time Complexity: O(n log n), Space Complexity: O(n), When to use: Large datasets, guaranteed O(n log n) performance
Idea: Pick pivot, partition array so smaller elements on left, larger on right. Recursively sort partitions.
Time Complexity: O(n log n) average, O(n²) worst case, Space Complexity: O(log n), When to use: Large datasets, typically fastest in practice
Definition: Recursion is a programming technique where a function calls itself to solve smaller instances of the same problem.
Must have: Base case: Condition where recursion stops; Recursive case: Function calls itself with simpler input
Without base case: Infinite recursion (stack overflow)
Definition: n! = n × (n-1) × (n-2) × ... × 1
Recursive approach: def factorial(n): if n == 0 or n == 1: return 1; else: return n * factorial(n - 1)
Trace factorial(4): factorial(4) = 4 * factorial(3) = 4 * (3 * factorial(2)) = 4 * (3 * (2 * factorial(1))) = 4 * (3 * (2 * 1)) = 4 * 6 = 24
Definition: fib(n) = fib(n-1) + fib(n-2)
Recursive approach: def fibonacci(n): if n == 0: return 0; if n == 1: return 1; return fibonacci(n - 1) + fibonacci(n - 2)
fibonacci(5): fib(5)=fib(4)+fib(3)=(fib(3)+fib(2))+(fib(2)+fib(1))=...=5
Problem: Many redundant calculations! fib(2) calculated multiple times. Better: Use iterative approach or memoization.
Good for: Tree traversals, Divide and conquer algorithms, Problems with recursive structure (Fibonacci, factorials), Backtracking (solving puzzles)
Avoid when: Simple iteration works better, Deep recursion (stack overflow risk), Too many redundant calculations (unless using memoization)
Definition: File processing involves reading from and writing to files to persist data beyond program execution.
Open file: file = open("data.txt", "r") # "r" = read mode
Read entire file: content = file.read(); print(content); file.close()
Read line by line: file = open("data.txt", "r"); for line in file: print(line.strip()) # strip() removes newline; file.close()
Better: Using with statement (auto-closes file): with open("data.txt", "r") as file: content = file.read(); print(content) # File automatically closed
Write mode (overwrites file): with open("output.txt", "w") as file: file.write("Hello, World!\n"); file.write("Second line\n")
Append mode (adds to end): with open("output.txt", "a") as file: file.write("Third line\n")
"r": Read (default), "w": Write (overwrites), "a": Append (adds to end), "r+": Read and write, "b": Binary mode (e.g., "rb" for reading binary)
CSV (Comma-Separated Values): Name,Age,Grade; Alice,20,A; Bob,21,B; Carol,19,A
Reading CSV: import csv; with open("students.csv", "r") as file: reader = csv.reader(file); for row in reader: print(row) # ['Name','Age','Grade'], ['Alice','20','A'], ...
Writing CSV: import csv; data = [['Name','Age','Grade'], ['Alice',20,'A'], ['Bob',21,'B']]; with open("students.csv", "w", newline='') as file: writer = csv.writer(file); writer.writerows(data)
Error Handling
Files might not exist or permissions might fail:
try: with open("data.txt", "r") as file: content = file.read(); print(content)
except FileNotFoundError: print("File not found!")
except PermissionError: print("Permission denied!")
except Exception as e: print(f"An error occurred: {e}")
You started wondering how to tell computers what to do.
Now you understand.
Data types define how information is stored—integers, floats, booleans, strings—each with specific operations and uses.
Selection (if/elif/else) makes decisions, executing different code based on conditions.
Iteration (for/while loops) repeats actions, processing collections or executing until conditions are met.
Functions encapsulate reusable code with parameters and return values, organizing programs into logical pieces.
Arrays and lists store collections, accessed by index—static with fixed size or dynamic growing as needed.
Stacks (LIFO) and queues (FIFO) provide specialized ordering for elements.
Big O notation describes algorithm efficiency, helping choose the right approach for large datasets.
Sorting algorithms—bubble, selection, insertion, merge, quick—each with different performance characteristics.
Recursion solves problems by breaking them into smaller identical problems, requiring base cases to prevent infinite loops.
File processing reads and writes data, persisting information beyond program execution.
Every program you use—from web browsers to games to mobile apps—is built from these fundamental concepts. Variables. Decisions. Loops. Functions. Data structures. Algorithms.
Understanding programming changes how you think about software. You're no longer just a user. You can build solutions from scratch.