mirror of
https://github.com/autistic-symposium/master-algorithms-py.git
synced 2025-05-23 08:51:31 -04:00
fixes
This commit is contained in:
parent
aa5010594e
commit
7b9e953f5a
194 changed files with 28 additions and 34 deletions
0
src/searching_and_sorting/searching/__init__.py
Normal file
0
src/searching_and_sorting/searching/__init__.py
Normal file
49
src/searching_and_sorting/searching/binary_search.py
Normal file
49
src/searching_and_sorting/searching/binary_search.py
Normal file
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
|
||||
def binary_search(seq, key):
|
||||
''' binary search iterative algorithm '''
|
||||
''' observe that the index is returned '''
|
||||
hi = len(seq)
|
||||
lo = 0
|
||||
while lo < hi:
|
||||
mid = (hi+lo) // 2
|
||||
if seq[mid] == key:
|
||||
return mid
|
||||
elif key < seq[mid]:
|
||||
hi = mid
|
||||
else:
|
||||
lo = mid + 1
|
||||
return None
|
||||
|
||||
|
||||
def binary_search_rec(seq, key, lo=0, hi=None):
|
||||
''' binary search recursive algorithm '''
|
||||
hi = hi or len(seq)
|
||||
if hi < lo: return None
|
||||
mid = (hi + lo) // 2
|
||||
if seq[mid] == key:
|
||||
return mid
|
||||
elif seq[mid] < key:
|
||||
return binary_search_rec(seq, key, mid + 1, hi)
|
||||
else:
|
||||
return binary_search_rec(seq, key, lo, mid - 1)
|
||||
|
||||
|
||||
def test_binary_search():
|
||||
seq = [1,2,5,6,7,10,12,12,14,15]
|
||||
key = 6
|
||||
assert(binary_search(seq, key) == 3)
|
||||
assert(binary_search_rec(seq, key) == 3)
|
||||
print('Tests passed!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_binary_search()
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
def find_max_unimodal_array(A):
|
||||
if len(A) <= 2 : return None
|
||||
left = 0
|
||||
right = len(A)-1
|
||||
while right > left +1:
|
||||
mid = (left + right)//2
|
||||
if A[mid] > A[mid-1] and A[mid] > A[mid+1]:
|
||||
return A[mid]
|
||||
elif A[mid] > A[mid-1] and A[mid] < A[mid+1]:
|
||||
left = mid
|
||||
else:
|
||||
right = mid
|
||||
return None
|
||||
|
||||
|
||||
def test_find_max_unimodal_array():
|
||||
seq = [1, 2, 5, 6, 7, 10, 12, 9, 8, 7, 6]
|
||||
assert(find_max_unimodal_array(seq) == 12)
|
||||
print('Tests passed!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_find_max_unimodal_array()
|
||||
|
||||
|
||||
|
||||
|
35
src/searching_and_sorting/searching/find_sqrt_bin_search.py
Normal file
35
src/searching_and_sorting/searching/find_sqrt_bin_search.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
|
||||
def find_sqrt_bin_search(n, error=0.001):
|
||||
''' implement square root using binary search '''
|
||||
lower = n < 1 and n or 1
|
||||
upper = n < 1 and 1 or n
|
||||
mid = lower + (upper - lower) / 2.0
|
||||
square = mid * mid
|
||||
while abs(square - n) > error:
|
||||
if square < n:
|
||||
lower = mid
|
||||
else:
|
||||
upper = mid
|
||||
mid = lower + (upper - lower) / 2.0
|
||||
square = mid * mid
|
||||
return mid
|
||||
|
||||
|
||||
def test_ind_sqrt_bin_search():
|
||||
number = 9
|
||||
assert(find_sqrt_bin_search(number) == 3)
|
||||
print('Tests passed!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_ind_sqrt_bin_search()
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
def binary_serch_counting(lst1, k, lo=0, hi=None):
|
||||
if hi is None: hi = len(lst1)
|
||||
while lo < hi:
|
||||
mid = (lo+hi)//2
|
||||
midval = lst1[mid]
|
||||
if midval < k:
|
||||
lo = mid +1
|
||||
elif midval > k:
|
||||
hi = mid
|
||||
else:
|
||||
return mid
|
||||
return -1
|
||||
|
||||
|
||||
def find_time_occurrence_list(seq, k):
|
||||
""" find how many times a k element appears in a sorted list. One way of doing this is using
|
||||
collections.OrderedDict to no mess with the sorting, and add entries for every count. This
|
||||
should be O(n). It has a O(1) space complexity since the size of the dict is fixed.
|
||||
Another way, since the array is sorted, it to use binary search, since this is only O(logn).
|
||||
"""
|
||||
index_some_k = binary_serch_counting(seq, k)
|
||||
count = 1
|
||||
sizet = len(seq)
|
||||
|
||||
for i in range(index_some_k+1, sizet): # go up
|
||||
if seq[i] == k: count +=1
|
||||
else: break
|
||||
|
||||
for i in range(index_some_k-1, -1, -1): # go down
|
||||
if seq[i] == k: count +=1
|
||||
else: break
|
||||
|
||||
return count
|
||||
|
||||
|
||||
def test_find_time_occurrence_list():
|
||||
seq = [1,2,2,2,2,2,2,5,6,6,7,8,9]
|
||||
k = 2
|
||||
assert(find_time_occurrence_list(seq, k) == 6)
|
||||
print('Tests passed!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_find_time_occurrence_list()
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
''' using sets '''
|
||||
|
||||
def intersection_two_arrays_sets(seq1, seq2):
|
||||
''' find the intersection of two arrays using set proprieties '''
|
||||
set1 = set(seq1)
|
||||
set2 = set(seq2)
|
||||
return set1.intersection(set2) #same as list(set1 & set2
|
||||
|
||||
|
||||
|
||||
''' using merge sort '''
|
||||
|
||||
def intersection_two_arrays_ms(seq1, seq2):
|
||||
''' find the intersection of two arrays using merge sort '''
|
||||
res = []
|
||||
while seq1 and seq2:
|
||||
if seq1[-1] == seq2[-1]:
|
||||
res.append(seq1.pop())
|
||||
seq2.pop()
|
||||
elif seq1[-1] > seq2[-1]:
|
||||
seq1.pop()
|
||||
else:
|
||||
seq2.pop()
|
||||
res.reverse()
|
||||
return res
|
||||
|
||||
|
||||
|
||||
|
||||
''' using binary search '''
|
||||
|
||||
def binary_search(seq, key, lo=0, hi=None):
|
||||
''' binary search iterative algorithm '''
|
||||
hi = hi or len(seq)
|
||||
while lo < hi:
|
||||
mid = (hi+lo) // 2
|
||||
if seq[mid] == key:
|
||||
return True
|
||||
elif key > seq[mid]:
|
||||
lo = mid + 1
|
||||
else:
|
||||
hi = mid
|
||||
return None
|
||||
|
||||
def intersection_two_arrays_bs(seq1, seq2):
|
||||
''' if A small and B is too large, we can do a binary search on each entry in B '''
|
||||
''' only works if sorted and the small sequence has not larger nmbers!!!'''
|
||||
if len(seq1) > len(seq2): seq, key = seq1, seq2
|
||||
else: seq, key = seq2, seq1
|
||||
|
||||
intersec = []
|
||||
for item in key:
|
||||
if binary_search(seq, item):
|
||||
intersec.append(item)
|
||||
return intersec
|
||||
|
||||
|
||||
|
||||
def test_intersection_two_arrays(module_name='this module'):
|
||||
seq1 = [1,2,3,5,7,8]
|
||||
seq2 = [3,5,6]
|
||||
|
||||
assert(set(intersection_two_arrays_sets(seq1,seq2)) == set([3,5]))
|
||||
assert(intersection_two_arrays_bs(seq1,seq2) == [3,5])
|
||||
assert(intersection_two_arrays_ms(seq1,seq2) == [3,5])
|
||||
|
||||
s = 'Tests in {name} have {con}!'
|
||||
print(s.format(name=module_name, con='passed'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_intersection_two_arrays()
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
def ordered_sequential_search(seq, n):
|
||||
''' an example of sequential search in an ordered seq:
|
||||
it improves the performance if the item is not present '''
|
||||
item = 0
|
||||
for item in seq:
|
||||
if item > n: return False
|
||||
if item == n: return True
|
||||
return False
|
||||
|
||||
|
||||
def test_ordered_sequential_search(module_name='this module'):
|
||||
seq = [1, 2, 4, 5, 6, 8, 10]
|
||||
n1 = 10
|
||||
n2 = 7
|
||||
assert(ordered_sequential_search(seq, n1) == True)
|
||||
assert(ordered_sequential_search(seq, n2) == False)
|
||||
|
||||
s = 'Tests in {name} have {con}!'
|
||||
print(s.format(name=module_name, con='passed'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_ordered_sequential_search()
|
||||
|
||||
|
||||
"""
|
||||
Case Best Case Worst Case Average Case
|
||||
item is present 1 n n/2
|
||||
item not present 1 n n/2
|
||||
"""
|
49
src/searching_and_sorting/searching/searching_in_a_matrix.py
Normal file
49
src/searching_and_sorting/searching/searching_in_a_matrix.py
Normal file
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
import numpy
|
||||
|
||||
def searching_in_a_matrix(m1, value):
|
||||
""" searches an element in a matrix where in every row, the values are increasing from left to
|
||||
right, but the last number in a row is smaller than the first number in the next row.
|
||||
The naive brute force solution scan all numbers and cost O(nm). However, since the numbers are
|
||||
already sorted, the matrix can be viewed as a 1D sorted array. The binary search algorithm is
|
||||
suitable. The efficience is O(logmn)."""
|
||||
|
||||
rows = len(m1)
|
||||
cols = len(m1[0])
|
||||
lo = 0
|
||||
hi = rows*cols
|
||||
while lo < hi:
|
||||
mid = (lo + hi)//2
|
||||
row = mid//cols
|
||||
col = mid%cols
|
||||
v = m1[row][col]
|
||||
if v == value: return True
|
||||
elif v > value: hi = mid
|
||||
else: lo = mid+1
|
||||
return False
|
||||
|
||||
|
||||
|
||||
def test_searching_in_a_matrix():
|
||||
a = [[1,3,5],[7,9,11],[13,15,17]]
|
||||
b = numpy.array([(1,2),(3,4)])
|
||||
assert(searching_in_a_matrix(a, 13) == True)
|
||||
assert(searching_in_a_matrix(a, 14) == False)
|
||||
assert(searching_in_a_matrix(b, 3) == True)
|
||||
assert(searching_in_a_matrix(b, 5) == False)
|
||||
print('Tests passed!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_searching_in_a_matrix()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
32
src/searching_and_sorting/searching/sequential_search.py
Normal file
32
src/searching_and_sorting/searching/sequential_search.py
Normal file
|
@ -0,0 +1,32 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
def sequential_search(seq, n):
|
||||
''' an example of sequential search (for items stored in a collection) '''
|
||||
for item in seq:
|
||||
if item == n: return True
|
||||
return False
|
||||
|
||||
|
||||
def test_sequential_search(module_name='this module'):
|
||||
seq = [1, 5, 6, 8, 3]
|
||||
n1 = 5
|
||||
n2 = 7
|
||||
assert(sequential_search(seq, n1) == True)
|
||||
assert(sequential_search(seq, n2) == False)
|
||||
|
||||
s = 'Tests in {name} have {con}!'
|
||||
print(s.format(name=module_name, con='passed'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_sequential_search()
|
||||
|
||||
|
||||
"""
|
||||
Case Best Case Worst Case Average Case
|
||||
item is present 1 n n2
|
||||
item is not present n n n
|
||||
""""
|
112
src/searching_and_sorting/searching_adv/binary_search.py
Normal file
112
src/searching_and_sorting/searching_adv/binary_search.py
Normal file
|
@ -0,0 +1,112 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
''' A recursive and an iterative example of binary search in Python.
|
||||
Remember: sequence must be sorted! You can return True/False or the index:
|
||||
>>> l1 = [1, 2, 3, 4, 5, 6, 7]
|
||||
>>> binary_search_rec(l1, 1)
|
||||
0
|
||||
>>> binary_search_rec(l1, 2)
|
||||
1
|
||||
>>> binary_search_rec(l1, 3)
|
||||
2
|
||||
>>> binary_search_rec(l1, 4)
|
||||
3
|
||||
>>> binary_search_rec(l1, 5)
|
||||
4
|
||||
>>> binary_search_rec(l1, 6)
|
||||
5
|
||||
>>> binary_search_rec(l1, 7)
|
||||
6
|
||||
>>> binary_search_rec(l1, 8)
|
||||
>>> l1 = [1, 2, 3, 4, 5, 6]
|
||||
>>> binary_search_rec(l1, 1)
|
||||
0
|
||||
>>> binary_search_rec(l1, 2)
|
||||
1
|
||||
>>> binary_search_rec(l1, 3)
|
||||
2
|
||||
>>> binary_search_rec(l1, 4)
|
||||
3
|
||||
>>> binary_search_rec(l1, 5)
|
||||
4
|
||||
>>> binary_search_rec(l1, 6)
|
||||
5
|
||||
>>> binary_search_rec(l1, 7)
|
||||
>>> l1 = [1, 2, 3, 4, 5, 6, 7]
|
||||
>>> binary_search_iter(l1, 1)
|
||||
0
|
||||
>>> binary_search_iter(l1, 2)
|
||||
1
|
||||
>>> binary_search_iter(l1, 3)
|
||||
2
|
||||
>>> binary_search_iter(l1, 4)
|
||||
3
|
||||
>>> binary_search_iter(l1, 5)
|
||||
4
|
||||
>>> binary_search_iter(l1, 6)
|
||||
5
|
||||
>>> binary_search_iter(l1, 7)
|
||||
6
|
||||
>>> binary_search_iter(l1, 8)
|
||||
>>> l1 = [1, 2, 3, 4, 5, 6]
|
||||
>>> binary_search_iter(l1, 1)
|
||||
0
|
||||
>>> binary_search_iter(l1, 2)
|
||||
1
|
||||
>>> binary_search_iter(l1, 3)
|
||||
2
|
||||
>>> binary_search_iter(l1, 4)
|
||||
3
|
||||
>>> binary_search_iter(l1, 5)
|
||||
4
|
||||
>>> binary_search_iter(l1, 6)
|
||||
5
|
||||
>>> binary_search_iter(l1, 7)
|
||||
'''
|
||||
|
||||
|
||||
def binary_search_iter(seq, key):
|
||||
hi, lo = len(seq), 0
|
||||
while lo < hi: # here is <!
|
||||
mid = (hi+lo)//2
|
||||
if key == seq[mid]: return mid
|
||||
elif key < seq[mid]: hi = mid
|
||||
else: lo = mid + 1
|
||||
return None
|
||||
|
||||
|
||||
def bool_binary_search_iter(seq, key):
|
||||
hi, lo = len(seq), 0
|
||||
while lo < hi:
|
||||
mid = (hi+lo)//2
|
||||
if key == seq[mid]: return True
|
||||
elif key < seq[mid]: hi = mid
|
||||
else: lo = mid + 1
|
||||
return False
|
||||
|
||||
|
||||
def binary_search_rec(seq, key, lo=0, hi=None):
|
||||
hi = hi or len(seq)
|
||||
if hi <= lo: return None # base case: <= for odd and even numbers!
|
||||
mid = (hi + lo) // 2
|
||||
if key == seq[mid]: return mid
|
||||
elif key < seq[mid] : return binary_search_rec(seq, key, lo, mid) # include until mid-1
|
||||
else: return binary_search_rec(seq, key, mid+1, hi)
|
||||
|
||||
|
||||
def bool_binary_search_rec(seq, key, lo=0, hi=None):
|
||||
hi = hi or len(seq)
|
||||
if hi <= lo: return False # base case: <= for odd and even numbers!
|
||||
mid = (hi + lo) // 2
|
||||
if key == seq[mid]: return True
|
||||
elif key < seq[mid] : return bool_binary_search_rec(seq, key, lo, mid)
|
||||
else: return bool_binary_search_rec(seq, key, mid+1, hi)
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
|
@ -0,0 +1,76 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
''' Searches an element in a matrix where in every row, the values are increasing from left to right, but the last number in a row is smaller than the first number in the next row.
|
||||
|
||||
(1) The naive brute force solution (sequential search) scan all numbers and cost O(nm). However, since the numbers are already sorted, the matrix can be viewed as a 1D sorted array. The binary search algorithm is suitable. The efficiency is O(logmn).
|
||||
|
||||
>>> m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
|
||||
>>> binary_search_matrix_rec(m, 6)
|
||||
(1, 2)
|
||||
>>> binary_search_matrix_rec(m, 12)
|
||||
>>> binary_search_matrix_iter(m, 6)
|
||||
(1, 2)
|
||||
>>> binary_search_matrix_iter(m, 12)
|
||||
>>> binary_search_matrix_iter(m, 1)
|
||||
(0, 0)
|
||||
|
||||
(2) Another solution is "discarding" arrays in the way. The efficiency is O(logm).
|
||||
>>> m = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
|
||||
>>> searching_matrix(m, 6)
|
||||
(1, 2)
|
||||
>>> searching_matrix(m, 12)
|
||||
|
||||
'''
|
||||
|
||||
|
||||
def binary_search_matrix_rec(m, key, lo=0, hi=None):
|
||||
if not m: return None
|
||||
rows = len(m)
|
||||
cols = len(m[0])
|
||||
hi = hi or rows*cols
|
||||
if hi > lo: # -----> REMEMBER THIS OR INDEX WILL EXPLODE!!!!!!!!
|
||||
mid = (hi + lo)//2
|
||||
row = mid//cols
|
||||
col = mid%cols
|
||||
item = m[row][col]
|
||||
if key == item: return row, col
|
||||
elif key < item: return binary_search_matrix_rec(m, key, lo, mid-1)
|
||||
else: return binary_search_matrix_rec(m, key, mid+1, hi)
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def binary_search_matrix_iter(m, key):
|
||||
if not m: return None
|
||||
rows = len(m)
|
||||
cols = len(m[0])
|
||||
lo, hi = 0, rows*cols
|
||||
while lo < hi:
|
||||
mid = (hi + lo)//2
|
||||
row = mid//rows
|
||||
col = mid%rows
|
||||
item = m[row][col]
|
||||
if key == item: return (row, col)
|
||||
elif key < item: hi = mid
|
||||
else: lo = mid +1
|
||||
return None
|
||||
|
||||
|
||||
def searching_matrix(m, key):
|
||||
if not m: return None
|
||||
rows = len(m)
|
||||
cols = len(m[0])
|
||||
i, j = 0, cols -1
|
||||
while i < rows and j > 0:
|
||||
item = m[i][j]
|
||||
if key == item: return (i, j)
|
||||
elif key < item: j -= 1
|
||||
else: i += 1
|
||||
return None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
|
@ -0,0 +1,56 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
''' Given a sorted array that was rotated, find an item with binary search:
|
||||
>>> l1 = [3, 4, 5, 6, 7, 1, 2]
|
||||
>>> find_element_rot_array(l1, 7)
|
||||
4
|
||||
>>> find_element_rot_array(l1, 3)
|
||||
0
|
||||
>>> find_element_rot_array(l1, 4)
|
||||
1
|
||||
>>> find_element_rot_array(l1, 5)
|
||||
2
|
||||
>>> find_element_rot_array(l1, 6)
|
||||
3
|
||||
>>> find_element_rot_array(l1, 1)
|
||||
5
|
||||
>>> find_element_rot_array(l1, 2)
|
||||
6
|
||||
>>> find_element_rot_array(l1, 8)
|
||||
|
||||
'''
|
||||
|
||||
def find_element_rot_array(seq, key, lo=0, hi=None):
|
||||
hi = hi or len(seq)
|
||||
if hi <= lo: return None # base case: <= for odd and even numbers!
|
||||
mid = (hi + lo) // 2
|
||||
if key == seq[mid]: return mid
|
||||
|
||||
# if left is ordered --> we work here
|
||||
if seq[lo] <= seq[mid]:
|
||||
# now, is the key there?
|
||||
if key < seq[mid] and key >= seq[lo]:
|
||||
return find_element_rot_array(seq, key, lo, mid)
|
||||
else:
|
||||
# all the other cases
|
||||
return find_element_rot_array(seq, key, mid+1, hi)
|
||||
|
||||
# right is ordered --> we work here
|
||||
else:
|
||||
# now, is the key there?
|
||||
if key > seq[mid] and key <= seq[hi-1]: # stupid hi-1!!!
|
||||
return find_element_rot_array(seq, key, mid+1, hi)
|
||||
else:
|
||||
# all the other cases
|
||||
return find_element_rot_array(seq, key, lo, mid)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
''' Given a sorted an array with empty strings, we use binary search to find some string (since
|
||||
the list is sorted):
|
||||
--> we deal with the empty strings with strip and then run to left and right, or move
|
||||
mid to the closed non-empty str (remember that the index must be conserved):
|
||||
>>> l1 = ['acre', 'ball', '', 'coach', '', 'cut', '']
|
||||
>>> find_str_array_with_empty_str(l1, l1[0])
|
||||
0
|
||||
>>> find_str_array_with_empty_str(l1, l1[1])
|
||||
1
|
||||
>>> find_str_array_with_empty_str(l1, l1[3])
|
||||
3
|
||||
>>> find_str_array_with_empty_str(l1, l1[5])
|
||||
5
|
||||
>>> find_str_array_with_empty_str(l1, 'bla')
|
||||
'''
|
||||
|
||||
|
||||
def find_str_array_with_empty_str(seq, s1):
|
||||
if not seq or not s1: return None
|
||||
hi = len(seq)
|
||||
lo = 0
|
||||
while hi > lo:
|
||||
mid = (hi+lo)//2
|
||||
|
||||
if seq[mid] == '':
|
||||
while True:
|
||||
left = mid-1
|
||||
right = mid+1
|
||||
if left < lo or right > hi: return None
|
||||
elif right < hi and seq[right]:
|
||||
mid = right
|
||||
break
|
||||
elif left > lo and seq[left]:
|
||||
mid = left
|
||||
break
|
||||
right += 1
|
||||
left -= 1
|
||||
|
||||
if s1 == seq[mid] == s1: return mid
|
||||
elif s1 < seq[mid]: hi = mid
|
||||
else: lo = mid + 1
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
0
src/searching_and_sorting/sorting/__init__.py
Normal file
0
src/searching_and_sorting/sorting/__init__.py
Normal file
37
src/searching_and_sorting/sorting/bubble_sort.py
Normal file
37
src/searching_and_sorting/sorting/bubble_sort.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
# Mari von Steinkirch @ 2013
|
||||
# mari.wahl9@gmail.com
|
||||
|
||||
# Bernardo Sulzbach (mafagafo) @ 2014
|
||||
# 1449441@gmail.com
|
||||
|
||||
|
||||
def bubble_sort(seq):
|
||||
"""
|
||||
Implementation of bubble sort.
|
||||
O(n²) and thus highly ineffective.
|
||||
:param seq: the sequence to be sorted.
|
||||
:return: the sorted sequence.
|
||||
"""
|
||||
size = len(seq) -1
|
||||
for num in range(size, 0, -1):
|
||||
for i in range(num):
|
||||
if seq[i] > seq[i+1]:
|
||||
temp = seq[i]
|
||||
seq[i] = seq[i+1]
|
||||
seq[i+1] = temp
|
||||
return seq
|
||||
|
||||
|
||||
def test_bubble_sort(module_name='this module'):
|
||||
seq = [4, 5, 2, 1, 6, 2, 7, 10, 13, 8]
|
||||
assert(bubble_sort(seq) == sorted(seq))
|
||||
|
||||
s = 'Tests in {name} have {con}!'
|
||||
print(s.format(name=module_name, con='passed'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_bubble_sort()
|
||||
|
27
src/searching_and_sorting/sorting/count_sort.py
Normal file
27
src/searching_and_sorting/sorting/count_sort.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
def count_sort_dict(a):
|
||||
''' an example of counting sort using default dictionaries '''
|
||||
b, c = [], defaultdict(list)
|
||||
for x in a:
|
||||
c[x].append(x) # we could have used key = lambda x:x
|
||||
for k in range(min(c), max(c) + 1):
|
||||
b.extend(c[k])
|
||||
return b
|
||||
|
||||
|
||||
def test_count_sort():
|
||||
seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2, 5, 4, 1, 5, 3]
|
||||
assert(count_sort_dict(seq) == sorted(seq))
|
||||
print('Tests passed!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_count_sort()
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
import random
|
||||
|
||||
def swap(A, x, y):
|
||||
tmp = A[x]
|
||||
A[x] = A[y]
|
||||
A[y] = tmp
|
||||
|
||||
|
||||
def qselect(A, k, left=None, right=None):
|
||||
left = left or 0
|
||||
right = right or len(A) - 1
|
||||
pivot = random.randint(left, right)
|
||||
pivotVal = A[pivot]
|
||||
|
||||
# Move pivot out of the sorting range
|
||||
swap(A, pivot, right)
|
||||
swapIndex, i = left, left
|
||||
while i <= right - 1:
|
||||
if A[i] < pivotVal:
|
||||
swap(A, i, swapIndex)
|
||||
swapIndex += 1
|
||||
i += 1
|
||||
|
||||
# Move pivot to final position
|
||||
swap(A, right, swapIndex)
|
||||
|
||||
# Check if pivot matches, else recurse on the correct half
|
||||
rank = len(A) - swapIndex
|
||||
if k == rank:
|
||||
return A[swapIndex]
|
||||
elif k < rank:
|
||||
return qselect(A, k, left=swapIndex+1, right=right)
|
||||
else:
|
||||
return qselect(A, k, left=left, right=swapIndex-1)
|
||||
|
||||
|
||||
|
||||
def find_k_largest_seq_quickselect(seq, k):
|
||||
''' perform quick select to get kth element, and find all elements larger '''
|
||||
kth_largest = qselect(seq, k)
|
||||
result = []
|
||||
for item in seq:
|
||||
if item >= kth_largest:
|
||||
result.append(item)
|
||||
return result
|
||||
|
||||
|
||||
|
||||
def test_find_k_largest_seq_quickselect():
|
||||
seq = [3, 10, 4, 5, 1, 8, 9, 11, 5]
|
||||
k = 2
|
||||
assert(find_k_largest_seq_quickselect(seq,k) == [10, 11])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_find_k_largest_seq_quickselect()
|
||||
|
35
src/searching_and_sorting/sorting/gnome_sort.py
Normal file
35
src/searching_and_sorting/sorting/gnome_sort.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
from do_benchmark import benchmark
|
||||
|
||||
@benchmark
|
||||
def gnome_sort(seq):
|
||||
''' sort a sequence using the gnome sort alg '''
|
||||
i = 0
|
||||
while i < len(seq):
|
||||
if i ==0 or seq[i-1] <= seq[i]:
|
||||
i += 1
|
||||
else:
|
||||
seq[i], seq[i-1] = seq[i-1], seq[i]
|
||||
i -= 1
|
||||
return seq
|
||||
|
||||
|
||||
def test_gnome_sort():
|
||||
seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2, 5, 4, 1, 5, 3]
|
||||
assert(gnome_sort(seq) == sorted(seq))
|
||||
print('Tests passed!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_gnome_sort()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
44
src/searching_and_sorting/sorting/heap.py
Normal file
44
src/searching_and_sorting/sorting/heap.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
class Heap(object):
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
for i in range(len(data)/2, -1, -1):
|
||||
self.__max_heapify__(i)
|
||||
|
||||
|
||||
def parent(self, i):
|
||||
return i >> 1
|
||||
|
||||
|
||||
def left_child(self, i):
|
||||
return (i << 1) + 1
|
||||
|
||||
|
||||
def right_child(self, i):
|
||||
return (i << 1) + 2 # +2 instead of +1 because it's 0-indexed.
|
||||
|
||||
|
||||
def __max_heapify__(self, i):
|
||||
largest = i
|
||||
left = self.left_child(i)
|
||||
right = self.right_child(i)
|
||||
n = len(self.data)
|
||||
largest = (left < n and self.data[left] > self.data[i]) and left or i
|
||||
largest = (right < n and self.data[right] > self.data[largest]) and right or largest
|
||||
if i != largest:
|
||||
self.data[i], self.data[largest] = self.data[largest], self.data[i]
|
||||
self.__max_heapify__(largest)
|
||||
|
||||
|
||||
def extract_max(self):
|
||||
n = len(self.data)
|
||||
max_element = self.data[0]
|
||||
self.data[0] = self.data[n - 1]
|
||||
self.data = self.data[:n - 1]
|
||||
self.__max_heapify__(0)
|
||||
return max_element
|
||||
|
||||
|
23
src/searching_and_sorting/sorting/heap_sort1.py
Normal file
23
src/searching_and_sorting/sorting/heap_sort1.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
import heapq
|
||||
|
||||
def heap_sort1(seq):
|
||||
''' heap sort with Python's heapq '''
|
||||
h = []
|
||||
for value in seq:
|
||||
heapq.heappush(h, value)
|
||||
return [heapq.heappop(h) for i in range(len(h))]
|
||||
|
||||
|
||||
def test_heap_sort1():
|
||||
seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2]
|
||||
assert(heap_sort1(seq) == sorted(seq))
|
||||
print('Tests passed!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_heap_sort1()
|
||||
|
24
src/searching_and_sorting/sorting/heap_sort2.py
Normal file
24
src/searching_and_sorting/sorting/heap_sort2.py
Normal file
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
from heap import Heap
|
||||
|
||||
def heap_sort2(seq):
|
||||
heap = Heap(seq)
|
||||
|
||||
res = []
|
||||
for i in range(len(seq)):
|
||||
res.insert(0, heap.extract_max())
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def test_heap_sort2():
|
||||
seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2]
|
||||
assert(heap_sort2(seq) == sorted(seq))
|
||||
print('Tests passed!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_heap_sort2()
|
36
src/searching_and_sorting/sorting/heap_sort3.py
Normal file
36
src/searching_and_sorting/sorting/heap_sort3.py
Normal file
|
@ -0,0 +1,36 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
def heap_sort3(seq):
|
||||
for start in range((len(seq)-2)//2, -1, -1):
|
||||
siftdown(seq, start, len(seq)-1)
|
||||
for end in range(len(seq)-1, 0, -1):
|
||||
seq[end], seq[0] = seq[0], seq[end]
|
||||
siftdown(seq, 0, end - 1)
|
||||
return seq
|
||||
|
||||
def siftdown(seq, start, end):
|
||||
root = start
|
||||
while True:
|
||||
child = root * 2 + 1
|
||||
if child > end: break
|
||||
if child + 1 <= end and seq[child] < seq[child + 1]:
|
||||
child += 1
|
||||
if seq[root] < seq[child]:
|
||||
seq[root], seq[child] = seq[child], seq[root]
|
||||
root = child
|
||||
else:
|
||||
break
|
||||
|
||||
|
||||
|
||||
def test_heap_sort():
|
||||
seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2]
|
||||
assert(heap_sort3(seq) == sorted(seq))
|
||||
print('Tests passed!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_heap_sort3()
|
||||
|
44
src/searching_and_sorting/sorting/insertion_sort.py
Normal file
44
src/searching_and_sorting/sorting/insertion_sort.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
|
||||
def insertion_sort(seq):
|
||||
''' sort a sequence using the insertion sort alg '''
|
||||
for i in range(1, len(seq)):
|
||||
j = i
|
||||
while j > 0 and seq[j-1] > seq[j]:
|
||||
seq[j-1], seq[j] = seq[j], seq[j-1]
|
||||
j -= 1
|
||||
return seq
|
||||
|
||||
|
||||
def insertion_sort_rec(seq, i = None):
|
||||
''' sort a sequence using the recursive insertion sort alg '''
|
||||
if i == None: i = len(seq) -1
|
||||
if i == 0: return i
|
||||
insertion_sort_rec(seq, i-1)
|
||||
j = i
|
||||
while j > 0 and seq[j-i] > seq[j]:
|
||||
seq[j-1], seq[j] = seq[j], seq[j-1]
|
||||
j -= 1
|
||||
return seq
|
||||
|
||||
|
||||
def test_insertion_sort():
|
||||
seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2, 5, 4, 1, 5, 3]
|
||||
assert(insertion_sort(seq) == sorted(seq))
|
||||
assert(insertion_sort_rec(seq) == sorted(seq))
|
||||
print('Tests passed!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_insertion_sort()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
33
src/searching_and_sorting/sorting/merge_sort.py
Normal file
33
src/searching_and_sorting/sorting/merge_sort.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
|
||||
def merge_sort(seq):
|
||||
if len(seq) <= 1: return seq
|
||||
mid = len(seq)//2
|
||||
lft, rgt = seq[:mid], seq[mid:]
|
||||
if len(lft)>1: lft = merge_sort(lft)
|
||||
if len(rgt)>1: rgt = merge_sort(rgt)
|
||||
|
||||
res = []
|
||||
while lft and rgt:
|
||||
if lft [-1]>= rgt[-1]:
|
||||
res.append(lft.pop())
|
||||
else:
|
||||
res.append(rgt.pop())
|
||||
res.reverse()
|
||||
return(lft or rgt) + res
|
||||
|
||||
|
||||
|
||||
|
||||
def test_merge_sort():
|
||||
seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2]
|
||||
assert(merge_sort(seq) == sorted(seq))
|
||||
print('Tests passed!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_merge_sort()
|
42
src/searching_and_sorting/sorting/quick_sort.py
Normal file
42
src/searching_and_sorting/sorting/quick_sort.py
Normal file
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
|
||||
def quick_sort(seq):
|
||||
if len(seq) < 2: return seq
|
||||
pivot = sorted(seq[0], seq[len(seq)//2], seq[-1])[1]
|
||||
print(pivot)
|
||||
left = quick_sort([x for x in seq[1:] if x < pivot])
|
||||
right = quick_sort([x for x in seq[1:] if x >= pivot])
|
||||
return left + [pivot] + right
|
||||
|
||||
|
||||
""" we can also divide them into two functions """
|
||||
def partition(seq):
|
||||
pi,seq = seq[0],seq[1:]
|
||||
lo = [x for x in seq if x <= pi]
|
||||
hi = [x for x in seq if x > pi]
|
||||
return lo, pi, hi
|
||||
|
||||
def quick_sort_divided(seq):
|
||||
if len(seq) < 2: return seq
|
||||
lo, pi, hi = partition(seq)
|
||||
return quick_sort_divided(lo) + [pi] + quick_sort_divided(hi)
|
||||
|
||||
|
||||
|
||||
|
||||
def test_quick_sort():
|
||||
seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2]
|
||||
assert(quick_sort(seq) == sorted(seq))
|
||||
assert(quick_sort_divided(seq) == sorted(seq))
|
||||
print('Tests passed!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_quick_sort()
|
||||
|
||||
|
||||
|
31
src/searching_and_sorting/sorting/selection_sort.py
Normal file
31
src/searching_and_sorting/sorting/selection_sort.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
def selection_sort(seq):
|
||||
''' sort a sequence using the selection sort alg '''
|
||||
for i in range(len(seq) -1, 0, -1):
|
||||
max_j = i
|
||||
for j in range(max_j):
|
||||
if seq[j] > seq[max_j]:
|
||||
max_j = j
|
||||
seq[i], seq[max_j] = seq[max_j], seq[i]
|
||||
return seq
|
||||
|
||||
|
||||
def test_selection_sort():
|
||||
seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2]
|
||||
assert(selection_sort(seq) == sorted(seq))
|
||||
print('Tests passed!')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_selection_sort()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
5
src/searching_and_sorting/sorting_adv/1.dat
Normal file
5
src/searching_and_sorting/sorting_adv/1.dat
Normal file
|
@ -0,0 +1,5 @@
|
|||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
4
src/searching_and_sorting/sorting_adv/2.dat
Normal file
4
src/searching_and_sorting/sorting_adv/2.dat
Normal file
|
@ -0,0 +1,4 @@
|
|||
3
|
||||
5
|
||||
6
|
||||
7
|
4
src/searching_and_sorting/sorting_adv/3.dat
Normal file
4
src/searching_and_sorting/sorting_adv/3.dat
Normal file
|
@ -0,0 +1,4 @@
|
|||
1
|
||||
3
|
||||
5
|
||||
8
|
70
src/searching_and_sorting/sorting_adv/merge_sort.py
Normal file
70
src/searching_and_sorting/sorting_adv/merge_sort.py
Normal file
|
@ -0,0 +1,70 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
''' Some examples of how to implement Merge Sort in Python
|
||||
--> RUNTIME: WORST/BEST/AVERAGE Is O(nlogn)
|
||||
--> space complexity is O(n) for arrays
|
||||
--> not in place, good for large arrays
|
||||
>>> seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2]
|
||||
>>> merge_sort(seq) == sorted(seq)
|
||||
True
|
||||
>>> seq2 = [3, 3, 3, 3, 3, 3, 3, 3]
|
||||
>>> merge_sort(seq2) == sorted(seq2)
|
||||
True
|
||||
>>> seq3 = []
|
||||
>>> merge_sort(seq3) == sorted(seq3)
|
||||
True
|
||||
'''
|
||||
|
||||
''' This is the main function that keep dividing the seq '''
|
||||
def merge_sort(seq):
|
||||
if len(seq) < 2 : return seq # base case
|
||||
mid = len(seq)//2
|
||||
left, right = None, None # we could have declared the arrays here,
|
||||
# but this would allocate unecessary extra space
|
||||
if seq[:mid]: left = merge_sort(seq[:mid])
|
||||
if seq[mid:]: right = merge_sort(seq[mid:]) # notice that mid is included!
|
||||
|
||||
return merge(left, right) # merge iteratively
|
||||
|
||||
|
||||
''' The two following merge functions are O(2n)=O(n) and O(n) respectively. They
|
||||
illustrate many features in Python that '''
|
||||
def merge_2n(left, right):
|
||||
if not left or not right: return left or right # nothing to be merged
|
||||
result = []
|
||||
while left and right:
|
||||
if left[-1] >= right[-1]:
|
||||
result.append(left.pop())
|
||||
else:
|
||||
result.append(right.pop())
|
||||
result.reverse()
|
||||
return (left or right) + result
|
||||
|
||||
|
||||
def merge(left, right):
|
||||
if not left or not right: return left or right # nothing to be merged
|
||||
result = []
|
||||
i, j = 0, 0
|
||||
while i < len(left) and j < len(right):
|
||||
if left[i] <= right[j]:
|
||||
result.append(left[i])
|
||||
i += 1
|
||||
else:
|
||||
result.append(right[j])
|
||||
j += 1
|
||||
if left[i:] : result.extend(left[i:]) # REMEMBER TO TO ENXTEND NOT APPEND
|
||||
if right[j:] : result.extend(right[j:])
|
||||
return result
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
|
95
src/searching_and_sorting/sorting_adv/merge_sorted_things.py
Normal file
95
src/searching_and_sorting/sorting_adv/merge_sorted_things.py
Normal file
|
@ -0,0 +1,95 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
''' --> In the case of two arrays: we can merge two arrays using the merge function from the merge sort
|
||||
--> we can do this for files too, merging each two
|
||||
|
||||
1) If we can modify the arrays (pop) we can use:
|
||||
def merge(left, right):
|
||||
if not left or not right: return left or right # nothing to be merged
|
||||
result = []
|
||||
while left and right:
|
||||
if left[-1] >= right[-1]:
|
||||
result.append(left.pop())
|
||||
else:
|
||||
result.append(right.pop())
|
||||
result.reverse()
|
||||
return (left or right) + result
|
||||
|
||||
|
||||
2) If we can't modify or we want to in place, we need two pointers:
|
||||
>>> l1 = [1, 2, 3, 4, 5, 6, 7]
|
||||
>>> l2 = [2, 4, 5, 8]
|
||||
>>> merge(l1, l2)
|
||||
[1, 2, 2, 3, 4, 4, 5, 5, 6, 7, 8]
|
||||
|
||||
|
||||
3) For example, in the case we have a big array filled 0s in the end, and another array with the size of the number of 0s:
|
||||
>>> l1 = [1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0]
|
||||
>>> l2 = [2, 4, 5, 8]
|
||||
>>> merge_two_arrays_inplace(l1, l2)
|
||||
[1, 2, 2, 3, 4, 4, 5, 5, 6, 7, 8]
|
||||
|
||||
|
||||
4) If we want to merge sorted files (and we have plenty of RAM to load all files):
|
||||
>>> list_files = ['1.dat', '2.dat', '3.dat']
|
||||
>>> merge_files(list_files)
|
||||
[1, 1, 2, 3, 3, 3, 4, 5, 5, 5, 6, 7, 8]
|
||||
'''
|
||||
|
||||
def merge(left, right):
|
||||
if not left or not right: return left or right # nothing to be merged
|
||||
result = []
|
||||
i, j = 0, 0
|
||||
while i < len(left) and j < len(right):
|
||||
if left[i] <= right[j]:
|
||||
result.append(left[i])
|
||||
i += 1
|
||||
else:
|
||||
result.append(right[j])
|
||||
j += 1
|
||||
if left[i:] : result.extend(left[i:]) # REMEMBER TO TO ENXTEND NOT APPEND
|
||||
if right[j:] : result.extend(right[j:])
|
||||
return result
|
||||
|
||||
|
||||
|
||||
def merge_two_arrays_inplace(l1, l2):
|
||||
if not l1 or not l2: return l1 or l2 # nothing to be merged
|
||||
p2 = len(l2) - 1
|
||||
p1 = len(l1) - len(l2) - 1
|
||||
p12 = len(l1) - 1
|
||||
while p2 >= 0 and p1 >= 0:
|
||||
item_to_be_merged = l2[p2]
|
||||
item_bigger_array = l1[p1]
|
||||
if item_to_be_merged < item_bigger_array:
|
||||
l1[p12] = item_bigger_array
|
||||
p1 -= 1
|
||||
else:
|
||||
l1[p12] = item_to_be_merged
|
||||
p2 -= 1
|
||||
p12 -= 1
|
||||
return l1
|
||||
|
||||
|
||||
def merge_files(list_files):
|
||||
result = []
|
||||
final = []
|
||||
for filename in list_files:
|
||||
aux = []
|
||||
with open(filename, 'r') as file:
|
||||
for line in file:
|
||||
aux.append(int(line))
|
||||
result.append(aux)
|
||||
final.extend(result.pop())
|
||||
for l in result:
|
||||
final = merge(l, final)
|
||||
return final
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
|
74
src/searching_and_sorting/sorting_adv/quick_sort.py
Normal file
74
src/searching_and_sorting/sorting_adv/quick_sort.py
Normal file
|
@ -0,0 +1,74 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
|
||||
''' Some examples of how to implement Quick Sort in Python
|
||||
--> RUNTIME: BEST/AVERAGE Is O(nlogn), WORST is O(n2)
|
||||
--> the first example is not in place, the second is in place
|
||||
--> test with two element arrays, identical values
|
||||
|
||||
Quick sort in place:
|
||||
1) select pivot as the index = 0
|
||||
2) start pointer1 at index = 1 and pointer2 in the last element
|
||||
3) while pointer1 < pointer2:
|
||||
if value in pointer1 <= pivot
|
||||
swap value in pointer1 with value in pointer2 and advanced pointer2
|
||||
else
|
||||
advance pointer1
|
||||
4) now the array is like this:
|
||||
[pivot, larger than pivot, smaller than pivot]
|
||||
5) swap the pivot where pointer 1 stop
|
||||
6) do recursively for [smaller] + [pivot] + [larger]
|
||||
|
||||
>>> seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2]
|
||||
>>> quick_sort(seq) == sorted(seq)
|
||||
True
|
||||
>>> quick_sort([3, 3, 3, 3, 3, 3]) == [3, 3, 3, 3, 3, 3]
|
||||
True
|
||||
>>> quick_sort([]) == []
|
||||
True
|
||||
>>> quick_sort([2,1]) == [1, 2]
|
||||
True
|
||||
>>> quick_sort_in(seq) == sorted(seq)
|
||||
True
|
||||
>>> quick_sort_in([3, 3, 3, 3, 3, 3]) == [3, 3, 3, 3, 3, 3]
|
||||
True
|
||||
>>> quick_sort_in([]) == []
|
||||
True
|
||||
>>> quick_sort_in([2,1]) == [1, 2]
|
||||
True
|
||||
'''
|
||||
|
||||
def quick_sort(seq):
|
||||
if len(seq) < 2 : return seq
|
||||
mid = len(seq)//2
|
||||
pi = seq[mid]
|
||||
seq = seq[:mid] + seq[mid+1:]
|
||||
left = quick_sort([x for x in seq if x <= pi]) # REMEMBER TO INCLUDE X (OR IN RIGHT)
|
||||
right = quick_sort([x for x in seq if x > pi])
|
||||
return left + [pi] + right
|
||||
|
||||
|
||||
|
||||
|
||||
def quick_sort_in(seq):
|
||||
if len(seq) < 2 : return seq
|
||||
if len(seq) == 2 and seq[0] > seq[1]:
|
||||
seq[0], seq[1] = seq[1], seq[0] # problems when only 2 elements because of swap
|
||||
pivot = seq[0] # start at the ends because we don't know how many elements
|
||||
p1, p2 = 1, len(seq) -1 # set pointers at both ends
|
||||
while p1 < p2: # must be < or out of range
|
||||
if seq[p1] <= pivot: # must be <= because of pivot swap
|
||||
seq[p1], seq[p2] = seq[p2], seq[p1]
|
||||
p2 -= 1
|
||||
else:
|
||||
p1 += 1
|
||||
seq[0], seq[p1] = seq[p1], pivot
|
||||
return quick_sort_in(seq[p1+1:]) + [seq[p1]] + quick_sort_in(seq[:p1])
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
|
@ -0,0 +1,35 @@
|
|||
#!/usr/bin/python3
|
||||
# mari von steinkirch @2013
|
||||
# steinkirch at gmail
|
||||
|
||||
''' A method to sort an array so that all the anagrams are together. Since we only
|
||||
want the anagrams to be grouped, we can use a dictionary for this task. This
|
||||
algorithm is O(n).
|
||||
>>> l1 = ['hat', 'ball', 'tha', 'cut', 'labl', 'hta', 'cool', 'cuy', 'uct']
|
||||
>>> sort_anagrams_together(l1)
|
||||
['cut', 'uct', 'cool', 'ball', 'labl', 'hat', 'tha', 'hta', 'cuy']
|
||||
'''
|
||||
|
||||
from collections import defaultdict
|
||||
def sort_anagrams_together(l1):
|
||||
result = []
|
||||
|
||||
# step 1 save the anagrams together
|
||||
dict_aux = defaultdict(list) # rememebr to indicate the type
|
||||
for word in l1:
|
||||
key = ''.join(sorted(word)) # need to sort the strings and join it
|
||||
dict_aux[key].append(word) # because only sorted give a list of each char
|
||||
|
||||
# step 2 print the anagrams. Note that if you want everything
|
||||
# sorted you would have to sort the keys and insert the angrams after that
|
||||
for key in dict_aux:
|
||||
result.extend(dict_aux[key])
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue