1. Sorting Algorithms Definition: Arrange data in a specific order (ascending/descending). Fundamental for efficient searching and analysis. Time Complexity: Common algorithms differ in time complexity, comparisons, and stability. Bubble Sort Mechanism: Repeatedly compares adjacent elements and swaps them if they are in the wrong order. Pseudocode: for i in range(n): for j in range(n-i-1): if a[j] > a[j+1]: swap(a[j], a[j+1]) Time Complexity: $O(n^2)$ Selection Sort Mechanism: Selects the smallest element and places it at the correct position. Pseudocode: for i in range(n): min_idx = i for j in range(i+1, n): if a[j] Time Complexity: $O(n^2)$ Insertion Sort Mechanism: Builds the sorted list one element at a time by inserting elements into their correct position. Time Complexity: $O(n^2)$ Merge Sort (Divide and Conquer) Mechanism: Divides list into halves, recursively sorts each half, then merges the sorted halves. Efficient and stable. Steps: Divide the list into two halves. Sort both halves recursively. Merge the sorted halves. Time Complexity: $O(n \log n)$ Quick Sort (Divide and Conquer) Mechanism: Selects a pivot, partitions list (smaller elements before pivot, larger after), then recursively sorts partitions. Steps: Choose a pivot. Partition the list into elements $<$ pivot and $>$ pivot. Recursively apply quicksort to the partitions. Time Complexity: Average: $O(n \log n)$ Worst: $O(n^2)$ (when pivot is poorly chosen) Sorting Algorithms Summary Table Algorithm Type Best Worst Notes Bubble Sort Comparison $O(n)$ $O(n^2)$ Simple but slow Selection Sort Comparison $O(n^2)$ $O(n^2)$ Minimum swaps Insertion Sort Comparison $O(n)$ $O(n^2)$ Good for nearly sorted data Merge Sort D&C $O(n \log n)$ $O(n \log n)$ Stable Quick Sort D&C $O(n \log n)$ $O(n^2)$ Fastest in practice 2. Expression Evaluation & Operator Precedence Operator Precedence: Predefined order determining sequence of computation in an expression. Associativity Rules: (left-to-right or right-to-left) decide order when operators share same precedence. Purpose: Ensures correct and predictable computation. E.g., multiplication/division before addition/subtraction. Override: Parentheses () can override default precedence. Python Operator Precedence (High $\rightarrow$ Low) Parentheses: () Exponential: ** Unary operators: +, -, ~ Multiplicative: *, /, //, % Additive: +, - Relational: <, <=, >, >= Equality: ==, != Logical AND: and Logical OR: or Example x = 10 + 2 * 3 # Multiplication happens first → 10 + 6 = 16 Understanding operator precedence helps avoid errors and ensures expressions are interpreted correctly. 3. Floating-point Representation (IEEE-754) Standard: Python uses IEEE-754 for floating-point numbers, stored in binary scientific notation : $\pm \text{mantissa} \times 2^{\text{exponent}}$. Rounding Errors: Binary cannot exactly represent many decimal values, leading to approximations and rounding errors. Format: Typically 64-bit double-precision (1 sign bit, 11 exponent bits, 52 fraction/mantissa bits). Exponent Bias: Uses a bias of 1023 to store both positive and negative exponents. Precision: Supports a wide range of values, approximately 15-17 significant decimal digits. Why Rounding Errors Occur Binary cannot exactly represent most decimal fractions (e.g., 0.1 is a repeating binary value). Example: 0.1 + 0.2 may result in 0.30000000000000004 . Example (demonstration) print(0.1 + 0.2) # Output: 0.30000000000000004 Understanding floating-point representation is crucial for accurate numerical programs and preventing precision-related bugs. 4. Operator Overloading (__add__, __str__, etc.) Definition: Allows Python operators (e.g., + , - , * , == ) to behave differently for user-defined objects. Mechanism: Achieved by defining special methods (magic or dunder methods) inside classes. Benefit: Improves readability and makes custom classes behave like built-in types. Examples: __add__() : Overloads + operator. __str__() : Controls string representation (e.g., for print() ). __eq__() : Overloads == operator. Common Use: Classes representing mathematical objects (vectors, matrices), complex numbers, dates. Example class Point: def __init__(self, x, y): self.x = x self.y = y def __add__(self, other): # overload + return Point(self.x + other.x, self.y + other.y) def __str__(self): # overload print() return f"({self.x}, {self.y})" p1 = Point(1, 2) p2 = Point(3, 4) print(p1 + p2) # Output: (4, 6) Operator overloading helps build intuitive and user-friendly object behavior. 5. File Pointer Manipulation (seek(), tell(), file positions) File Pointer: Internal pointer indicating current position for next read/write operation. Control: Moves automatically but can be controlled manually using seek() and inspected with tell() . Importance: Essential for random access to file contents. tell() – Get Current Position Method: tell() returns the current byte offset of the file pointer from the beginning of the file. Example: f = open("data.txt", "r") print(f.tell()) # position starts at 0 seek() – Change File Pointer Position Method: seek(offset, whence) changes the current file position. `whence` values: 0: From beginning (default) 1: From current pointer position 2: From end of file Example: f.seek(10, 0) # move to byte 10 from start f.seek(0, 2) # move to end of file Uses of File Pointer Control Random access reading Skipping unwanted parts Re-reading file sections Appending or modifying specific parts File pointer manipulation provides fine control over file navigation, used in text processing, log analysis, and binary file operations. 6. Figures vs Subplots (Matplotlib) Feature Figure Subplot (Axes) Definition Top-level container holding all plot elements (axes, titles, legends, graphics). Individual plotting area inside a figure where a single chart or graph is drawn. Purpose Acts as the canvas or window where one or more subplots are arranged. Used to display an actual plot (e.g., line, bar, scatter chart). Contains One or more Axes (subplots), plus decorations like suptitle. Plot area, x/y labels, ticks, grid, legend, and actual plotted data. Creation plt.figure() plt.subplot() or plt.subplots() How many? Only one figure is shown at a time (unless explicitly created). Multiple subplots can exist inside a single figure. Analogy A blank sheet of paper. Different boxes drawn on the sheet, each holding a separate chart. Example import matplotlib.pyplot as plt fig, axes = plt.subplots(1, 2) # 1 Figure, 2 Subplots axes[0].plot([1,2,3], [1,4,9]) axes[1].plot([1,2,3], [3,2,1]) plt.show() The figure serves as the overall container, while each subplot represents an independent graph within that figure. 7. Tkinter (GUI Programming) Definition: Python's standard GUI library for creating window-based applications. Widgets: Pre-built components like buttons, labels, textboxes, menus, frames. Layout Managers: Widgets placed using pack() , grid() , or place() . Common Tkinter Widgets Label: Displays text or images. Button: Executes a function when clicked. Entry: Single-line textbox for user input. Text: Multi-line text area. Radiobutton: Allows selecting one option from a set. Checkbutton: Toggle between ON/OFF states. Frame: Container widget for grouping other widgets. Listbox: Displays a list of selectable items. Canvas: Used for drawing shapes and images. Radio Button Example Purpose: Allows user to choose exactly one option from a group. Mechanism: Each radiobutton is associated with a shared variable that stores the selected value. Example import tkinter as tk root = tk.Tk() root.title("Radio Button Example") choice = tk.StringVar() tk.Radiobutton(root, text="Option A", variable=choice, value="A").pack() tk.Radiobutton(root, text="Option B", variable=choice, value="B").pack() tk.Radiobutton(root, text="Option C", variable=choice, value="C").pack() root.mainloop() When user selects an option, the variable choice stores the corresponding value. Provides simple, intuitive interface for single-choice inputs. GUI Program with Textbox, OK & Quit buttons Components: Input fields (Entry widget), OK button (performs action), Quit button (exits application). Example GUI Program import tkinter as tk def show_text(): entered = entry.get() print("You typed:", entered) root = tk.Tk() root.title("Simple GUI") entry = tk.Entry(root, width=25) entry.pack(pady=5) ok_btn = tk.Button(root, text="OK", command=show_text) ok_btn.pack(pady=5) quit_btn = tk.Button(root, text="Quit", command=root.quit) quit_btn.pack(pady=5) root.mainloop() Program accepts user input from textbox, displays it on console when OK is clicked. Quit button closes window. 8. OSI Layer Explanation (7-layer model, functions, examples) Definition: Conceptual framework for understanding and standardizing network communication. Divisions: Divides network communication into seven distinct layers , each with specific tasks. Purpose: Helps understand data movement between devices over a network. 7 Layers of the OSI Model Physical Layer: Deals with hardware transmission (cables, signals, voltage levels, bit streams). Data Link Layer: Handles framing, MAC addresses, error detection, reliable transfer over a single link. Network Layer: Manages logical addressing and routing (IP addresses). Responsible for packet forwarding. Transport Layer: Provides end-to-end communication, reliability, segmentation, flow control. Protocols: TCP, UDP. Session Layer: Establishes, manages, and terminates sessions between applications. Presentation Layer: Translates, encrypts, compresses data. Ensures sender and receiver interpret data identically. Application Layer: Closest to the user. Provides services like email, file transfer, web browsing (HTTP, FTP, SMTP). OSI model is widely used for teaching and understanding network architecture by breaking complex communication processes into manageable layers. 9. Binary Search Algorithm Definition: Efficient searching algorithm for finding an element in a sorted list or array. Mechanism: Repeatedly divides the search interval in half. Compares target with middle element, eliminating half of the search space. Advantage: Much faster than linear search. Algorithm Steps Start with two pointers: low at beginning, high at end of sorted list. Find the mid index: mid = (low + high) // 2 . If arr[mid] equals target, search is successful. If target is smaller, search left half by setting high = mid - 1 . If target is larger, search right half by setting low = mid + 1 . Repeat until low > high . If not found, return failure. Example (Pseudocode) low = 0 high = n - 1 while low Binary search has a time complexity of $O(\log n)$, making it ideal for large, pre-sorted datasets.