Problem solving in programming involves analyzing a problem, designing a solution, implementing the solution, and testing the result. It is the first step in creating a working computer program.
Clearly stating the problem helps define what inputs are required, what processing is needed, and what the expected output should be.
Program design refers to planning the logical steps (algorithm) before coding. Techniques include using flowcharts, pseudocode, and structure diagrams.
Debugging is the process of finding and fixing errors in a program.
Good documentation helps other programmers understand the code. It includes comments in the code, user manuals, and technical specifications.
A graphical representation of the program logic using standard symbols like arrows, decision blocks, and processes.
It shows different conditions and corresponding actions in a table format for clarity in decision-making processes.
An algorithm is a step-by-step set of instructions to solve a specific problem.
Algorithm to find the largest of two numbers:
1. Start
2. Input a, b
3. If a > b then
print a is largest
else
print b is largest
4. Stop
Encourages dividing a program into small, reusable modules or functions. It improves clarity and debugging.
Python is a high-level, interpreted, general-purpose programming language with a focus on readability and simplicity.
# Simple Python Program
def greet():
print("Hello, World!")
greet()
# Variable and arithmetic operation
x = 10
y = 5
print("Sum is:", x + y)
The Python interpreter reads and executes Python code line by line. It can be accessed via the command line or through an IDE like VS Code or IDLE.
Python can be used for arithmetic operations directly in the shell.
# Python as a calculator
print(5 + 3)
print(10 / 2)
print(2 ** 3)
The interactive environment where you type code and see immediate output is called the Python shell.
Python uses indentation (spaces/tabs) to define blocks of code. Incorrect indentation leads to errors.
if 5 > 2:
print("5 is greater than 2") # Correct indentation
Literals are fixed values in code, like numbers or text. Strings are enclosed in single or double quotes.
name = "Python"
age = 20
print(name, "is", age, "years old")
# Ternary operator example
a = 5
b = 10
max_val = a if a > b else b
print("Max is:", max_val)
Python files end with .py. You can write code in any text editor or IDE and run it using the Python interpreter.
name = input("Enter your name: ")
print("Hello", name)
x = 10
if x > 5:
print("x is greater than 5")
else:
print("x is 5 or less")
for i in range(5):
print(i)
# While loop
i = 0
while i < 3:
print(i)
i += 1
import sys
sys.exit() # exits the program
for i in range(5):
if i == 2:
continue
print(i)
def greet(name):
print("Hello", name)
greet("Alice")
def greet(name="Guest"):
print("Hello", name)
greet()
Exceptions can be handled using try-except blocks.
try:
x = int(input("Enter number: "))
except ValueError:
print("Invalid input!")
Execution depends on conditions using if-else.
Using if-elif-else for multiple conditions.
x = 5
if x > 10:
print("Big")
elif x == 5:
print("Medium")
else:
print("Small")
x = 5
if x > 0:
if x < 10:
print("x is between 0 and 10")
def square(n):
return n * n
print(square(4))
A function that calls itself.
def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n - 1)
print(factorial(5))
Recursion occurs when a function calls itself in order to solve a problem. Each recursive call breaks the problem into simpler sub-problems.
# Example of recursion: Factorial function
def factorial(n):
if n == 1:
return 1
else:
return n * factorial(n - 1)
print(factorial(5))
Each recursive call is placed on the call stack. As the recursion progresses, a new stack frame is created. When the function reaches the base case, it starts unwinding and returns the result.
# Factorial stack diagram representation:
# factorial(5) → factorial(4) → factorial(3) → factorial(2) → factorial(1)
# Unwinding: factorial(1) → factorial(2) → factorial(3) → factorial(4) → factorial(5)
Multiple assignment allows you to assign values to multiple variables in a single statement.
x, y, z = 10, 20, 30
print(x, y, z)
The `while` loop repeatedly executes a block of code as long as a given condition is true.
# Example of while loop
x = 0
while x < 5:
print(x)
x += 1
Tables are typically represented as lists of lists (two-dimensional arrays) in Python. These can be used to store data in rows and columns.
# Creating a 2D table (list of lists)
table = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Accessing elements
print(table[0][1]) # Output: 2
Two-dimensional tables can be useful for storing grids, matrices, or tabular data. You can access elements using two indices: one for the row and one for the column.
# Example of accessing and modifying a 2D table
matrix = [[1, 2], [3, 4]]
matrix[0][1] = 99 # Change value
print(matrix) # Output: [[1, 99], [3, 4]]
A string is a sequence of characters. It is a compound data type because it can hold multiple values (characters).
# Example of a string as a compound data type
s = "Hello"
print(s[0]) # Output: H
Strings have a length, which can be found using the built-in `len()` function.
s = "Python"
print(len(s)) # Output: 6
You can use a `for` loop to traverse a string (or any iterable).
s = "Python"
for char in s:
print(char)
Strings can be sliced to get substrings. The slicing syntax is s[start:end].
s = "Python"
print(s[1:4]) # Output: yth
Strings can be compared using relational operators.
s1 = "apple"
s2 = "banana"
print(s1 == s2) # Output: False
print(s1 < s2) # Output: True
The `find()` method returns the index of the first occurrence of a substring. If not found, it returns -1.
s = "Python programming"
index = s.find("programming")
print(index) # Output: 7
Lists are ordered collections of items in Python. They can hold different data types.
lst = [1, 2, 3, 4]
print(lst) # Output: [1, 2, 3, 4]
You can access elements by index and modify them by assigning new values.
lst[0] = 10
print(lst) # Output: [10, 2, 3, 4]
Lists can also be sliced to get sublists.
lst = [1, 2, 3, 4, 5]
print(lst[1:4]) # Output: [2, 3, 4]
lst = [1, 2, 3]
lst.append(4)
print(lst) # Output: [1, 2, 3, 4]
Looping allows us to iterate over list elements. The `for` loop is commonly used for counting elements in a list, and can also be used to iterate through the list to perform specific operations.
# Loop through a list and count the number of elements
lst = [1, 2, 3, 4, 5]
count = 0
for item in lst:
count += 1
print("Total elements:", count)
Each item in a list has an index, which can be used to access elements directly. Indexing starts at 0.
# Accessing elements in a list
lst = ['apple', 'banana', 'cherry']
print(lst[0]) # Output: apple
print(lst[1]) # Output: banana
print(lst[2]) # Output: cherry
The `len()` function returns the number of elements in a list.
# Find the length of a list
lst = ['apple', 'banana', 'cherry']
print(len(lst)) # Output: 3
The `in` operator is used to check if an element is present in a list.
# Check membership in a list
lst = ['apple', 'banana', 'cherry']
print('banana' in lst) # Output: True
print('orange' in lst) # Output: False
You can use `for` loops to iterate over a list and perform operations on each element.
# Example of looping through a list
lst = [10, 20, 30, 40]
for item in lst:
print(item * 2)
Python provides various operations to manipulate lists, such as adding, removing, or modifying elements.
# Adding elements to a list
lst = [1, 2, 3]
lst.append(4)
lst.insert(1, 10) # Insert at index 1
print(lst) # Output: [1, 10, 2, 3, 4]
# Removing elements
lst.remove(10) # Removes the first occurrence of 10
lst.pop() # Removes the last element
print(lst) # Output: [1, 2, 3]
Elements in a list can be deleted using the `del` keyword or the `remove()` method.
# Deleting elements from a list
lst = [1, 2, 3, 4]
del lst[1] # Removes element at index 1
print(lst) # Output: [1, 3, 4]
Cloning a list allows you to create a new copy of the list. You can use slicing or the `copy()` method to clone a list.
# Cloning a list
lst = [1, 2, 3]
cloned_lst = lst[:] # Slicing method
print(cloned_lst) # Output: [1, 2, 3]
# Alternatively, using the copy() method
cloned_lst = lst.copy()
print(cloned_lst) # Output: [1, 2, 3]
A nested list is a list within another list, allowing you to store more complex data structures.
# Example of a nested list (list of lists)
nested_lst = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# Accessing elements in a nested list
print(nested_lst[0][1]) # Output: 2
print(nested_lst[2][2]) # Output: 9
OOP is a programming paradigm based on the concept of objects. Objects are instances of classes, and methods are functions defined within classes.
# Creating a class and an object
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def greet(self):
print(f"Hello, my name is {self.name} and I am {self.age} years old.")
# Creating an object of the class
person1 = Person("Alice", 30)
person1.greet() # Output: Hello, my name is Alice and I am 30 years old.
Python has many built-in libraries that provide various functionalities. Some of the commonly used libraries include:
# Example using the math library
import math
print(math.sqrt(16)) # Output: 4.0
Data structures are a way of organizing and storing data efficiently. Let's look at some common data structures in Python.
Arrays are used to store multiple values in a single variable. In Python, arrays can be represented using lists, as Python does not have a dedicated array data structure.
# Creating an array using a list
arr = [1, 2, 3, 4, 5]
print(arr) # Output: [1, 2, 3, 4, 5]
Lists in Python are dynamic arrays that can store elements of different types and sizes. They can be modified after creation by adding, removing, or changing elements.
# Creating a list
lst = [10, 20, 30, 40]
print(lst) # Output: [10, 20, 30, 40]
Sets are unordered collections of unique elements. They do not allow duplicates and are useful for membership tests and mathematical operations like union and intersection.
# Creating a set
s = {1, 2, 3, 4}
print(s) # Output: {1, 2, 3, 4}
# Adding and removing elements
s.add(5)
s.remove(2)
print(s) # Output: {1, 3, 4, 5}
A stack is a collection of elements with two main operations: push (adding an element) and pop (removing an element). It follows the Last In, First Out (LIFO) principle.
# Stack operations using a list
stack = []
stack.append(1) # Push
stack.append(2) # Push
stack.append(3) # Push
print(stack) # Output: [1, 2, 3]
stack.pop() # Pop
print(stack) # Output: [1, 2]
A queue is a collection of elements that follows the First In, First Out (FIFO) principle. Elements are added at the back and removed from the front.
# Queue operations using collections.deque
from collections import deque
queue = deque()
queue.append(1) # Enqueue
queue.append(2) # Enqueue
queue.append(3) # Enqueue
print(queue) # Output: deque([1, 2, 3])
queue.popleft() # Dequeue
print(queue) # Output: deque([2, 3])
Searching algorithms are used to find a specific element in a data structure. Below are two common searching algorithms: Linear Search and Binary Search.
Linear search is a simple method that checks every element in a list until the target element is found.
# Linear Search
def linear_search(arr, target):
for i in range(len(arr)):
if arr[i] == target:
return i # Return the index of the target element
return -1 # Target not found
arr = [5, 3, 8, 4, 2]
target = 4
result = linear_search(arr, target)
print("Element found at index:", result) # Output: Element found at index: 3
Binary search works on sorted arrays. It repeatedly divides the search interval in half. If the target value is less than the middle element, the search continues on the left half, otherwise, it searches the right half.
# Binary Search
def binary_search(arr, target):
low = 0
high = len(arr) - 1
while low <= high:
mid = (low + high) // 2
if arr[mid] == target:
return mid # Target found
elif arr[mid] < target:
low = mid + 1 # Search right half
else:
high = mid - 1 # Search left half
return -1 # Target not found
arr = [1, 2, 3, 4, 5, 6, 7, 8]
target = 4
result = binary_search(arr, target)
print("Element found at index:", result) # Output: Element found at index: 3
Sorting algorithms are used to arrange elements in a specific order, either ascending or descending. Below are three common sorting algorithms: Bubble Sort, Selection Sort, and Insertion Sort.
Bubble sort works by repeatedly stepping through the list, comparing adjacent elements, and swapping them if they are in the wrong order. This process repeats until the list is sorted.
# Bubble Sort
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] # Swap
return arr
arr = [64, 34, 25, 12, 22, 11, 90]
sorted_arr = bubble_sort(arr)
print("Sorted array:", sorted_arr) # Output: Sorted array: [11, 12, 22, 25, 34, 64, 90]
Selection sort works by repeatedly finding the minimum element from the unsorted part of the list and swapping it with the first unsorted element.
# Selection Sort
def selection_sort(arr):
for i in range(len(arr)):
min_idx = i
for j in range(i+1, len(arr)):
if arr[j] < arr[min_idx]:
min_idx = j
arr[i], arr[min_idx] = arr[min_idx], arr[i] # Swap
return arr
arr = [64, 34, 25, 12, 22, 11, 90]
sorted_arr = selection_sort(arr)
print("Sorted array:", sorted_arr) # Output: Sorted array: [11, 12, 22, 25, 34, 64, 90]
Insertion sort works by taking each element and inserting it into the correct position in the sorted part of the list.
# Insertion Sort
def insertion_sort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i-1
while j >= 0 and key < arr[j]:
arr[j+1] = arr[j]
j -= 1
arr[j+1] = key
return arr
arr = [64, 34, 25, 12, 22, 11, 90]
sorted_arr = insertion_sort(arr)
print("Sorted array:", sorted_arr) # Output: Sorted array: [11, 12, 22, 25, 34, 64, 90]