Skip to content

Commit 6c554ec

Browse files
committed
Added implementations for core sorting algorithms
Introduces the following sorting algorithms into the `algorithms/` directory: - Selection Sort - Insertion Sort - Quick Sort - Heap Sort - Radix Sort - Merge Sort - Shell Sort
1 parent 7f81ef2 commit 6c554ec

File tree

7 files changed

+294
-0
lines changed

7 files changed

+294
-0
lines changed

algorithms/heap_sort.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
def heap_sort(array, update_callback):
2+
def heapify(n, i, arr_copy): # Pass arr_copy for visualization consistency
3+
largest = i
4+
l = 2 * i + 1
5+
r = 2 * i + 2
6+
7+
# Highlight the root being considered for heapify
8+
update_callback(arr_copy, highlight_indices=[i], moving_index=None)
9+
10+
# See if left child exists and is greater than root
11+
if l < n:
12+
# Highlight comparison
13+
update_callback(arr_copy, highlight_indices=[i, l], moving_index=l)
14+
if array[l] > array[largest]:
15+
largest = l
16+
17+
# See if right child exists and is greater than largest so far
18+
if r < n:
19+
# Highlight comparison
20+
update_callback(arr_copy, highlight_indices=[i, largest, r], moving_index=r)
21+
if array[r] > array[largest]:
22+
largest = r
23+
24+
# Change root, if needed
25+
if largest != i:
26+
array[i], array[largest] = array[largest], array[i]
27+
# Highlight the swap during heapify
28+
arr_copy[:] = array # Update visualization copy
29+
update_callback(
30+
arr_copy, highlight_indices=[i, largest], moving_index=largest
31+
)
32+
# Heapify the root.
33+
heapify(n, largest, arr_copy)
34+
35+
n = len(array)
36+
vis_array = list(array) # Use a copy for consistent visualization during heapify
37+
38+
# Build a maxheap.
39+
# Since last parent will be at ((n//2)-1) we can start at that location.
40+
for i in range(n // 2 - 1, -1, -1):
41+
heapify(n, i, vis_array)
42+
43+
# One by one extract elements
44+
for i in range(n - 1, 0, -1):
45+
# Move current root to end
46+
array[i], array[0] = array[0], array[i]
47+
# Highlight the swap (moving max element to sorted position)
48+
vis_array[:] = array # Update visualization copy
49+
update_callback(vis_array, highlight_indices=[0, i], moving_index=i)
50+
51+
# call max heapify on the reduced heap
52+
heapify(i, 0, vis_array)
53+
54+
update_callback(array) # Final update before sweep
55+
56+
# Final sweep animation
57+
for i in range(n):
58+
update_callback(array, moving_index=i, end=True, sweep=True)

algorithms/insertion_sort.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
def insertion_sort(array, update_callback):
2+
n = len(array)
3+
for i in range(1, n):
4+
key = array[i]
5+
j = i - 1
6+
# Highlight the key element being considered
7+
update_callback(array, highlight_indices=[i], moving_index=i)
8+
9+
# Move elements of array[0..i-1], that are greater than key,
10+
# to one position ahead of their current position
11+
while j >= 0 and key < array[j]:
12+
array[j + 1] = array[j]
13+
# Highlight comparison and the element being shifted
14+
update_callback(array, highlight_indices=[j, i], moving_index=j + 1)
15+
j -= 1
16+
array[j + 1] = key
17+
# Highlight the final position where the key was inserted
18+
update_callback(array, highlight_indices=[j + 1], moving_index=j + 1)
19+
20+
update_callback(array) # Final update before sweep
21+
22+
# Final sweep animation
23+
for i in range(n):
24+
update_callback(array, moving_index=i, end=True, sweep=True)

algorithms/merge_sort.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
def merge_sort(array, update_callback):
2+
def merge_sort_recursive(arr, temp, left_start, right_end):
3+
if left_start >= right_end:
4+
return
5+
6+
middle = (left_start + right_end) // 2
7+
merge_sort_recursive(arr, temp, left_start, middle)
8+
merge_sort_recursive(arr, temp, middle + 1, right_end)
9+
merge(arr, temp, left_start, right_end)
10+
11+
def merge(arr, temp, left_start, right_end):
12+
left_end = (right_end + left_start) // 2
13+
right_start = left_end + 1
14+
size = right_end - left_start + 1
15+
16+
left = left_start
17+
right = right_start
18+
index = left_start
19+
20+
highlight = list(range(left_start, right_end + 1))
21+
22+
while left <= left_end and right <= right_end:
23+
# Highlight elements being compared
24+
update_callback(arr, highlight_indices=[left, right], moving_index=index)
25+
if arr[left] <= arr[right]:
26+
temp[index] = arr[left]
27+
left += 1
28+
else:
29+
temp[index] = arr[right]
30+
right += 1
31+
index += 1
32+
33+
# Copy remaining elements from left half
34+
while left <= left_end:
35+
update_callback(arr, highlight_indices=[left], moving_index=index)
36+
temp[index] = arr[left]
37+
left += 1
38+
index += 1
39+
40+
# Copy remaining elements from right half
41+
while right <= right_end:
42+
update_callback(arr, highlight_indices=[right], moving_index=index)
43+
temp[index] = arr[right]
44+
right += 1
45+
index += 1
46+
47+
# Copy sorted elements back to original array
48+
for i in range(left_start, right_end + 1):
49+
arr[i] = temp[i]
50+
# Show the placement in the original array
51+
update_callback(arr, highlight_indices=[i], moving_index=i)
52+
53+
n = len(array)
54+
temp_array = [0] * n
55+
merge_sort_recursive(array, temp_array, 0, n - 1)
56+
57+
update_callback(array) # Final update before sweep
58+
59+
# Final sweep animation
60+
for i in range(n):
61+
update_callback(array, moving_index=i, end=True, sweep=True)

algorithms/quick_sort.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
def quick_sort(array, update_callback):
2+
def partition(low, high):
3+
pivot = array[high]
4+
# Highlight the pivot element
5+
update_callback(array, highlight_indices=[high], moving_index=None)
6+
i = low - 1
7+
for j in range(low, high):
8+
# Highlight elements being compared
9+
update_callback(array, highlight_indices=[i + 1, j, high], moving_index=j)
10+
if array[j] < pivot:
11+
i += 1
12+
array[i], array[j] = array[j], array[i]
13+
# Highlight the swap
14+
update_callback(array, highlight_indices=[i, j, high], moving_index=j)
15+
16+
# Place pivot in correct position
17+
array[i + 1], array[high] = array[high], array[i + 1]
18+
# Highlight the pivot's final position for this partition
19+
update_callback(array, highlight_indices=[i + 1], moving_index=i + 1)
20+
return i + 1
21+
22+
def quick_sort_recursive(low, high):
23+
if low < high:
24+
# pi is partitioning index, array[p] is now at right place
25+
pi = partition(low, high)
26+
27+
# Separately sort elements before partition and after partition
28+
quick_sort_recursive(low, pi - 1)
29+
quick_sort_recursive(pi + 1, high)
30+
31+
quick_sort_recursive(0, len(array) - 1)
32+
update_callback(array) # Final update before sweep
33+
34+
# Final sweep animation
35+
for i in range(len(array)):
36+
update_callback(array, moving_index=i, end=True, sweep=True)

algorithms/radix_sort.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
def radix_sort(array, update_callback):
2+
def counting_sort(array, exp):
3+
n = len(array)
4+
output = [0] * n
5+
count = [0] * 10
6+
7+
# Store count of occurrences in count[]
8+
for i in range(n):
9+
index = array[i] // exp
10+
count[index % 10] += 1
11+
# Highlight element being read
12+
update_callback(array, highlight_indices=[i], moving_index=None)
13+
14+
# Change count[i] so that count[i] now contains actual
15+
# position of this digit in output[]
16+
for i in range(1, 10):
17+
count[i] += count[i - 1]
18+
19+
# Build the output array
20+
i = n - 1
21+
while i >= 0:
22+
index = array[i] // exp
23+
output_idx = count[index % 10] - 1
24+
output[output_idx] = array[i]
25+
count[index % 10] -= 1
26+
# Highlight element being placed
27+
update_callback(array, highlight_indices=[i], moving_index=output_idx)
28+
i -= 1
29+
30+
# Copy the output array to array[], so that array[] now
31+
# contains sorted numbers according to current digit
32+
for i in range(n):
33+
array[i] = output[i]
34+
# Show the array after this pass - highlight the element just placed
35+
update_callback(array, highlight_indices=[], moving_index=i)
36+
37+
if not array:
38+
return # Handle empty array
39+
40+
max_element = max(array) if array else 0
41+
exp = 1
42+
while max_element // exp > 0:
43+
counting_sort(array, exp)
44+
exp *= 10
45+
46+
update_callback(array) # Final update before sweep
47+
48+
# Final sweep animation
49+
for i in range(len(array)):
50+
update_callback(array, moving_index=i, end=True, sweep=True)

algorithms/selection_sort.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
def selection_sort(array, update_callback):
2+
n = len(array)
3+
for i in range(n):
4+
# Find the minimum element in remaining unsorted array
5+
min_idx = i
6+
# Highlight the start of the unsorted section
7+
update_callback(array, highlight_indices=[i], moving_index=None)
8+
9+
for j in range(i + 1, n):
10+
# Highlight current minimum and element being compared
11+
update_callback(array, highlight_indices=[i, min_idx], moving_index=j)
12+
if array[j] < array[min_idx]:
13+
min_idx = j
14+
# Highlight the new minimum found
15+
update_callback(array, highlight_indices=[i, min_idx], moving_index=j)
16+
17+
# Swap the found minimum element with the first element
18+
array[i], array[min_idx] = array[min_idx], array[i]
19+
# Highlight the swap into the sorted position
20+
update_callback(array, highlight_indices=[i], moving_index=min_idx)
21+
22+
update_callback(array) # Final update before sweep
23+
24+
# Final sweep animation
25+
for i in range(n):
26+
update_callback(array, moving_index=i, end=True, sweep=True)

algorithms/shell_sort.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
def shell_sort(array, update_callback):
2+
n = len(array)
3+
# Start with a large gap, then reduce the gap
4+
# Using Knuth's sequence: h = h * 3 + 1 -> ..., 40, 13, 4, 1
5+
gap = 1
6+
while gap < n / 3:
7+
gap = gap * 3 + 1
8+
9+
while gap > 0:
10+
# Do a gapped insertion sort for this gap size.
11+
# The first gap elements a[0..gap-1] are already in gapped order
12+
# keep adding one more element until the entire array is gap sorted
13+
for i in range(gap, n):
14+
# add a[i] to the elements that have been gap sorted
15+
# save a[i] in temp and make a hole at position i
16+
temp = array[i]
17+
18+
# shift earlier gap-sorted elements up until the correct location for a[i] is found
19+
j = i
20+
while j >= gap and array[j - gap] > temp:
21+
array[j] = array[j - gap]
22+
# Highlight comparison and movement
23+
update_callback(array, highlight_indices=[j, j - gap], moving_index=j)
24+
j -= gap
25+
26+
# put temp (the original a[i]) in its correct location
27+
array[j] = temp
28+
update_callback(
29+
array, highlight_indices=[i], moving_index=j
30+
) # Show final placement
31+
32+
# Reduce the gap
33+
gap = gap // 3 # Integer division is fine here
34+
35+
update_callback(array) # Final update before sweep
36+
37+
# Final sweep animation
38+
for i in range(n):
39+
update_callback(array, moving_index=i, end=True, sweep=True)

0 commit comments

Comments
 (0)