Programming
How Do You Actually Tell Computers What to Do?
You 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.
Data Types and Their Operations
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.
Primitive Data Types
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().
Selection: Making Decisions
Definition: Selection structures allow programs to execute different code based on conditions.
IF Statements
Basic syntax: if condition: # execute this code if condition is True
Example: age = 18; if age >= 18: print("You can vote")
IF-ELSE
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")
IF-ELIF-ELSE
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
Nested Selection
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)
Iteration: Repeating Actions
Definition: Iteration structures execute code repeatedly, either a fixed number of times or until a condition is met.
FOR Loops
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
WHILE Loops
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")
Loop Control
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)
Nested Loops
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}")
Functions
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.
Defining Functions
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 and Arguments
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
Return Values
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
Scope
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
Static and Dynamic Data Structures
Static Structures
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
Dynamic Structures
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
Arrays and Lists
Arrays
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
Multi-Dimensional Arrays
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)
Stacks
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
Queues
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
Big O Notation
Definition: Big O notation describes the performance of an algorithm by expressing how runtime or space requirements grow as input size increases.
Why It Matters
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
Common Big O Classifications
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.
Sorting Algorithms
Bubble Sort
Idea: Repeatedly swap adjacent elements if they're in wrong order.
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
Selection Sort
Idea: Find minimum element, swap with first position. Repeat for remaining elements.
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)
Insertion Sort
Idea: Build sorted array one element at a time by inserting each element in correct position. Like sorting playing cards in your hand.
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
Merge Sort
Idea: Divide array in half, recursively sort each half, merge sorted halves.
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
Quick Sort
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
Recursion
Definition: Recursion is a programming technique where a function calls itself to solve smaller instances of the same problem.
Recursive Structure
Must have: Base case: Condition where recursion stops; Recursive case: Function calls itself with simpler input
Without base case: Infinite recursion (stack overflow)
Example: Factorial
Definition: n! = n × (n-1) × (n-2) × ... × 1
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
Example: Fibonacci
Definition: fib(n) = fib(n-1) + fib(n-2)
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.
When to Use Recursion
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)
File Processing
Definition: File processing involves reading from and writing to files to persist data beyond program execution.
Reading Files
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
Writing Files
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")
File Modes
"r": Read (default), "w": Write (overwrites), "a": Append (adds to end), "r+": Read and write, "b": Binary mode (e.g., "rb" for reading binary)
Processing CSV Files
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}")
Putting It All Together
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.