|
1 | | -from typing import Any |
2 | | - |
3 | | - |
4 | | -def bubble_sort_iterative(collection: list[Any]) -> list[Any]: |
5 | | - """Pure implementation of bubble sort algorithm in Python |
6 | | -
|
7 | | - :param collection: some mutable ordered collection with heterogeneous |
8 | | - comparable items inside |
9 | | - :return: the same collection ordered by ascending |
10 | | -
|
11 | | - Examples: |
12 | | - >>> bubble_sort_iterative([0, 5, 2, 3, 2]) |
13 | | - [0, 2, 2, 3, 5] |
14 | | - >>> bubble_sort_iterative([]) |
15 | | - [] |
16 | | - >>> bubble_sort_iterative([-2, -45, -5]) |
17 | | - [-45, -5, -2] |
18 | | - >>> bubble_sort_iterative([-23, 0, 6, -4, 34]) |
19 | | - [-23, -4, 0, 6, 34] |
20 | | - >>> bubble_sort_iterative([0, 5, 2, 3, 2]) == sorted([0, 5, 2, 3, 2]) |
21 | | - True |
22 | | - >>> bubble_sort_iterative([]) == sorted([]) |
23 | | - True |
24 | | - >>> bubble_sort_iterative([-2, -45, -5]) == sorted([-2, -45, -5]) |
25 | | - True |
26 | | - >>> bubble_sort_iterative([-23, 0, 6, -4, 34]) == sorted([-23, 0, 6, -4, 34]) |
27 | | - True |
28 | | - >>> bubble_sort_iterative(['d', 'a', 'b', 'e']) == sorted(['d', 'a', 'b', 'e']) |
29 | | - True |
30 | | - >>> bubble_sort_iterative(['z', 'a', 'y', 'b', 'x', 'c']) |
31 | | - ['a', 'b', 'c', 'x', 'y', 'z'] |
32 | | - >>> bubble_sort_iterative([1.1, 3.3, 5.5, 7.7, 2.2, 4.4, 6.6]) |
33 | | - [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7] |
34 | | - >>> bubble_sort_iterative([1, 3.3, 5, 7.7, 2, 4.4, 6]) |
35 | | - [1, 2, 3.3, 4.4, 5, 6, 7.7] |
36 | | - >>> import random |
37 | | - >>> collection_arg = random.sample(range(-50, 50), 100) |
38 | | - >>> bubble_sort_iterative(collection_arg) == sorted(collection_arg) |
39 | | - True |
40 | | - >>> import string |
41 | | - >>> collection_arg = random.choices(string.ascii_letters + string.digits, k=100) |
42 | | - >>> bubble_sort_iterative(collection_arg) == sorted(collection_arg) |
43 | | - True |
| 1 | +from typing import Any, List |
| 2 | + |
| 3 | +""" |
| 4 | +Bubble Sort Algorithms |
| 5 | +
|
| 6 | +This module provides iterative and optimized implementations |
| 7 | +of the Bubble Sort algorithm. |
| 8 | +
|
| 9 | +Time Complexity: |
| 10 | + Best Case: O(n) |
| 11 | + Average Case: O(n^2) |
| 12 | + Worst Case: O(n^2) |
| 13 | +
|
| 14 | +Space Complexity: |
| 15 | + O(1) |
| 16 | +""" |
| 17 | + |
| 18 | + |
| 19 | +def bubble_sort_iterative(collection: List[Any]) -> List[Any]: |
44 | 20 | """ |
45 | | - length = len(collection) |
46 | | - for i in reversed(range(length)): |
| 21 | + Bubble Sort (Iterative) |
| 22 | +
|
| 23 | + Sorts a list in ascending order using the bubble sort algorithm. |
| 24 | +
|
| 25 | + :param collection: A mutable list of comparable elements |
| 26 | + :return: Sorted list |
| 27 | + """ |
| 28 | + |
| 29 | + n = len(collection) |
| 30 | + if n < 2: |
| 31 | + return collection |
| 32 | + |
| 33 | + for i in range(n): |
47 | 34 | swapped = False |
48 | | - for j in range(i): |
| 35 | + for j in range(0, n - i - 1): |
49 | 36 | if collection[j] > collection[j + 1]: |
50 | | - swapped = True |
51 | 37 | collection[j], collection[j + 1] = collection[j + 1], collection[j] |
| 38 | + swapped = True |
| 39 | + |
52 | 40 | if not swapped: |
53 | | - break # Stop iteration if the collection is sorted. |
| 41 | + break |
| 42 | + |
54 | 43 | return collection |
55 | 44 |
|
56 | 45 |
|
57 | | -def bubble_sort_recursive(collection: list[Any]) -> list[Any]: |
58 | | - """It is similar iterative bubble sort but recursive. |
59 | | -
|
60 | | - :param collection: mutable ordered sequence of elements |
61 | | - :return: the same list in ascending order |
62 | | -
|
63 | | - Examples: |
64 | | - >>> bubble_sort_recursive([0, 5, 2, 3, 2]) |
65 | | - [0, 2, 2, 3, 5] |
66 | | - >>> bubble_sort_iterative([]) |
67 | | - [] |
68 | | - >>> bubble_sort_recursive([-2, -45, -5]) |
69 | | - [-45, -5, -2] |
70 | | - >>> bubble_sort_recursive([-23, 0, 6, -4, 34]) |
71 | | - [-23, -4, 0, 6, 34] |
72 | | - >>> bubble_sort_recursive([0, 5, 2, 3, 2]) == sorted([0, 5, 2, 3, 2]) |
73 | | - True |
74 | | - >>> bubble_sort_recursive([]) == sorted([]) |
75 | | - True |
76 | | - >>> bubble_sort_recursive([-2, -45, -5]) == sorted([-2, -45, -5]) |
77 | | - True |
78 | | - >>> bubble_sort_recursive([-23, 0, 6, -4, 34]) == sorted([-23, 0, 6, -4, 34]) |
79 | | - True |
80 | | - >>> bubble_sort_recursive(['d', 'a', 'b', 'e']) == sorted(['d', 'a', 'b', 'e']) |
81 | | - True |
82 | | - >>> bubble_sort_recursive(['z', 'a', 'y', 'b', 'x', 'c']) |
83 | | - ['a', 'b', 'c', 'x', 'y', 'z'] |
84 | | - >>> bubble_sort_recursive([1.1, 3.3, 5.5, 7.7, 2.2, 4.4, 6.6]) |
85 | | - [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7] |
86 | | - >>> bubble_sort_recursive([1, 3.3, 5, 7.7, 2, 4.4, 6]) |
87 | | - [1, 2, 3.3, 4.4, 5, 6, 7.7] |
88 | | - >>> bubble_sort_recursive(['a', 'Z', 'B', 'C', 'A', 'c']) |
89 | | - ['A', 'B', 'C', 'Z', 'a', 'c'] |
90 | | - >>> import random |
91 | | - >>> collection_arg = random.sample(range(-50, 50), 100) |
92 | | - >>> bubble_sort_recursive(collection_arg) == sorted(collection_arg) |
93 | | - True |
94 | | - >>> import string |
95 | | - >>> collection_arg = random.choices(string.ascii_letters + string.digits, k=100) |
96 | | - >>> bubble_sort_recursive(collection_arg) == sorted(collection_arg) |
97 | | - True |
| 46 | +def bubble_sort_optimized(collection: List[Any]) -> List[Any]: |
98 | 47 | """ |
99 | | - length = len(collection) |
100 | | - swapped = False |
101 | | - for i in range(length - 1): |
102 | | - if collection[i] > collection[i + 1]: |
103 | | - collection[i], collection[i + 1] = collection[i + 1], collection[i] |
104 | | - swapped = True |
105 | | - |
106 | | - return collection if not swapped else bubble_sort_recursive(collection) |
107 | | - |
108 | | - |
109 | | -if __name__ == "__main__": |
110 | | - import doctest |
111 | | - from random import sample |
112 | | - from timeit import timeit |
113 | | - |
114 | | - doctest.testmod() |
115 | | - |
116 | | - # Benchmark: Iterative seems slightly faster than recursive. |
117 | | - num_runs = 10_000 |
118 | | - unsorted = sample(range(-50, 50), 100) |
119 | | - timer_iterative = timeit( |
120 | | - "bubble_sort_iterative(unsorted[:])", globals=globals(), number=num_runs |
121 | | - ) |
122 | | - print("\nIterative bubble sort:") |
123 | | - print(*bubble_sort_iterative(unsorted), sep=",") |
124 | | - print(f"Processing time (iterative): {timer_iterative:.5f}s for {num_runs:,} runs") |
125 | | - |
126 | | - unsorted = sample(range(-50, 50), 100) |
127 | | - timer_recursive = timeit( |
128 | | - "bubble_sort_recursive(unsorted[:])", globals=globals(), number=num_runs |
129 | | - ) |
130 | | - print("\nRecursive bubble sort:") |
131 | | - print(*bubble_sort_recursive(unsorted), sep=",") |
132 | | - print(f"Processing time (recursive): {timer_recursive:.5f}s for {num_runs:,} runs") |
| 48 | + Optimized Bubble Sort |
| 49 | +
|
| 50 | + Uses the last swap position to reduce unnecessary comparisons |
| 51 | + when part of the list is already sorted. |
| 52 | +
|
| 53 | + :param collection: A mutable list of comparable elements |
| 54 | + :return: Sorted list |
| 55 | + """ |
| 56 | + |
| 57 | + n = len(collection) |
| 58 | + if n < 2: |
| 59 | + return collection |
| 60 | + |
| 61 | + while n > 1: |
| 62 | + last_swap = 0 |
| 63 | + for i in range(1, n): |
| 64 | + if collection[i - 1] > collection[i]: |
| 65 | + collection[i - 1], collection[i] = collection[i], collection[i - 1] |
| 66 | + last_swap = i |
| 67 | + n = last_swap |
| 68 | + |
| 69 | + return collection |
0 commit comments