Skip to content

Commit 5cc90d1

Browse files
TjstretchalotOmkarPathak
authored andcommitted
Add tests and improve documentation on new sorting algorithms (#97)
This effectively standardizes the function arguments for all the new sorting algorithms to be consistent with the other ones. Also fixes a few bugs and performs some style improvements, such as moving documentation of functions to after the function definition instead of before, and adding documentation where it is missing.
1 parent 3f98cc9 commit 5cc90d1

File tree

5 files changed

+238
-143
lines changed

5 files changed

+238
-143
lines changed

pygorithm/sorting/brick_sort.py

Lines changed: 25 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
1-
def brick_sort(arr, n):
2-
# Initially array is unsorted
3-
isSorted = 0
4-
while isSorted == 0:
5-
isSorted = 1
6-
temp = 0
7-
for i in range(1, n-1, 2):
8-
if arr[i] > arr[i+1]:
9-
arr[i], arr[i+1] = arr[i+1], arr[i]
10-
isSorted = 0
11-
12-
for i in range(0, n-1, 2):
13-
if arr[i] > arr[i+1]:
14-
arr[i], arr[i+1] = arr[i+1], arr[i]
15-
isSorted = 0
16-
17-
return
1+
def brick_sort(arr):
2+
"""Performs an odd-even in-place sort, which is a variation of a bubble
3+
sort.
4+
5+
https://www.geeksforgeeks.org/odd-even-sort-brick-sort/
6+
7+
:param arr: the array of values to sort
8+
:return: the sorted array
9+
"""
10+
# Initially array is unsorted
11+
is_sorted = False
12+
while not is_sorted:
13+
is_sorted = True
14+
15+
for i in range(1, len(arr) - 1, 2):
16+
if arr[i] > arr[i + 1]:
17+
arr[i], arr[i + 1] = arr[i + 1], arr[i]
18+
is_sorted = False
19+
20+
for i in range(0, len(arr) - 1, 2):
21+
if arr[i] > arr[i + 1]:
22+
arr[i], arr[i + 1] = arr[i + 1], arr[i]
23+
is_sorted = False
24+
25+
return arr

pygorithm/sorting/cocktail_sort.py

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -3,55 +3,58 @@
33
last modified: 14-10-2019
44
'''
55

6-
'''
76

8-
Cocktail Sort is a variation of Bubble sort.
9-
The Bubble sort algorithm always traverses elements from left
10-
and moves the largest element to its correct position in first iteration
11-
and second largest in second iteration and so on.
12-
Cocktail Sort traverses through a given array in both directions alternatively.
7+
def cocktail_sort(arr):
8+
'''
9+
Cocktail Sort is a variation of Bubble sort.
10+
The Bubble sort algorithm always traverses elements from left
11+
and moves the largest element to its correct position in first iteration
12+
and second largest in second iteration and so on.
13+
Cocktail Sort traverses through a given array in both directions alternatively.
1314
14-
'''
15+
This is an in-place sort.
1516
16-
def cocktail_sort(a):
17-
n = len(a)
17+
:param arr: the array to sort
18+
:return: the sorted array, which is the same reference as arr
19+
'''
1820
swapped = True
1921
start = 0
20-
end = n-1
21-
while swapped:
22-
23-
# reset the swapped flag on entering the loop,
24-
# because it might be true from a previous
25-
# iteration.
22+
end = len(arr) - 1
23+
while swapped:
24+
# reset the swapped flag on entering the loop,
25+
# because it might be true from a previous
26+
# iteration.
2627
swapped = False
27-
28-
# loop from left to right same as the bubble
29-
# sort
30-
for i in range(start, end):
31-
if a[i] > a[i + 1]:
32-
a[i], a[i + 1] = a[i + 1], a[i]
28+
29+
# loop from left to right same as the bubble
30+
# sort
31+
for i in range(start, end):
32+
if arr[i] > arr[i + 1]:
33+
arr[i], arr[i + 1] = arr[i + 1], arr[i]
3334
swapped = True
34-
35-
# if nothing moved, then array is sorted.
36-
if not swapped:
35+
36+
# if nothing moved, then array is sorted.
37+
if not swapped:
3738
break
38-
39-
# otherwise, reset the swapped flag so that it
40-
# can be used in the next stage
39+
40+
# otherwise, reset the swapped flag so that it
41+
# can be used in the next stage
4142
swapped = False
42-
43-
# move the end point back by one, because
44-
# item at the end is in its rightful spot
43+
44+
# move the end point back by one, because
45+
# item at the end is in its rightful spot
4546
end -= 1
46-
47-
# from right to left, doing the same
48-
# comparison as in the previous stage
49-
for i in range(end-1, start-1, -1):
50-
if a[i] > a[i + 1]:
51-
a[i], a[i + 1] = a[i + 1], a[i]
47+
48+
# from right to left, doing the same
49+
# comparison as in the previous stage
50+
for i in range(end - 1, start - 1, -1):
51+
if arr[i] > arr[i + 1]:
52+
arr[i], arr[i + 1] = arr[i + 1], arr[i]
5253
swapped = True
53-
54-
# increase the starting point, because
55-
# the last stage would have moved the next
56-
# smallest number to its rightful spot.
54+
55+
# increase the starting point, because
56+
# the last stage would have moved the next
57+
# smallest number to its rightful spot.
5758
start = start + 1
59+
60+
return arr

pygorithm/sorting/gnome_sort.py

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,34 @@
33
last modified: 14-10-2019
44
'''
55

6-
'''
76

8-
Gnome Sort also called Stupid sort is based on the concept of a Garden Gnome sorting his flower pots.
9-
A garden gnome sorts the flower pots by the following method-
107

11-
He looks at the flower pot next to him and the previous one;
12-
if they are in the right order he steps one pot forward, otherwise he swaps them and steps one pot backwards.
13-
If there is no previous pot (he is at the starting of the pot line), he steps forwards;
14-
if there is no pot next to him (he is at the end of the pot line), he is done.
158

16-
'''
179

10+
# A function to sort the given list using Gnome sort
11+
def gnome_sort(arr):
12+
'''
13+
Gnome Sort also called Stupid sort is based on the concept of a Garden Gnome sorting his flower pots.
14+
A garden gnome sorts the flower pots by the following method-
1815
16+
He looks at the flower pot next to him and the previous one;
17+
if they are in the right order he steps one pot forward, otherwise he swaps them and steps one pot backwards.
18+
If there is no previous pot (he is at the starting of the pot line), he steps forwards;
19+
if there is no pot next to him (he is at the end of the pot line), he is done.
1920
20-
# A function to sort the given list using Gnome sort
21-
def gnome_sort( arr, n):
21+
This is an in-place sort.
22+
23+
:param arr: the array of values to sort
24+
:return: the sorted array, which is the same reference as arr
25+
'''
2226
index = 0
23-
while index < n:
24-
if index == 0:
27+
while index < len(arr):
28+
if index == 0:
2529
index = index + 1
26-
if arr[index] >= arr[index - 1]:
30+
elif arr[index] >= arr[index - 1]:
2731
index = index + 1
28-
else:
29-
arr[index], arr[index-1] = arr[index-1], arr[index]
32+
else:
33+
arr[index], arr[index - 1] = arr[index - 1], arr[index]
3034
index = index - 1
31-
35+
3236
return arr

pygorithm/sorting/tim_sort.py

Lines changed: 108 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,108 @@
1-
from insertion_sort import sort
2-
# iterative Timsort function to sort the
3-
# array[0...n-1] (similar to merge sort)
4-
def tim_sort(arr, n):
5-
6-
# Sort individual subarrays of size RUN
7-
for i in range(0, n, RUN):
8-
sort(arr, i, min((i+31), (n-1)))
9-
10-
# start merging from size RUN (or 32). It will merge
11-
# to form size 64, then 128, 256 and so on ....
12-
size = RUN
13-
while size < n:
14-
15-
# pick starting point of left sub array. We
16-
# are going to merge arr[left..left+size-1]
17-
# and arr[left+size, left+2*size-1]
18-
# After every merge, we increase left by 2*size
19-
for left in range(0, n, 2*size):
20-
21-
# find ending point of left sub array
22-
# mid+1 is starting point of right sub array
23-
mid = left + size - 1
24-
right = min((left + 2*size - 1), (n-1))
25-
26-
# merge sub array arr[left.....mid] &
27-
# arr[mid+1....right]
28-
merge(arr, left, mid, right)
29-
30-
size = 2*size
31-
32-
def merge(arr, l, m, r):
33-
34-
# original array is broken in two parts
35-
# left and right array
36-
len1, len2 = m - l + 1, r - m
37-
left, right = [], []
38-
for i in range(0, len1):
39-
left.append(arr[l + i])
40-
for i in range(0, len2):
41-
right.append(arr[m + 1 + i])
42-
43-
i, j, k = 0, 0, l
44-
# after comparing, we merge those two array
45-
# in larger sub array
46-
while i < len1 and j < len2:
47-
48-
if left[i] <= right[j]:
49-
arr[k] = left[i]
50-
i += 1
51-
52-
else:
53-
arr[k] = right[j]
54-
j += 1
55-
56-
k += 1
57-
58-
# copy remaining elements of left, if any
59-
while i < len1:
60-
61-
arr[k] = left[i]
62-
k += 1
63-
i += 1
64-
65-
# copy remaining element of right, if any
66-
while j < len2:
67-
arr[k] = right[j]
68-
k += 1
69-
j += 1
1+
def inplace_insertion_sort(arr, start_ind, end_ind):
2+
"""
3+
Performs an in-place insertion sort over a continuous slice of an
4+
array. A natural way to avoid this would be to use numpy arrays,
5+
where slicing does not copy.
6+
7+
This is in-place and has no result.
8+
9+
:param arr: the array to sort
10+
:param start_ind: the index to begin sorting at
11+
:param end_ind: the index to end sorting at. This index is excluded
12+
from the sort (i.e., len(arr) is ok)
13+
"""
14+
for i in range(start_ind + 1, end_ind):
15+
current_number = arr[i]
16+
17+
for j in range(i - 1, start_ind - 1, -1):
18+
if arr[j] > current_number:
19+
arr[j], arr[j + 1] = arr[j + 1], arr[j]
20+
else:
21+
arr[j + 1] = current_number
22+
break
23+
24+
25+
# iterative Timsort function to sort the
26+
# array[0...n-1] (similar to merge sort)
27+
def tim_sort(arr, run=32):
28+
"""
29+
Tim sort algorithm. See https://en.wikipedia.org/wiki/Timsort.
30+
This is performed in-place.
31+
32+
:param arr: list of values to sort
33+
:param run: the largest array that is sorted with an insertion sort.
34+
:return: the sorted array
35+
"""
36+
37+
# Sort individual subarrays of size run
38+
39+
for i in range(0, len(arr), run):
40+
inplace_insertion_sort(arr, i, min(i + run, len(arr)))
41+
42+
# start merging from size RUN (or 32). It will merge
43+
# to form size 64, then 128, 256 and so on ....
44+
size = run
45+
while size < len(arr):
46+
# pick starting point of left sub array. We
47+
# are going to merge arr[left..left+size-1]
48+
# and arr[left+size, left+2*size-1]
49+
# After every merge, we increase left by 2*size
50+
for left in range(0, len(arr), 2 * size):
51+
# find ending point of left sub array
52+
# mid+1 is starting point of right sub array
53+
mid = left + size
54+
right = min(left + (2 * size), len(arr))
55+
56+
# merge sub array arr[left.....mid] &
57+
# arr[mid+1....right]
58+
merge(arr, left, mid, right)
59+
60+
size = 2 * size
61+
return arr
62+
63+
def merge(arr, left, mid, right):
64+
"""
65+
Merge of two sections of array, both of which are individually
66+
sorted. The result is that the entire chunk is sorted. Note that right
67+
edges are exclusive (like slicing).
68+
69+
This modifies the passed array, but requires a complete copy of the array.
70+
71+
.. code:: python
72+
73+
merge([0, -1, 1, 3, 2, 4], 2, 4, 6) # [0, -1, 1, 2, 3, 4]
74+
75+
:param arr: the array which should have a portion sorted in-place
76+
:param left: the left-most index which is included in the merge
77+
:param mid: the first index that belongs to the second section
78+
:param right: the right-edge in the merge, which is not included in the sort.
79+
"""
80+
# original array is broken in two parts
81+
# left and right array
82+
left_arr = arr[left:mid]
83+
right_arr = arr[mid:right]
84+
85+
left_pos = 0
86+
right_pos = 0
87+
arr_ind = left
88+
# after comparing, we merge those two array
89+
# in larger sub array
90+
while left_pos < len(left_arr) and right_pos < len(right_arr):
91+
if left_arr[left_pos] <= right_arr[right_pos]:
92+
arr[arr_ind] = left_arr[left_pos]
93+
left_pos += 1
94+
else:
95+
arr[arr_ind] = right_arr[right_pos]
96+
right_pos += 1
97+
98+
arr_ind += 1
99+
100+
# copy remaining elements of left, if any
101+
for i in range(left_pos, len(left_arr)):
102+
arr[arr_ind] = left_arr[i]
103+
arr_ind += 1
104+
105+
# copy remaining element of right, if any
106+
for i in range(right_pos, len(right_arr)):
107+
arr[arr_ind] = right_arr[i]
108+
arr_ind += 1

0 commit comments

Comments
 (0)