diff --git a/book/book_second_edition.pdf b/book/book_second_edition.pdf index fcc036c..82b0f38 100644 Binary files a/book/book_second_edition.pdf and b/book/book_second_edition.pdf differ diff --git a/src/neat_builtin_examples/lists_and_strings/reverse_words_sentence.py b/src/neat_builtin_examples/lists_and_strings/reverse_words_sentence.py index 46c9acf..5fcee65 100644 --- a/src/neat_builtin_examples/lists_and_strings/reverse_words_sentence.py +++ b/src/neat_builtin_examples/lists_and_strings/reverse_words_sentence.py @@ -43,7 +43,6 @@ def reversing_words_setence_logic(string1): reverser(string1) p = 0 start = 0 - final = [] while p < len(string1): if string1[p] == u"\u0020": reverser(string1,start,p-1) diff --git a/src/searching_and_sorting/sorting/merge_sort.py b/src/searching_and_sorting/sorting/merge_sort.py index d234bde..5a099c0 100644 --- a/src/searching_and_sorting/sorting/merge_sort.py +++ b/src/searching_and_sorting/sorting/merge_sort.py @@ -4,28 +4,63 @@ __author__ = "Mari Wahl" __email__ = "marina.w4hl@gmail.com" -''' Some examples of how to implement Merge Sort in Python + +''' 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 + --> in general not in place, good for large arrays + --> 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] ''' + + +""" + The typical example... +""" + def merge_sort(seq): - if len(seq) <= 1: return seq + if len(seq) < 2: + 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) + if len(lft)>1: + lft = merge_sort(lft) + if len(rgt)>1: + rgt = merge_sort(rgt) res = [] while lft and rgt: @@ -38,11 +73,6 @@ def merge_sort(seq): -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!') - ''' We could also divide this sort into two parts, separating @@ -50,17 +80,18 @@ def test_merge_sort(): ''' def merge_sort_sep(seq): - if len(seq) < 2 : return seq # base case + 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! - + left = merge_sort(seq[:mid]) + right = merge_sort(seq[mid:]) # notice that mid is included! return merge(left, right) # merge iteratively + + def merge(left, right): - if not left or not right: return left or right # nothing to be merged + 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): @@ -70,14 +101,14 @@ def merge(left, right): else: result.append(right[j]) j += 1 - if left[i:] : result.extend(left[i:]) # REMEMBER TO TO ENXTEND NOT APPEND + if left[i:] : result.extend(left[i:]) # REMEMBER TO EXTEND, NOT APPEND if right[j:] : result.extend(right[j:]) return result -''' The two following merge functions are O(2n)=O(n) and O(n) respectively. They +''' The following merge functions is O(2n) and 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 @@ -92,9 +123,52 @@ def merge_2n(left, right): +''' Merge two arrays in place ''' +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 +''' Merge sort for files ''' +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 + + + + + +def test_merge_sort(): + seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2] + seq_sorted = sorted(seq) + assert(merge_sort(seq) == seq_sorted) + assert(merge_sort_sep(seq) == seq_sorted) + print('Tests passed!') + if __name__ == '__main__': test_merge_sort() diff --git a/src/searching_and_sorting/sorting/merge_sorted_things.py b/src/searching_and_sorting/sorting/merge_sorted_things.py deleted file mode 100644 index c2cc384..0000000 --- a/src/searching_and_sorting/sorting/merge_sorted_things.py +++ /dev/null @@ -1,96 +0,0 @@ -#!/usr/bin/python - -__author__ = "Mari Wahl" -__email__ = "marina.w4hl@gmail.com" - -''' --> 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() - - diff --git a/src/searching_and_sorting/sorting/quick_sort.py b/src/searching_and_sorting/sorting/quick_sort.py index 0d25d6a..39d1d90 100644 --- a/src/searching_and_sorting/sorting/quick_sort.py +++ b/src/searching_and_sorting/sorting/quick_sort.py @@ -25,16 +25,7 @@ __email__ = "marina.w4hl@gmail.com" -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 - -''' slightly different in the way we get the pivot''' def quick_sort(seq): if len(seq) < 2 : return seq mid = len(seq)//2