Skip to content

Commit bdfbb44

Browse files
committed
cleanup, work on tests for sorting
1 parent e803b98 commit bdfbb44

3 files changed

Lines changed: 52 additions & 46 deletions

File tree

‎README.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ algorithms
3030
- Quicksort (Hoare partition scheme) :white_check_mark:
3131
- Quicksort (middle pivot) :x:
3232
- Insertion Sort :white_check_mark:
33+
- Selection Sort
3334
- search
3435
- Linear Search :white_check_mark:
3536
- Binary Search :white_check_mark:

‎examples/sort/quick.py‎

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1+
"""Some implementations of quicksort"""
12
import logging
23

34
logging.basicConfig(filename='quick_sort.log', format='%(asctime)s %(message)s', level=logging.DEBUG)
45

56

6-
class QuickSort(object):
7-
"""Some implementations of quicksort"""
7+
class QuickSort1(object):
8+
"""Implementation 1: first element pivot"""
89

910
@classmethod
1011
def _quicksort_partition(cls, lst, start, end):
@@ -71,23 +72,21 @@ def _quick(cls, lst, start, end):
7172
return lst
7273

7374
@classmethod
74-
def quick(cls, src_lst, start=0, end=None, inline=False):
75+
def quick(cls, lst, start=0, end=None):
7576
"""
7677
Original C.A.R Hoare Quicksort partition scheme implementation
7778
https://en.wikipedia.org/wiki/Quicksort#Hoare_partition_scheme
7879
"""
7980
if end is None:
80-
end = (len(src_lst) - 1)
81-
82-
# support for inline sorting vs returning a sorted copy
83-
if inline:
84-
lst = src_lst
85-
else:
86-
lst = copy.deepcopy(src_lst)
81+
end = (len(lst) - 1)
8782
return cls._quick(lst, start, end)
8883

84+
85+
class QuickSort2(object):
86+
"""Implementation 2: middle pivot"""
87+
8988
@classmethod
90-
def _quicksort_partition2(cls, lst, left, right):
89+
def _quicksort_partition(cls, lst, left, right):
9190
"""
9291
Internal partition and sorting method
9392
:param int left: start of partition
@@ -101,20 +100,19 @@ def _quicksort_partition2(cls, lst, left, right):
101100
# https://en.wikipedia.org/wiki/Quicksort#Choice_of_pivot
102101
# "median of three" pivot selection is also good
103102

104-
pivot_index = left + right // 2
103+
# middle, but protection from integer overflow
104+
pivot_index = left + (right-left) // 2
105105
logging.debug('pivot index: %s' % pivot_index)
106106

107107
pivot_value = lst[pivot_index]
108108
logging.debug('pivot value: %s' % pivot_value)
109109

110110
# for now the pivot element remains in its initial list position,
111111
# and elements will be index swapped (their indices switch)
112-
# relative to the pivot value, not the pivot's index
113-
112+
# relative to the pivot value
114113
swapping = True
115114
while swapping:
116-
init_left = left
117-
init_right = right
115+
118116
# with comparisons relative to the pivot,
119117
# "left pointer" index moves from left to right, and will stop on any element with a value not less than pivot value,
120118
# "right pointer" index moves from right to left, and will stop on any element with a value not greater than pivot value
@@ -135,9 +133,9 @@ def _quicksort_partition2(cls, lst, left, right):
135133
lst[left] = lst[right]
136134
lst[right] = tmp
137135

138-
# the end result is that all elements "less than or equal" are left of the last position of the left bracket,
136+
# the end result is that all elements "less than or equal" are left of the last position of the left pointer,
139137
# potentially unsorted
140-
# and all elements "greater than or equal" are right of the last position of the right bracket,
138+
# and all elements "greater than or equal" are right of the last position of the right pointer,
141139
# potentially unsorted
142140

143141
# Edge case: all elements are less than/equal pivot, e.g.: [5, 3, 7, 1, 3, 2]
@@ -152,7 +150,7 @@ def _quicksort_partition2(cls, lst, left, right):
152150
return left
153151

154152
@classmethod
155-
def _quick2(cls, lst, start, end):
153+
def _quick(cls, lst, start, end):
156154
"""Quicksort implementation for a list, internal method"""
157155
# this method is called recursively
158156
# on the left and right sections of each partition
@@ -163,19 +161,17 @@ def _quick2(cls, lst, start, end):
163161
if start < end:
164162
partition_index = cls._quicksort_partition(lst, start, end)
165163

166-
# what do we do when partition_index is the start or end?
164+
# what do we do when partition_index is the start VS end?
165+
# how to handle both situations?
167166

168-
logging.debug(
169-
'partition:',
170-
lst[start:partition_index],
171-
lst[partition_index+1, end]
172-
)
167+
logging.debug('partition:', lst[start:partition_index], lst[partition_index+1, end])
173168
cls._quick(lst, start, partition_index)
174169
cls._quick(lst, partition_index + 1, end)
170+
175171
return lst
176172

177173
@classmethod
178-
def quick2(cls, lst, start=0, end=None):
174+
def quick(cls, lst, start=0, end=None):
179175
"""
180176
Quicksort implementation 2,
181177
middle pivot selection

