12. Sorting and Searching
Higher Secondary · Computer Science · Science Stream

Sorting and Searching

Sorting arranges data in a specific order — ascending or descending — so it becomes easier to access, interpret and process. Searching locates a given element within a collection of data. This chapter covers two classic sorting algorithms — bubble sort and selection sort — along with Python's built-in sort() and sorted(), and then moves to searching with binary search (iterative and recursive), the in operator and index().

12.1 · Live Tool

Sort Visualiser

Enter a comma-separated list of numbers, pick bubble sort or selection sort, and step through each comparison. Amber bars are being compared; red means a swap just happened; violet means an element has settled into its final sorted position.

Step Through a Sort

● live
Enter numbers, pick an algorithm, then press Load, then step through with Next Step.
Notice how bubble sort always compares adjacent pairs, while selection sort scans the whole unsorted part first to find the minimum before making one swap.
12.1.1

Bubble Sort

Bubble sort arranges a list of elements in ascending or descending order. The algorithm moves through the list and compares each pair of adjacent elements — if they are in the wrong order, they are swapped. Bubble sort gets its name because the larger element "bubbles" towards the end of the list.

Initial list: 23 12 7 11 4 Pass 1 23,12 → swap → 12 23 7 11 4 23, 7 → swap → 12 7 23 11 4 23,11 → swap → 12 7 11 23 4 23, 4 → swap → 12 7 11 4 23 ← 23 bubbled to the last position Pass 2 (ignore 23) 12, 7 → swap → 7 12 11 4 [23] 12,11 → swap → 7 11 12 4 [23] 12, 4 → swap → 7 11 4 12 [23] ← 12 bubbled to position 4 Pass 3 (ignore 23, 12) 7,11 → no swap → 7 11 4 [12 23] 11, 4 → swap → 7 4 11 [12 23] ← 11 bubbled to position 3 Pass 4 (ignore 23, 12, 11) 7, 4 → swap → 4 7 [11 12 23] Final sorted list: 4 7 11 12 23

To sort a list containing N elements, bubble sort requires (N − 1) passes. During each pass, the number of elements to be compared reduces by one, since the largest remaining element always moves to its correct position at the end.

Algorithm for Bubble Sort (ascending order)

  1. Step 1: Start.
  2. Step 2: Accept a value in N as the number of elements of the list.
  3. Step 3: Accept N elements into the list named LIST.
  4. Step 4: Repeat Steps 5 to 7, (N − 1) times.
  5. Step 5: Repeat Step 6 until the second last element of the current list.
  6. Step 6: Starting from the first position, compare two adjacent elements in the list. If they are not in the proper order, swap the elements.
  7. Step 7: Revise the list by excluding the last element in the current list.
  8. Step 8: Print the sorted list, LIST.
  9. Step 9: Stop.

To improve clarity and maintainability, Python encourages dividing large code blocks into smaller, well-defined functions. Following this approach, the bubble sort steps (5 to 7) are separated into a dedicated bubble_sort() function.

bubble_sort.py
# Traverse through all elements in the list
def bubble_sort(LIST, n):
    for i in range(n - 1):
        # Last i elements are already in place
        for j in range(0, n - i - 1):
            # Swap if element found is greater than next element
            if LIST[j] > LIST[j + 1]:
                LIST[j], LIST[j + 1] = LIST[j + 1], LIST[j]
    return LIST

# Accept number of elements
count = int(input("Enter how many numbers: "))
# Create an empty list
ITEMS = []
# Accept n numbers from the user
for i in range(count):
    num = int(input(f"Enter number {i+1}: "))
    ITEMS.append(num)
# Display the list
print("Original list:", ITEMS)
# Display the sorted list
print("Sorted list:", bubble_sort(ITEMS, count))
IDLE Shell 3.10.12
Enter how many numbers: 5
Enter number 1: 56
Enter number 2: 34
Enter number 3: 98
Enter number 4: 12
Enter number 5: 39
Original list: [56, 34, 98, 12, 39]
Sorted list: [12, 34, 39, 56, 98]
12.1.2

Selection Sort

To sort a list in ascending order, selection sort starts by finding the smallest value in the list and placing it in the first position — the element originally at the first position is shifted to where the smallest element was. This is repeated to find the second smallest, and so on, until the entire list is sorted.

