This commit is contained in:
Mari Wahl 2014-08-20 16:40:57 -04:00
parent aa5010594e
commit 7b9e953f5a
194 changed files with 28 additions and 34 deletions

View 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()

View file

@ -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()

View 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()

View file

@ -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()

View file

@ -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()

View file

@ -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
"""

View 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()

View 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
""""

View 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()

View file

@ -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()

View file

@ -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()

View file

@ -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()

View 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() 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()

View 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()

View file

@ -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()

View 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()

View 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

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View 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()

View file

@ -0,0 +1,5 @@
1
2
3
4
5

View file

@ -0,0 +1,4 @@
3
5
6
7

View file

@ -0,0 +1,4 @@
1
3
5
8

View 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()

View 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()

View 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()

View file

@ -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()