‎tests/sort.py‎

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,46 +3,55 @@
33
import unittest
44
from unittest import TestCase
55

6-
from examples.sort import Sort
6+
from examples.sort import bubble, insertion, merge, quick, selection
77

88

9-
# TODO
109
class TestSort(TestCase):
1110
"""Sort unit tests"""
1211

1312
def setUp(self):
14-
self.jumbled_int_list = [5, 2, 3, 1, 4, 8, 5, 9]
13+
self.jumbled_int_lists = (
14+
[9, 3, 1, 6, 4, 7, 7, 2, 0],
15+
[5, 2, 3, 1, 4, 8, 5, 9],
16+
[6, 3, 4, 1, 2, 7, 3],
17+
[5, 3, 7, 1, 3, 2],
18+
[1, 1, 1, 1, 1]
19+
)
1520

1621
def test_quick_sort(self):
17-
self.assertEqual(
18-
Sort.quick(jumbled_int_list),
19-
sort(jumbled_int_list)
20-
)
22+
for lst in jumbled_int_lists:
23+
self.assertEqual(
24+
quick.QuickSort1.quick(lst),
25+
sort(lst)
26+
)
2127

2228
def test_merge_sort(self):
2329
#self.assertEqual(
24-
# Sort.merge(jumbled_int_list),
30+
# merge.merge_sort(jumbled_int_list),
2531
# sort(jumbled_int_list)
2632
#)
2733
pass
2834

2935
def test_bubble_sort(self):
30-
self.assertEqual(
31-
Sort.bubble(jumbled_int_list),
32-
sort(jumbled_int_list)
33-
)
36+
for lst in jumbled_int_lists:
37+
self.assertEqual(
38+
bubble.bubble_sort(lst),
39+
sort(lst)
40+
)
3441

3542
def test_insertion_sort(self):
36-
self.assertEqual(
37-
Sort.insertion(jumbled_int_list),
38-
sort(jumbled_int_list)
39-
)
43+
for lst in jumbled_int_lists:
44+
self.assertEqual(
45+
insertion.insertion_sort(lst),
46+
sort(lst)
47+
)
4048

4149
def test_selection_sort(self):
42-
self.assertEqual(
43-
Sort.selection(jumbled_int_list),
44-
sort(jumbled_int_list)
45-
)
50+
for lst in jumbled_int_lists:
51+
self.assertEqual(
52+
selection.selection_sort(lst),
53+
sort(lst)
54+
)
4655

4756

4857
if __name__ == '__main__':

0 commit comments

Comments
 (0)