Initial list: 32 23 10 2 30 Pass 1: smallest = 2 → exchange with position 1 After Pass 1: 2 23 10 32 30 Pass 2 (exclude pos 1): smallest = 10 → exchange with position 2 After Pass 2: 2 10 23 32 30 Pass 3 (exclude pos 1,2): smallest = 23 → already in place, no exchange After Pass 3: 2 10 23 32 30 Pass 4 (exclude pos 1,2,3): smallest = 30 → exchange with position 4 After Pass 4: 2 10 23 30 32 Final sorted list: 2 10 23 30 32

A pass is completed once the smallest element in the unsorted section is located and exchanged with the element at the current position. For N elements there will be N − 1 passes. Though each pass is intended for an exchange, no exchange is made if the smallest value is already in the correct location — as seen in Pass 3 above.

Algorithm for Selection Sort

  1. Step 1: Start.
  2. Step 2: Accept a value in N as the number of elements of the list.
  3. Step 3: Accept N elements into the list named LIST.
  4. Step 4: Repeat Steps 5 to 9, (N − 1) times.
  5. Step 5: Assume the first element in the list as the smallest and store it in MIN and its position in POS.
  6. Step 6: Repeat Step 7 until the last element of the list.
  7. Step 7: Compare the next element in the list with the value of MIN. If it is found smaller, store it in MIN and its position in POS.
  8. Step 8: If the first element in the unsorted list and the value in MIN are not the same, then swap the first element with the element at position POS.
  9. Step 9: Revise the list by excluding the first element in the current list.
  10. Step 10: Print the sorted LIST.
  11. Step 11: Stop.

As with bubble sort, the repeated operations of identifying the smallest element and swapping it (steps 5 to 9) are grouped into a separate selection_sort() function.

selection_sort.py
# Traverse through all elements in the list
def selection_sort(LIST, n):
    for i in range(n - 1):
        # Assume first element is the minimum
        min_index = i
        # Find index of smallest element in the remaining list
        for j in range(i + 1, n):
            if LIST[j] < LIST[min_index]:
                min_index = j
        # Swap min element with the first element of unsorted part
        LIST[i], LIST[min_index] = LIST[min_index], LIST[i]
    return LIST

# Accept number of elements
count = int(input("Enter how many numbers: "))
# Create an empty list
ITEMS = []
# Accept n numbers from the user
for i in range(count):
    num = int(input(f"Enter number {i+1}: "))
    ITEMS.append(num)
# Display the list
print("Original list:", ITEMS)
# Display the sorted list
print("Sorted list:", selection_sort(ITEMS, count))
IDLE Shell 3.10.12
Enter how many numbers: 5
Enter number 1: 78
Enter number 2: 45
Enter number 3: 97
Enter number 4: 34
Enter number 5: 67
Original list: [78, 45, 97, 34, 67]
Sorted list: [34, 45, 67, 78, 97]

Bubble sort vs Selection sort

Bubble sort repeatedly compares and swaps adjacent pairs as it moves through the list, so several swaps can happen within a single pass. Selection sort instead scans the entire unsorted portion first to find the overall smallest value, and performs at most one swap per pass.

12.1.3

Sorting Using Built-in Functions

Even though it is important to understand the algorithms behind sorting, Python provides two built-in tools for quick, efficient sorting: sort() and sorted().

(a) sort() Function

The built-in function sort() arranges the elements of a list in place — it changes the original list instead of creating a new one, and works only with lists. By default it sorts in ascending order; pass reverse=True for descending order.

>>>numbers = [5, 2, 8, 1, 9] >>>numbers.sort() >>>print(numbers) [1, 2, 5, 8, 9] >>>numbers = [5, 2, 8, 1, 9] >>>numbers.sort(reverse=True) >>>print(numbers) [9, 8, 5, 2, 1]

Apart from numbers, sort() can be used on lists of strings, or any data type that supports comparison. By default, strings are sorted alphabetically. The key parameter specifies a function that determines the sorting criteria — for example, sorting by word length with key=len.

>>>words = ['apple', 'kiwi', 'banana', 'mango'] >>>words.sort() >>>print(words) ['apple', 'banana', 'kiwi', 'mango'] >>>words.sort(key=len) >>>print(words) ['kiwi', 'apple', 'mango', 'banana']

(b) sorted() Function

This built-in function returns a new sorted list from the elements of literal collections such as list, tuple or string — it does not modify the original collection. Like sort(), it also accepts reverse=True and key=len.

