Computer Science with Applications - Condensed Study Guide
Computer Science with Applications - Condensed Study Guide
Guide
1. Getting Started
1.1 Computational Thinking
Core Principles:
Problem Decomposition: Break large problems into smaller, manageable pieces
Pattern Recognition: Identify similarities and recurring themes
Abstraction: Focus on essential features while hiding unnecessary details
Algorithm Design: Create step-by-step solutions
Example: Planning a dinner party
Decomposition: Guest list, menu planning, shopping, cooking, setup
Pattern recognition: Similar tasks for different courses
Abstraction: Focus on "prepare food" rather than every cooking detail
Algorithm: Specific sequence of tasks with timing
1.2 Programming Basics
Variables and Assignment:
python
Data Types:
Integers: Whole numbers ( 42 , -17 )
Floats: Decimal numbers ( 3.14 , -2.7 )
Strings: Text ( "Hello" , 'Python' )
Booleans: True/False values
Operators:
python
# Arithmetic
10 + 3 # 13 (addition)
10 - 3 # 7 (subtraction)
10 * 3 # 30 (multiplication)
10 / 3 # 3.333... (division)
10 // 3 # 3 (floor division)
10 % 3 # 1 (modulo - remainder)
10 ** 3 # 1000 (exponentiation)
# Comparison
x == y # Equal
x != y # Not equal
x < y # Less than
x <= y # Less than or equal
x > y # Greater than
x >= y # Greater than or equal
# Logical
True and False # False
True or False # True
not True # False
Input/Output:
python
temperature = 75
For Loops:
python
While Loops:
python
count = 0
while count < 5:
print(f"Count: {count}")
count += 1
Loop Control:
python
for i in range(10):
if i == 3:
continue # Skip rest of this iteration
if i == 7:
break # Exit the loop entirely
print(i) # Prints: 0, 1, 2, 4, 5, 6
Args:
name (str): The person's name
greeting (str): The greeting message (default: "Hello")
Returns:
str: The complete greeting
"""
return f"{greeting}, {name}!"
# Function calls
message = greet("Alice") # "Hello, Alice!"
message = greet("Bob", "Hi") # "Hi, Bob!"
message = greet(greeting="Hey", name="Charlie") # Keyword arguments
Variable Scope:
python
def example_function():
local_var = "I'm local"
print(global_var) # Can access global variables
print(local_var) # Can access local variables
example_function()
print(global_var) # Can access global variables
# print(local_var) # ERROR: local_var not accessible here
def calculate_stats(numbers):
total = sum(numbers)
count = len(numbers)
average = total / count if count > 0 else 0
return total, count, average
The Call Stack Concept: When functions call other functions, Python keeps track using a "call stack":
python
def function_a():
print("In function A")
function_b()
print("Back in function A")
def function_b():
print("In function B")
function_c()
print("Back in function B")
def function_c():
print("In function C")
function_a()
# Output:
# In function A
# In function B
# In function C
# Back in function B
# Back in function A
Args:
principal (float): Initial investment amount
rate (float): Annual interest rate (as decimal, e.g., 0.05 for 5%)
time (float): Time in years
compounds_per_year (int): Number of times interest compounds per year
Returns:
float: Final amount after compound interest
Example:
>>> calculate_compound_interest(1000, 0.05, 10, 12)
1643.6194649423633
"""
return principal * (1 + rate/compounds_per_year) ** (compounds_per_year * time)
Exception Handling:
python
# Usage
print(safe_divide(10, 2)) # 5.0
print(safe_divide(10, 0)) # Error message, returns None
print(safe_divide("10", 2)) # Error message, returns None
Advanced Exception Handling:
python
def process_file(filename):
try:
with open(filename, 'r') as file:
data = file.read()
# Process data here
return data
except FileNotFoundError:
print(f"File {filename} not found")
except PermissionError:
print(f"Permission denied to read {filename}")
except Exception as e:
print(f"Unexpected error: {e}")
finally:
print("File processing attempt completed")
2. Data Structures
2.1 Lists, Tuples, and Strings
Lists - Mutable Sequences:
python
# Creating lists
numbers = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True]
empty = []
# Accessing elements
print(numbers[0]) # 1 (first element)
print(numbers[-1]) # 5 (last element)
print(numbers[1:4]) # [2, 3, 4] (slicing)
print(numbers[:3]) # [1, 2, 3] (first 3)
print(numbers[2:]) # [3, 4, 5] (from index 2)
# Modifying lists
numbers.append(6) # Add to end: [1, 2, 3, 4, 5, 6]
numbers.insert(0, 0) # Insert at index 0: [0, 1, 2, 3, 4, 5, 6]
numbers.remove(3) # Remove first occurrence of 3
popped = numbers.pop() # Remove and return last element
popped_at_index = numbers.pop(1) # Remove and return element at index 1
# List operations
len(numbers) # Length
3 in numbers # Check membership (True/False)
numbers.count(2) # Count occurrences
numbers.index(4) # Find index of first occurrence
numbers.sort() # Sort in place
sorted_copy = sorted(numbers) # Return sorted copy
numbers.reverse() # Reverse in place
List Comprehensions:
python
# Traditional way
squares = []
for x in range(10):
squares.append(x**2)
# With condition
even_squares = [x**2 for x in range(10) if x % 2 == 0]
# To create a copy:
list3 = list1.copy() # Shallow copy
list4 = list1[:] # Another way to shallow copy
list5 = list(list1) # Another way to shallow copy
# Creating tuples
coordinates = (3, 5)
single_item = (42,) # Note the comma for single-item tuple
empty_tuple = ()
# Tuple unpacking
x, y = coordinates # x = 3, y = 5
# String methods
print(text.lower()) # "hello, world!"
print(text.upper()) # "HELLO, WORLD!"
print(text.strip()) # Remove whitespace from ends
print(text.replace("World", "Python")) # "Hello, Python!"
print(text.split(", ")) # ["Hello", "World!"]
# String formatting
name = "Alice"
age = 30
print(f"My name is {name} and I am {age} years old") # f-string (preferred)
print("My name is {} and I am {} years old".format(name, age)) # .format()
print("My name is %s and I am %d years old" % (name, age)) # % formatting (old)
# String operations
"apple" in "pineapple" # True
"hello" + " " + "world" # "hello world"
"ha" * 3 # "hahaha"
2.2 Dictionaries and Sets
Dictionaries - Key-Value Pairs:
python
# Creating dictionaries
student = {
"name": "Alice",
"age": 20,
"major": "Computer Science",
"gpa": 3.8
}
empty_dict = {}
dict_from_pairs = dict([("a", 1), ("b", 2)])
# Dictionary methods
print(student.keys()) # dict_keys(['name', 'age', 'year'])
print(student.values()) # dict_values(['Alice', 21, 'Junior'])
print(student.items()) # dict_items([('name', 'Alice'), ('age', 21), ('year', 'Jun
Dictionary Comprehensions:
python
# Square numbers
squares = {x: x**2 for x in range(1, 6)} # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# Creating sets
numbers = {1, 2, 3, 4, 5}
empty_set = set() # Note: {} creates an empty dict, not set
from_list = set([1, 2, 2, 3, 3, 4]) # {1, 2, 3, 4} - duplicates removed
# Set operations
numbers.add(6) # Add element
numbers.remove(3) # Remove element (raises error if not found)
numbers.discard(10) # Remove element (no error if not found)
class Stack:
def __init__(self):
self.items = []
def pop(self):
"""Remove and return top item"""
if self.is_empty():
raise IndexError("Stack is empty")
return self.items.pop()
def peek(self):
"""Return top item without removing it"""
if self.is_empty():
raise IndexError("Stack is empty")
return self.items[-1]
def is_empty(self):
return len(self.items) == 0
def size(self):
return len(self.items)
# Usage example
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)
print(stack.pop()) # 3
print(stack.peek()) # 2
Stack Applications:
python
def is_balanced_parentheses(expression):
"""Check if parentheses are balanced using a stack"""
stack = []
pairs = {'(': ')', '[': ']', '{': '}'}
return len(stack) == 0
print(is_balanced_parentheses("((()))")) # True
print(is_balanced_parentheses("([{}])")) # True
print(is_balanced_parentheses("((()]")) # False
class Queue:
def __init__(self):
self.items = deque()
def dequeue(self):
"""Remove and return front item"""
if self.is_empty():
raise IndexError("Queue is empty")
return self.items.popleft()
def front(self):
"""Return front item without removing it"""
if self.is_empty():
raise IndexError("Queue is empty")
return self.items[0]
def is_empty(self):
return len(self.items) == 0
def size(self):
return len(self.items)
# Usage example
queue = Queue()
queue.enqueue("first")
queue.enqueue("second")
queue.enqueue("third")
print(queue.dequeue()) # "first"
print(queue.front()) # "second"
def get_balance(self):
"""Return current balance"""
return self.balance
def __str__(self):
"""String representation of the object"""
return f"Account({self.account_holder}, ${self.balance})"
def __repr__(self):
"""Developer-friendly representation"""
return f"BankAccount('{self.account_holder}', {self.balance})"
Inheritance:
python
class SavingsAccount(BankAccount):
def __init__(self, account_holder, initial_balance=0, interest_rate=0.02):
super().__init__(account_holder, initial_balance) # Call parent constructor
self.interest_rate = interest_rate
def apply_interest(self):
"""Add interest to the account"""
interest = self.balance * self.interest_rate
self.balance += interest
self.transaction_history.append(f"Interest added: ${interest:.2f}")
# Usage
savings = SavingsAccount("Charlie", 1000, 0.05)
savings.apply_interest()
print(savings.get_balance()) # 1050.0
class Temperature:
def __init__(self, celsius=0):
self._celsius = celsius # Private variable (by convention)
@property
def celsius(self):
return self._celsius
@celsius.setter
def celsius(self, value):
if value < -273.15:
raise ValueError("Temperature cannot be below absolute zero")
self._celsius = value
@property
def fahrenheit(self):
return (self._celsius * 9/5) + 32
@fahrenheit.setter
def fahrenheit(self, value):
self.celsius = (value - 32) * 5/9
# Usage
temp = Temperature(25)
print(temp.celsius) # 25
print(temp.fahrenheit) # 77.0
temp.fahrenheit = 86
print(temp.celsius) # 30.0
def square(x):
return x ** 2
def cube(x):
return x ** 3
numbers = [1, 2, 3, 4, 5]
squared = apply_operation(numbers, square) # [1, 4, 9, 16, 25]
cubed = apply_operation(numbers, cube) # [1, 8, 27, 64, 125]
numbers = [1, 2, 3, 4, 5]
# Traditional approach
squared = []
for num in numbers:
squared.append(num ** 2)
# Using map
squared = list(map(lambda x: x**2, numbers)) # [1, 4, 9, 16, 25]
# Traditional approach
evens = []
for num in numbers:
if num % 2 == 0:
evens.append(num)
# Using filter
evens = list(filter(lambda x: x % 2 == 0, numbers)) # [2, 4, 6, 8, 10]
numbers = [1, 2, 3, 4, 5]
# Using reduce
product = reduce(lambda x, y: x * y, numbers) # 120
# Find maximum
maximum = reduce(lambda x, y: x if x > y else y, numbers) # 5
def make_multiplier(n):
"""Return a function that multiplies by n"""
def multiplier(x):
return x * n
return multiplier
double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5)) # 10
print(triple(4)) # 12
@timer_decorator
def slow_function():
import time
time.sleep(1)
return "Done!"
3.2 Recursion
Understanding Recursion: Recursion is when a function calls itself. Every recursive function needs:
1. Base case: Condition where recursion stops
2. Recursive case: Function calls itself with simpler input
Classic Example - Factorial:
python
def factorial(n):
"""Calculate n! = n × (n-1) × (n-2) × ... × 1"""
# Base case
if n <= 1:
return 1
# Recursive case
return n * factorial(n - 1)
# Trace of factorial(4):
# factorial(4) = 4 * factorial(3)
# factorial(3) = 3 * factorial(2)
# factorial(2) = 2 * factorial(1)
# factorial(1) = 1 <- base case
# Working backwards:
# factorial(2) = 2 * 1 = 2
# factorial(3) = 3 * 2 = 6
# factorial(4) = 4 * 6 = 24
print(factorial(5)) # 120
Fibonacci Sequence:
python
def fibonacci(n):
"""Return the nth Fibonacci number"""
# Base cases
if n <= 1:
return n
# Recursive case
return fibonacci(n - 1) + fibonacci(n - 2)
if n <= 1:
return n
# Recursive cases
if target < arr[mid]:
return binary_search(arr, target, left, mid - 1)
else:
return binary_search(arr, target, mid + 1, right)
# Usage
sorted_list = [1, 3, 5, 7, 9, 11, 13, 15]
index = binary_search(sorted_list, 7)