-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathalgorithms.py
More file actions
169 lines (126 loc) · 4.91 KB
/
algorithms.py
File metadata and controls
169 lines (126 loc) · 4.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
def bubble_sort(arr, track_steps=True):
arr = arr.copy()
n = len(arr)
steps = [] if track_steps else None
op_count = 0 # count the number of steps taken to sort
for i in range(n - 1):
swapped = False
# last i elements are already in place
for j in range(n - i - 1):
op_count += 1
if track_steps:
steps.append({'type': 'comparison', 'indices': [j, j + 1], 'array': arr.copy()})
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j] # Swap using tuple assignment
swapped = True
op_count += 1
if track_steps:
steps.append({'type': 'swap', 'indices': [j, j + 1], 'array': arr.copy()})
# If no two elements were swapped by inner loop, then break
if not swapped:
break
return (arr, steps, op_count) if track_steps else (arr, op_count)
def selection_sort(arr, track_steps=True):
arr = arr.copy()
n = len(arr)
steps = [] if track_steps else None
op_count = 0 # count the number of steps taken to sort
for i in range(n - 1):
min_index = i
# Find minimum in remaining unsorted array
for j in range(i + 1, n):
op_count += 1
if track_steps:
steps.append({'type': 'comparison', 'indices': [j,min_index], 'array': arr.copy()})
if arr[j] < arr[min_index]:
min_index = j
if track_steps:
steps.append({'type': 'change_min_index', 'index': min_index, 'array': arr.copy()})
if min_index != i:
# Swap with first element of unsorted part
arr[min_index], arr[i] = arr[i], arr[min_index]
op_count += 1
if track_steps:
steps.append({'type': 'swap', 'indices': [min_index, i], 'array': arr.copy()})
return (arr, steps, op_count) if track_steps else (arr, op_count)
def insertion_sort(arr, track_steps=True):
arr = arr.copy()
steps = [] if track_steps else None
op_count = 0 # count the number of steps taken to sort
# Traverse through 1 to len(arr)
for i in range(1, len(arr)):
# Store the current element to be inserted
key = arr[i]
# Move elements of arr[0..i-1], that are greater than key, to one position ahead of their current position
j = i - 1
if track_steps:
steps.append({'type': 'extract', 'index': i, 'array': arr.copy()})
while j >= 0:
op_count += 1
if key < arr[j]:
if track_steps:
steps.append({'type': 'comparison', 'indices': [j, j + 1], 'array': arr.copy()})
arr[j + 1] = arr[j]
op_count += 1
if track_steps:
steps.append({'type': 'shift', 'indices': [j, j + 1], 'array': arr.copy()})
j -= 1
else:
break
# Insert the key at its correct position
arr[j + 1] = key
op_count += 1
if track_steps:
steps.append({'type': 'insert', 'index': j + 1, 'array': arr.copy()})
return (arr, steps, op_count) if track_steps else (arr, op_count)
def merge_sort(arr, track_steps=True):
arr = arr.copy()
steps = []
op_count = 0 # count the number of steps taken to sort
def _merge_sort(left, right):
if left >= right:
return
# Finding the midpoint of the list
mid = (left + right) // 2
_merge_sort(left, mid)
_merge_sort(mid + 1, right)
merge(left, mid, right)
def merge(left, mid, right):
temp = []
i, j = left, mid + 1
nonlocal op_count
while i <= mid and j <= right:
op_count += 1
if track_steps:
steps.append({
"type": "comparison",
"indices": [i, j],
"array": arr.copy()
})
# Copy data to temp lists left_half and right_half
if arr[i] <= arr[j]:
temp.append(arr[i])
i += 1
else:
temp.append(arr[j])
j += 1
# Check if any elements were left in the left half
while i <= mid:
temp.append(arr[i])
i += 1
# Check if any elements were left in the right half
while j <= right:
temp.append(arr[j])
j += 1
# Copy back into original array
for k in range(len(temp)):
arr[left + k] = temp[k]
op_count += 1
if track_steps:
steps.append({
"type": "overwrite",
"index": left + k,
"array": arr.copy()
})
_merge_sort(0, len(arr) - 1)
return (arr, steps, op_count) if track_steps else (arr, op_count)