>>>numbers = [5, 2, 8, 1, 9] >>>sorted_numbers = sorted(numbers) >>>print(sorted_numbers) [1, 2, 5, 8, 9] >>>print(numbers) [5, 2, 8, 1, 9] >>>sorted_numbers = sorted(numbers, reverse=True) >>>print(sorted_numbers) [9, 8, 5, 2, 1] >>>words = ['apple', 'kiwi', 'banana', 'mango'] >>>sorted_words = sorted(words, key=len) >>>print(sorted_words) ['kiwi', 'apple', 'mango', 'banana']

sort() modifies in place

Works only on lists, changes the original list, and returns None — never assign the result of list.sort() back to a variable.

sorted() returns a copy

Works on any iterable (list, tuple, string), leaves the original untouched, and returns a brand-new sorted list.

Even though Python provides sort() and sorted() for quick and efficient sorting, it is important to study the algorithms behind these operations. Learning bubble sort and selection sort helps you understand how data is processed, how efficiency is measured, and why certain methods perform better in specific situations.

12.2

Searching

Searching is the process of finding the location of a given element within a collection of data, such as a list, array, or database. It helps determine whether a particular item is present and, if present, its location.

Linear Search

Each element is checked one by one, in order, until the target is found or the list ends. Simple and convenient for small lists — already covered in Chapter 9.

Binary Search

Works efficiently only on sorted elements, repeatedly dividing the search space in half. Far fewer comparisons than linear search on large lists.

12.2.1

Binary Search

Binary search is an efficient searching technique that uses the minimum number of comparisons to locate an element in a sorted list. It checks the middle element — if it matches, the search ends; if the search value is smaller, it continues in the first half; if larger, it continues in the second half.

Sorted list: 21 28 33 35 45 58 61 Index: 0 1 2 3 4 5 6 Search for: 45 FIRST = 0, LAST = 6 Iteration 1: MIDDLE = (0+6)/2 = 3 → LIST[3] = 35, less than 45 → FIRST = MIDDLE+1 = 4, LAST = 6 Iteration 2: MIDDLE = (4+6)/2 = 5 → LIST[5] = 58, greater than 45 → FIRST = 4, LAST = MIDDLE-1 = 4 Iteration 3: MIDDLE = (4+4)/2 = 4 → LIST[4] = 45 ✓ Match! Search terminates successfully at index 4.

Algorithm for Binary Search

  1. Step 1: Start.
  2. Step 2: Accept a value in N as the number of elements of the list.
  3. Step 3: Accept N elements into the list named LIST in sorted order.
  4. Step 4: Accept the value to be searched in the variable ITEM.
  5. Step 5: Set search location, LOC = -1.
  6. Step 6: Store the position of the first element of the list in FIRST and position of the last element in LAST.
  7. Step 7: Repeat Steps 8 to 12 while (FIRST <= LAST).
  8. Step 8: Find the middle position using (FIRST + LAST)/2 and store it in MIDDLE.
  9. Step 9: Compare the search value in ITEM with the element at MIDDLE of the list.
  10. Step 10: If the MIDDLE element contains the search value, stop, display the position and go to Step 13.
  11. Step 11: If the search value is larger than the MIDDLE element, set FIRST = MIDDLE + 1.
  12. Step 12: If the search value is smaller than the MIDDLE element, set LAST = MIDDLE - 1.
  13. Step 13: If the value at LOC is less than 0, display "Not Found"; else display LOC + 1 as the position of the search value.
  14. Step 14: Stop.

As with the sorting algorithms, the repeated operations of locating the required element or narrowing the list to half its size are grouped into a separate binary_search() function.

binary_search.py
# Initialize variables
def binary_search(LIST, item, n):
    low = 0
    high = n - 1
    LOC = -1
    LIST.sort()
    # Perform binary search
    while low <= high:
        mid = (low + high) // 2
        if LIST[mid] == item:
            LOC = mid + 1   # Record position
            break
        elif item > LIST[mid]:
            low = mid + 1   # Search right half
        else:
            high = mid - 1  # Search left half
    # Display the location
    if LOC == -1:
        return None
    else:
        return LOC

# Accept number of elements
count = int(input("Enter how many numbers: "))
ITEMS = []
for i in range(count):
    num = float(input(f"Enter number {i+1}: "))
    ITEMS.append(num)
