-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsort.py
309 lines (262 loc) · 7.81 KB
/
sort.py
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
#!/usr/bin/python
import random
import copy
#=======#
# SORTS #
#=======#
#def selectionSort(A)
#def insertionSort(A)
#def quickSort(A, left, right)
#def shellSort(A)
#def mergeSort(A, left, right)
#def countingSort(A)
#def radixSort(A)
#def bucketSort(A)
#=========#
# HELPERS #
#=========#
#def createRandomIntArray(size, minVal, maxVal)
#def generateIntArray(size)
#def isSorted(input)
#def choosePivot(A, left, right)
#def partition(A, left, right)
#def merge(A, Lstart, Lend, Rstart, Rend)
#def convertStringToInt(A)
def createRandomIntArray(size, minVal, maxVal):
Arr = []
for i in range(size):
Arr.append(random.randint(minVal, maxVal))
return Arr
def generateIntArray(size):
Arr = range(size)
random.shuffle(Arr)
return Arr
def isSorted(input):
n = len(input)
val = input[0]
for i in range(1, n):
if (input[i] < val):
return False
val = input[i]
return True
def selectionSort(A):
n = len(A)
for i in reversed(range(1, n)):
maxIndex = i
for j in reversed(range(0, i)):
if A[maxIndex] < A[j]:
maxIndex = j
temp = A[maxIndex]
A[maxIndex] = A[i]
A[i] = temp
return A
def insertionSort(A):
n = len(A)
for i in range(1, n):
for j in reversed(range(1,i+1)):
if (A[j] < A[j-1]):
temp = A[j-1]
A[j-1] = A[j]
A[j] = temp
return A
def choosePivot(A, left, right):
# Pick first element
#return A[left]
# Pick random element
return A[random.randint(left, right)]
# Left half will be <= pivot
# Right half will be > pivot
def partition(A, left, right):
pivotVal = choosePivot(A, left, right)
i = left
j = right
while True:
while (A[j] > pivotVal):
j -= 1
while (A[i] < pivotVal):
i += 1
if i < j:
temp = A[i]
A[i] = A[j]
A[j] = temp
else: # Pointers have crossed over
return j
# Works only for distinct elements in A
def quickSort(A, left, right):
if left < right:
split = partition(A, left, right)
quickSort(A, left, split)
quickSort(A, split+1, right)
return A
def shellSort(A):
n = len(A)
seq = range(1,n,3) # seq can be replaced
for gap in reversed(seq):
for i in range(gap, n):
temp = A[i]
j = i
# Assume subarrays (w.r.t. mod gap) involving A[0]-A[j]
# Insert A[j] into its correct position in its respective (mod gap) subarray
# "Mini insertion sort"
while (j >= gap):
if (A[j-gap] > temp):
A[j] = A[j-gap]
j -= gap
else:
break;
A[j] = temp
return A
def merge(A, Lstart, Lend, Rstart, Rend):
merged = []
l = Lstart
r = Rstart
while True:
# If one of the sublists is exhausted, just append the rest of the other sublist
if (l > Lend):
merged += A[r:Rend+1]
break;
if (r > Rend):
merged += A[l:Lend+1]
break;
# Add the smaller value to the merged array, then advance pointer
if (A[l] < A[r]):
merged.append(A[l])
l += 1
else:
merged.append(A[r])
r += 1
# Sanity check
if (len(merged) != (Lend - Lstart + 1) + (Rend - Rstart + 1)):
print "ERROR IN MERGING"
# Reflect updated merged section into actual array
for i in range(Lstart, Rend+1):
A[i] = merged[i - Lstart]
def mergeSort(A, left, right):
if (left == right):
return A
else:
mid = (left+right)/2 # Python division truncates remainders
mergeSort(A, left, mid)
mergeSort(A, mid+1, right)
merge(A, left, mid, mid+1, right)
return A
def countingSort(A):
# Obtain min/max values of input
minVal = A[0]
maxVal = A[0]
for i in range(0, len(A)):
if A[i] < minVal:
minVal = A[i]
if A[i] > maxVal:
maxVal = A[i]
# Create counter and output arrays
counter = []
for i in range(minVal, maxVal+1):
counter.append(0)
# Count occurences + Create output array
output = []
for i in range(0, len(A)):
counter[A[i]-minVal] += 1
output.append(0)
# Cumulate counts
for i in range(1, len(counter)):
counter[i] += counter[i-1]
# Sanity check
if counter[len(counter)-1] != len(A):
print "ERROR IN COUNTING"
for i in range(0, len(A)):
output[counter[A[i]-minVal]-1] = A[i]
counter[A[i]-minVal] -= 1
return output
def convertStringToInt(A):
converted = []
for i in range(0, len(A)):
converted.append(int(A[i]))
return converted
def radixSort(A):
base = 10 # Assume base = 10. In general, this might not always be the case
converted = []
maxLength = 0
# Count max length
for i in range(0, len(A)):
converted.append(str(A[i]))
maxLength = max(maxLength, len(converted[i]))
# Pad zeroes in front till same length
for i in range(0, len(converted)):
while len(converted[i]) < maxLength:
converted[i] = "0" + converted[i]
A = converted
# Sort from 'least significant bit' to 'most significant bit'
for l in reversed(range(0, maxLength)):
sublists = []
for b in range(0, base):
sublists.append([])
# Add each item to its appropriate sublist
for i in range(0, len(converted)):
sublists[int(A[i][l])].append(A[i])
# Sort the sublists based on the length index [Modified Insertion sort]
for b in range(0, base):
for i in range(0, len(sublists[b])):
for j in reversed(range(1, i+1)):
if (sublists[b][j][l] < sublists[b][j-1][l]):
temp = sublists[b][j]
sublists[b][j] = sublists[b][j-1]
sublists[b][j-1] = temp
# Concatenate lists
A = []
for b in range(0, base):
A += sublists[b]
return convertStringToInt(A)
def bucketSort(A):
# Obtain min/max values of input
minVal = A[0]
maxVal = A[0]
for i in range(0, len(A)):
if A[i] < minVal:
minVal = A[i]
if A[i] > maxVal:
maxVal = A[i]
# Create n buckets
buckets = []
for i in range(0, len(A)):
buckets.append([])
# Put items into buckets
for i in range(0, len(A)):
index = (A[i]-minVal)/(maxVal-minVal)
buckets[index].append(A[i])
# Sort each bucket [Insertion sort]
for b in range(0, len(buckets)):
for i in range(0, len(buckets[b])):
for j in reversed(range(1, i+1)):
if (buckets[b][j] < buckets[b][j-1]):
temp = buckets[b][j]
buckets[b][j] = buckets[b][j-1]
buckets[b][j-1] = temp
# Concatenate buckets
A = []
for b in range(0, len(buckets)):
A += buckets[b]
return A
#======#
# MAIN #
#======#
n = input()
A = createRandomIntArray(n, 0, n)
#A = generateIntArray(n) # Distinct sequence of integers
print "Input: ", A
B = selectionSort(copy.deepcopy(A))
C = insertionSort(copy.deepcopy(A))
#D = quickSort(copy.deepcopy(A), 0, len(A)-1)
E = shellSort(copy.deepcopy(A))
F = mergeSort(copy.deepcopy(A), 0, len(A)-1)
G = countingSort(copy.deepcopy(A))
H = radixSort(copy.deepcopy(A))
I = bucketSort(copy.deepcopy(A))
print "Selection Sort: ", B, isSorted(B)
print "Insertion Sort: ", C, isSorted(C)
#print "Quick Sort: ", D, isSorted(D)
print "Shell Sort: ", E, isSorted(E)
print "Merge Sort: ", F, isSorted(F)
print "Counting Sort: ", G, isSorted(G)
print "Radix Sort: ", H, isSorted(H)
print "Bucket Sort: ", I, isSorted(I)