print("Number list:", ITEMS)
# Accept item to search
search_item = float(input("Enter the element to search: "))
pos = binary_search(ITEMS, search_item, count)
if pos is None:
    print("Element not found")
else:
    print("Element found at position ", pos)
IDLE Shell 3.10.12
Enter how many numbers: 5
Enter number 1: 23
Enter number 2: 34
Enter number 3: 43
Enter number 4: 46
Enter number 5: 49
Number list: [23.0, 34.0, 43.0, 46.0, 49.0]
Enter the element to search: 46
Element found at position  4

Recursive Binary Search

Binary search is a good example of a problem that repeats in smaller, similar patterns — making it a natural fit for recursion. The algorithm examines the middle element; if the search value is smaller, it recursively searches the first half, and if larger, it recursively searches the second half.

rec_binary.py
def bsearch_recursive(arr, low, high, item):
    if low > high:
        return -1                       # Element not found
    mid = (low + high) // 2
    if arr[mid] == item:
        return mid + 1                  # Return position
    elif item > arr[mid]:
        return bsearch_recursive(arr, mid + 1, high, item)   # Right half
    else:
        return bsearch_recursive(arr, low, mid - 1, item)    # Left half

# Accept number of elements
n = int(input("Enter how many numbers: "))
LIST = []
for i in range(n):
    num = float(input(f"Enter number {i+1}: "))
    LIST.append(num)
print("Number list:", LIST)

# Accept item to search
item = float(input("Enter the element to search: "))

# Perform recursive binary search
LOC = bsearch_recursive(LIST, 0, n - 1, item)

# Display result
if LOC == -1:
    print("Element not found")
else:
    print("Element found at position", LOC)
12.2.1 · Live Tool

Binary Search Lab

Enter a comma-separated list (it will be sorted automatically) and a value to search for, then step through each iteration to watch FIRST, LAST and MIDDLE narrow down the answer.

Try a Binary Search

● live
Enter a sorted-ish list and a target, then press Load, then step through with Next Step.
Amber borders mark the current FIRST/LAST window; the violet bar is MIDDLE on each iteration.
Let Us Do

Quick Recap

Tap a question to reveal the answer.

Why does bubble sort get its name, and how many passes does it need for N elements?

Bubble sort repeatedly compares and swaps adjacent elements, so the largest unsorted element gradually "bubbles" towards the end of the list with each pass — just like a bubble rising to the surface. For a list of N elements, bubble sort requires (N − 1) passes, since the last pass leaves only two elements to compare.

In selection sort, why might a pass complete without any exchange taking place?

Each pass of selection sort finds the smallest element in the remaining unsorted portion and swaps it into the current position. If that smallest element is already sitting in the correct position, no exchange is needed — the pass still "completes," but no swap occurs, as seen in Pass 3 of the worked example.

What is the key structural difference between how bubble sort and selection sort make their swaps?

Bubble sort can perform many swaps within a single pass, since it swaps every out-of-order adjacent pair as it moves through the list. Selection sort performs at most one swap per pass — it first scans the entire unsorted section to find the minimum, and only then makes a single exchange.

What is the difference between list.sort() and sorted(list)?

sort() is a list method that sorts the list in place, modifying the original list and returning None — it only works on lists. sorted() is a built-in function that returns a new sorted list, leaving the original list, tuple, or string unchanged, and it works on any iterable.

Why must the list be sorted before applying binary search?

Binary search relies on comparing the search value with the middle element to decide whether to continue in the left half or the right half of the list. This "narrowing down" logic only works correctly if the elements are arranged in sorted order — on an unsorted list, the algorithm could eliminate the half that actually contains the target.

In binary search, what happens when FIRST becomes greater than LAST?

The condition FIRST <= LAST controls the search loop. Once FIRST exceeds LAST, it means the search range has been fully narrowed down without finding a match, so the loop ends and the search reports the element as "Not Found" (or returns -1/None depending on the implementation).

How does the recursive version of binary search differ from the iterative version?

The iterative version uses a while loop and updates low/high variables on each pass. The recursive version, bsearch_recursive(), instead calls itself with new low and high boundaries for the relevant half of the list, with the base case low > high stopping the recursion when the element is not found.

What is the difference between the in operator and the index() function when searching a list?

The in operator only checks whether a value exists in a list, string, or tuple, returning True or False. The index() function goes further and returns the position (starting from 0) of the first occurrence of that value — but it raises an exception if the value is not found.