├── .gitignore ├── .python-version ├── .travis.yml ├── .vscode └── settings.json ├── 10장_검색 ├── 10_intersection_two_arrays.py ├── 1_sequential_search.py ├── 2_ordered_sequential_search.py ├── 3_quick_select.py ├── 4_binary_search.py ├── 5_search_entry_matrix.py ├── 6_searching_in_a_matrix.py ├── 7_find_max_unimodal_array.py ├── 8_find_sqrt_bin_search.py ├── 9_find_time_occurence_list.py └── binary_search.py ├── 11장_동적_계획법 ├── 1_memoized_fib.py ├── 2_memoized_longest_inc_subseq.py ├── benchmark.py └── functools_wraps.py ├── 12장_그래프_기초 ├── 1_tree.py └── 2_bunchclass.py ├── 13장_이진_트리 ├── 1_BT_lists.py ├── 2_binary_tree.py ├── 3_binary_search_tree.py ├── 4_AVL_BST.py └── binary_tree.py ├── 14장_트리_순회 ├── 1_transversal_BST_iteratively.py ├── 2_transversal_BST_recursively.py ├── 3_transversal_BST_ancestor.py ├── binary_search_tree.py ├── binary_tree.py └── transversal_BST_recursively.py ├── 1장_숫자 ├── .DS_Store ├── 10_finding_prime.py ├── 11_generate_prime.py ├── 12_testing_numpy.py ├── 13_testing_numpy_speed.py ├── 1_testing_floats.py ├── 2_convert_to_decimal.py ├── 3_convert_from_decimal.py ├── 4_convert_from_decimal_larger_bases.py ├── 5_convert_dec_to_any_base_rec.py ├── 6_finding_gcd.py ├── 7_testing_random.py ├── 8_find_fibonacci_seq.py └── 9_find_fibonacci_by_generator.py ├── 2장_내장_시퀀스_타입 ├── 10_combination.py ├── 11_palindrome.py ├── 1_count_unique_words.py ├── 2_runtime_lists_with_timeit_module.py ├── 3_reversing_string.py ├── 4_reversing_words_.py ├── 5_reversing_words.py ├── 6_reversing_words.py ├── 7_reversing_words.py ├── 8_simple_str_compression.py └── 9_permutation.py ├── 3장_컬렉션_데이터_구조 ├── 10_is_anagram_using_ord.py ├── 11_find_dice_probabilities.py ├── 12_delete_duplicate_char_str.py ├── 1_set_operations_with_lists.py ├── 2_set_operations_with_dicts.py ├── 3_setdefault_example.py ├── 4_runtime_dicts_with_timeit_module.py ├── 5_defaultdict_example.py ├── 6_orderedDict_example.py ├── 7_counterDict_example.py ├── 8_find_top_N_recurring_words.py └── 9_is_anagram.py ├── 4장_구조와_모듈 ├── 1_sys_example.py ├── 2_fib_generator.py ├── 3_grep_word_from_files.py ├── 4_remove_blank_lines.py ├── 5_remove_blank_lines_with.py ├── 6_change_ext_file.py ├── hello.py └── hello.txt ├── 5장_객체지향_설계 ├── 10_adapter_pattern_BETTER.py ├── 11_adapter_pattern_BEST.py ├── 12_facade_pattern.py ├── 13_observer_pattern.py ├── 1_hash_and_eq_NO.py ├── 2_hash_and_eq_NO.py ├── 3_hash_and_eq_OK.py ├── 4_benchmark_decorator.py ├── 5_class_and_static_decorator.py ├── 6_observer_pattern_with_set.py ├── 7_observer_pattern_with_dict.py ├── 8_observer_pattern_with_event.py ├── 9_adapter_pattern_OK.py ├── ShapeClass.py └── hash_and_eq.py ├── 6장_파이썬_고급 ├── 1_threading_with_queue.py ├── 2_threading_mutex.py ├── 3_threading_semaphore.py ├── 4_threading_with_condition.py ├── 5_using_time_module.py ├── 6_doctest_factorial.py ├── coroutine.py ├── event_simple.py ├── test_pytest.py └── threading_event.py ├── 7장_추상_데이터_타입 ├── 10_linkedlist_LIFO.py ├── 11_linkedlist_FIFO.py ├── 12_hash_table.py ├── 13_reverse_string_with_stack.py ├── 14_balance_parenthesis_str_stack.py ├── 15_dec2bin_with_stack.py ├── 16_stack_with_min.py ├── 17_set_of_stacks.py ├── 18_palindrome_checker_with_deque.py ├── 19_animal_shelter.py ├── 1_stack.py ├── 20_find_N_largest_smallest_items_seq.py ├── 21_merge_sorted_seqs.py ├── 22_find_kth_from_the_end.py ├── 23_part_linked_list.py ├── 24_doubled_linked_list_fifo.py ├── 25_check_pal.py ├── 26_sum_linked_list.py ├── 27_circular_linked_list.py ├── 2_stack_with_node.py ├── 3_queue.py ├── 4_queue_from_two_stacks.py ├── 5_linked_queue.py ├── 6_deque.py ├── 7_max_heapify.py ├── 8_priority_queue.py ├── 9_node.py ├── deque.py ├── linkedListFIFO.py ├── node.py ├── queue.py └── stack.py ├── 8장_점근적_분석 └── find_fibonacci_seq.py ├── 9장_정렬 ├── 10_heap_sort_2.py ├── 11_heap_sort_3.py ├── 1_bubble_sort.py ├── 2_selection_sort.py ├── 3_insertion_sort.py ├── 4_gnome_sort.py ├── 5_count_sort.py ├── 6_merge_sort.py ├── 7_quick_sort.py ├── 8_find_k_largest_seq_quicksort.py ├── 9_heap_sort_1.py ├── a.dat ├── b.dat ├── c.dat └── heap.py ├── HALEIWA.jpg ├── README.md ├── README_old.md ├── ebook └── book_second_edition.pdf ├── interview_problems ├── balanced.py ├── binary_search.py ├── bst.py ├── check_anagram.py ├── combination.py ├── hash_table.py ├── linked_list.py ├── longest_common_prefix.py ├── longest_increasing_subsequence.py ├── merge_sort.py ├── palindome.py ├── permutation.py ├── queue.py ├── quick_sort.py ├── reverse_str.py └── stack.py ├── requirements.txt └── source_code ├── .DS_Store ├── USEFUL ├── advanced │ └── lru_cache.py ├── basic_examples │ ├── example_OrderedDict.py │ ├── example_args.py │ ├── example_benchmark_decorator.py │ ├── example_comp_lists.py │ ├── example_counter.py │ ├── example_decorators.py │ ├── example_defaultdict.py │ ├── example_doctest.py │ ├── example_fractions.py │ ├── example_generator.py │ ├── example_lambda.py │ ├── example_logging.py │ ├── example_numpy.py │ ├── example_open_files.py │ ├── example_pickle.py │ ├── example_queue.py │ ├── example_random.py │ ├── example_setdefault.py │ ├── example_sets.py │ ├── example_socket.py │ ├── example_string_format.py │ ├── example_subprocess.py │ ├── example_telnet.py │ ├── example_testing.py │ ├── example_threads.py │ └── example_time.py ├── dynamic_programming │ ├── __init__.py │ ├── memo.py │ └── memoized_longest_inc_subseq.py ├── oop │ ├── ShapeClass.py │ └── __init__.py └── useful_with_files │ ├── change_ext_file.py │ ├── count_unique_words_files.py │ ├── count_unique_words_frequency.py │ ├── grep_word_from_files.py │ └── remove_blank_lines.py ├── abstract_structures ├── HashTable.py ├── Queue.py ├── Stack.py ├── __init__.py ├── heap │ ├── __init__.py │ ├── find_N_largest_smallest_items_seq.py │ ├── heapify.py │ ├── merge_sorted_seqs.py │ └── priority_queue.py ├── linked_list │ ├── __init__.py │ ├── circular_ll.py │ ├── double_linked_list_fifo.py │ ├── find_kth_from_the_end.py │ ├── linked_list_fifo.py │ ├── linked_list_lifo.py │ ├── node.py │ ├── part_linked_list.py │ └── sum_linked_list.py ├── queues │ ├── __init__.py │ ├── animal_shelter.py │ ├── deque.py │ ├── linked_queue.py │ ├── palindrome_checker_with_deque.py │ └── queue.py └── stacks │ ├── __init__.py │ ├── dec2bin_with_stack.py │ ├── linked_stack.py │ ├── reverse_string_with_stack.py │ ├── set_of_stacks.py │ ├── stack.py │ ├── stack_with_min.py │ └── towers_of_hanoi.py ├── bitwise ├── bit_array.py ├── bitwise.txt ├── clear_bits.py ├── find_bit_len.py ├── find_how_many_1_binary.py ├── get_bit.py ├── get_float_rep_bin.py ├── insert_small_bin_into_big_bin.py ├── next_with_same_num_1s.py ├── num_bits_to_convert_2_nums.py ├── set_bit.py ├── swap_in_place.py ├── swap_odd_even.py └── update_bit.py ├── builtin_structures ├── __init__.py ├── anagram.py ├── balance.txt ├── balance_symbols.py ├── check_if_2_numbers_sum_to_k.py ├── check_if_3_numbers_sum_to_zero.py ├── check_non_overlapping_intervals.py ├── convert_numerical_bases.py ├── convert_str_2_int.py ├── count_unique_words_On2.py ├── delete_duplicate_char_str.py ├── fibonacci.py ├── find_0_MxN_replace_cols_rows.py ├── find_dice_probabilities.py ├── find_edit_distance.py ├── find_first_non_repetead_char.py ├── find_gcd.py ├── find_if_substr.py ├── find_if_unique_char.py ├── find_largest_sum.py ├── find_longest_inc_subseq.py ├── find_longest_str_unique_chars.py ├── find_non_repeating_number.py ├── find_product_without_division.py ├── find_top_N_recurring_words.py ├── find_two_missing_numbers_in_sequence.py ├── get_float_rep_bin.py ├── interserction_two_arrays.py ├── max_subarray_stocks.py ├── number_of_zeros_factorial.txt ├── palindrome.py ├── permutations.py ├── permutations_alphanumeric.py ├── primes.py ├── prod_other_ints.py ├── ransom_note.py ├── reverse_string.py ├── reverse_words.py ├── rotate_NxN.py ├── runtime_dicts_with_timeit_module.py ├── runtime_lists_with_timeit_module.py ├── search_entry_matrix.py ├── simple_str_comprension.py └── sum_two_numbers_as_strings.py ├── learning └── decorator.py ├── searching_and_sorting ├── searching │ ├── __init__.py │ ├── binary_search.py │ ├── binary_search_matrix.py │ ├── find_item_rotated_sorted_array.py │ ├── find_max_unimodal_array.py │ ├── find_sqrt_bin_search.py │ ├── find_str_array_with_empty_str.py │ ├── find_time_occurence_list.py │ ├── ordered_sequential_search.py │ ├── quick_select.py │ ├── searching_in_a_matrix.py │ └── sequential_search.py └── sorting │ ├── 1.dat │ ├── 2.dat │ ├── 3.dat │ ├── __init__.py │ ├── bubble_sort.py │ ├── count_sort.py │ ├── gnome_sort.py │ ├── heap.py │ ├── heap_sort.py │ ├── insertion_sort.py │ ├── merge_and_sort_two_arrays.py │ ├── merge_sort.py │ ├── quick_sort.py │ ├── selection_sort.py │ └── sort_anagrams_together.py └── trees ├── __init__.py ├── binary_search_tree.py ├── binary_tree.py ├── binary_tree_generators.py ├── bunchclass.py ├── check_ancestor.py ├── check_if_balanced.py ├── check_if_bst.py ├── check_largest_item.py ├── simple_tree.py ├── transversal.py └── trie.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | *~ 3 | 4 | # C extensions 5 | *.so 6 | 7 | # Packages 8 | *.egg 9 | *.egg-info 10 | dist 11 | build 12 | eggs 13 | parts 14 | bin 15 | var 16 | sdist 17 | develop-eggs 18 | .installed.cfg 19 | lib 20 | lib64 21 | 22 | # Installer logs 23 | pip-log.txt 24 | 25 | # Unit test / coverage reports 26 | .coverage 27 | .tox 28 | nosetests.xml 29 | 30 | # Translations 31 | *.mo 32 | 33 | # Mr Developer 34 | .mr.developer.cfg 35 | .project 36 | .pydevproject 37 | 38 | # PyCharm 39 | .idea -------------------------------------------------------------------------------- /.python-version: -------------------------------------------------------------------------------- 1 | 3.7.0 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | # command to install dependencies 5 | install: "pip install -r requirements.txt" 6 | # command to run tests 7 | script: nosetests 8 | notifications: 9 | email: false 10 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "python.linting.pylintEnabled": false, 3 | "python.linting.pep8Enabled": true, 4 | "python.linting.enabled": true 5 | } -------------------------------------------------------------------------------- /10장_검색/10_intersection_two_arrays.py: -------------------------------------------------------------------------------- 1 | from binary_search import binary_search_iter 2 | 3 | 4 | # 파이썬 set 사용 5 | def intersection_two_arrays_sets(seq1, seq2): 6 | set1 = set(seq1) 7 | set2 = set(seq2) 8 | return set1.intersection(set2) 9 | 10 | 11 | # 병합 정렬 사용 12 | def intersection_two_arrays_ms(seq1, seq2): 13 | res = [] 14 | while seq1 and seq2: 15 | if seq1[-1] == seq2[-1]: 16 | res.append(seq1.pop()) 17 | seq2.pop() 18 | elif seq1[-1] > seq2[-1]: 19 | seq1.pop() 20 | else: 21 | seq2.pop() 22 | res.reverse() 23 | return res 24 | 25 | 26 | # 이진 검색 사용 27 | def intersection_two_arrays_bs(seq1, seq2): 28 | if len(seq1) > len(seq2): 29 | seq, key = seq1, seq2 30 | else: 31 | seq, key = seq2, seq1 32 | intersec = [] 33 | for item in key: 34 | if binary_search_iter(seq, item): 35 | intersec.append(item) 36 | return intersec 37 | 38 | 39 | def test_intersection_two_arrays(): 40 | seq1 = [1, 2, 3, 5, 7, 8] 41 | seq2 = [3, 5, 6] 42 | assert(set(intersection_two_arrays_sets(seq1, seq2)) == set([3, 5])) 43 | assert(intersection_two_arrays_bs(seq1, seq2) == [3, 5]) 44 | assert(intersection_two_arrays_ms(seq1, seq2) == [3, 5]) 45 | print("테스트 통과!") 46 | 47 | 48 | if __name__ == "__main__": 49 | test_intersection_two_arrays() 50 | -------------------------------------------------------------------------------- /10장_검색/1_sequential_search.py: -------------------------------------------------------------------------------- 1 | def sequential_search(seq, n): 2 | for item in seq: 3 | if item == n: 4 | return True 5 | return False 6 | 7 | 8 | def test_sequential_search(): 9 | seq = [1, 5, 6, 8, 3] 10 | n1 = 5 11 | n2 = 7 12 | assert(sequential_search(seq, n1) is True) 13 | assert(sequential_search(seq, n2) is False) 14 | print("테스트 통과!") 15 | 16 | 17 | if __name__ == "__main__": 18 | test_sequential_search() 19 | -------------------------------------------------------------------------------- /10장_검색/2_ordered_sequential_search.py: -------------------------------------------------------------------------------- 1 | def ordered_sequential_search(seq, n): 2 | item = 0 3 | for item in seq: 4 | if item > n: 5 | return False 6 | if item == n: 7 | return True 8 | return False 9 | 10 | 11 | def test_ordered_sequential_search(): 12 | seq = [1, 2, 4, 5, 6, 8, 10] 13 | n1 = 10 14 | n2 = 7 15 | assert(ordered_sequential_search(seq, n1) is True) 16 | assert(ordered_sequential_search(seq, n2) is False) 17 | print("테스트 통과!") 18 | 19 | 20 | if __name__ == "__main__": 21 | test_ordered_sequential_search() 22 | -------------------------------------------------------------------------------- /10장_검색/4_binary_search.py: -------------------------------------------------------------------------------- 1 | # 재귀함수 2 | def binary_search_rec(seq, target, low, high): 3 | if low > high: 4 | return None 5 | mid = (low + high) // 2 6 | if target == seq[mid]: 7 | return mid 8 | elif target < seq[mid]: 9 | return binary_search_rec(seq, target, low, mid-1) 10 | else: 11 | return binary_search_rec(seq, target, mid+1, high) 12 | 13 | 14 | # 반복문 15 | def binary_search_iter(seq, target): 16 | high, low = len(seq), 0 17 | while low < high: 18 | mid = (high + low) // 2 19 | if target == seq[mid]: 20 | return mid 21 | elif target < seq[mid]: 22 | high = mid 23 | else: 24 | low = mid + 1 25 | return None 26 | 27 | 28 | def test_binary_search(): 29 | seq = [1, 2, 5, 6, 7, 10, 12, 12, 14, 15] 30 | target = 6 31 | assert(binary_search_iter(seq, target) == 3) 32 | assert(binary_search_rec(seq, target, 0, len(seq)) == 3) 33 | print("테스트 통과!") 34 | 35 | 36 | if __name__ == "__main__": 37 | test_binary_search() 38 | -------------------------------------------------------------------------------- /10장_검색/5_search_entry_matrix.py: -------------------------------------------------------------------------------- 1 | def find_elem_matrix_bool(m1, value): 2 | found = False 3 | row = 0 4 | col = len(m1[0]) - 1 5 | while row < len(m1) and col >= 0: 6 | if m1[row][col] == value: 7 | found = True 8 | break 9 | elif m1[row][col] > value: 10 | col -= 1 11 | else: 12 | row += 1 13 | return found 14 | 15 | 16 | def test_find_elem_matrix_bool(): 17 | m1 = [[1, 2, 8, 9], [2, 4, 9, 12], [4, 7, 10, 13], [6, 8, 11, 15]] 18 | assert(find_elem_matrix_bool(m1, 8) is True) 19 | assert(find_elem_matrix_bool(m1, 3) is False) 20 | m2 = [[0]] 21 | assert(find_elem_matrix_bool(m2, 0) is True) 22 | print("테스트 통과!") 23 | 24 | 25 | if __name__ == "__main__": 26 | test_find_elem_matrix_bool() 27 | -------------------------------------------------------------------------------- /10장_검색/6_searching_in_a_matrix.py: -------------------------------------------------------------------------------- 1 | def searching_in_a_matrix(m1, value): 2 | rows = len(m1) 3 | cols = len(m1[0]) 4 | lo = 0 5 | hi = rows*cols 6 | while lo < hi: 7 | mid = (lo + hi) // 2 8 | row = mid // cols 9 | col = mid % cols 10 | v = m1[row][col] 11 | if v == value: 12 | return True 13 | elif v > value: 14 | hi = mid 15 | else: 16 | lo = mid+1 17 | return False 18 | 19 | 20 | def test_searching_in_a_matrix(): 21 | a = [[1, 3, 5], [7, 9, 11], [13, 15, 17]] 22 | import numpy 23 | b = numpy.array([(1, 2), (3, 4)]) 24 | assert(searching_in_a_matrix(a, 13) is True) 25 | assert(searching_in_a_matrix(a, 14) is False) 26 | assert(searching_in_a_matrix(b, 3) is True) 27 | assert(searching_in_a_matrix(b, 5) is False) 28 | print("테스트 통과!") 29 | 30 | 31 | if __name__ == "__main__": 32 | test_searching_in_a_matrix() 33 | -------------------------------------------------------------------------------- /10장_검색/7_find_max_unimodal_array.py: -------------------------------------------------------------------------------- 1 | def find_max_unimodal_array(A): 2 | if len(A) <= 2: 3 | return None 4 | left = 0 5 | right = len(A)-1 6 | while right > left + 1: 7 | mid = (left + right) // 2 8 | if A[mid] > A[mid-1] and A[mid] > A[mid+1]: 9 | return A[mid] 10 | elif A[mid] > A[mid-1] and A[mid] < A[mid+1]: 11 | left = mid 12 | else: 13 | right = mid 14 | return None 15 | 16 | 17 | def test_find_max_unimodal_array(): 18 | seq = [1, 2, 5, 6, 7, 10, 12, 9, 8, 7, 6] 19 | assert(find_max_unimodal_array(seq) == max(seq)) 20 | print("테스트 통과!") 21 | 22 | 23 | if __name__ == "__main__": 24 | test_find_max_unimodal_array() 25 | -------------------------------------------------------------------------------- /10장_검색/8_find_sqrt_bin_search.py: -------------------------------------------------------------------------------- 1 | def find_sqrt_bin_search(n, error=0.001): 2 | lower = n < 1 and n or 1 3 | upper = n < 1 and 1 or n 4 | mid = lower + (upper - lower) / 2.0 5 | square = mid * mid 6 | while abs(square - n) > error: 7 | if square < n: 8 | lower = mid 9 | else: 10 | upper = mid 11 | mid = lower + (upper - lower) / 2.0 12 | square = mid * mid 13 | return mid 14 | 15 | 16 | if __name__ == "__main__": 17 | a = 2 18 | b = 9 19 | import math 20 | print(math.sqrt(a)) 21 | print(find_sqrt_bin_search(a)) 22 | print(math.sqrt(b)) 23 | print(find_sqrt_bin_search(b)) 24 | -------------------------------------------------------------------------------- /10장_검색/9_find_time_occurence_list.py: -------------------------------------------------------------------------------- 1 | from binary_search import binary_search_iter 2 | 3 | 4 | def find_time_occurrence_list(seq, k): 5 | index_some_k = binary_search_iter(seq, k) 6 | count = 1 7 | sizet = len(seq) 8 | for i in range(index_some_k+1, sizet): 9 | if seq[i] == k: 10 | count += 1 11 | else: 12 | break 13 | for i in range(index_some_k-1, -1, -1): 14 | if seq[i] == k: 15 | count += 1 16 | else: 17 | break 18 | return count 19 | 20 | 21 | def test_find_time_occurrence_list(): 22 | seq = [1, 2, 2, 2, 2, 2, 2, 5, 6, 6, 7, 8, 9] 23 | k = 2 24 | assert(find_time_occurrence_list(seq, k) == 6) 25 | print("테스트 통과!") 26 | 27 | 28 | if __name__ == "__main__": 29 | test_find_time_occurrence_list() 30 | -------------------------------------------------------------------------------- /10장_검색/binary_search.py: -------------------------------------------------------------------------------- 1 | # 재귀함수 2 | def binary_search_rec(seq, target, low, high): 3 | if low > high: 4 | return None 5 | mid = (low + high) // 2 6 | if target == seq[mid]: 7 | return mid 8 | elif target < seq[mid]: 9 | return binary_search_rec(seq, target, low, mid-1) 10 | else: 11 | return binary_search_rec(seq, target, mid+1, high) 12 | 13 | 14 | # 반복문 15 | def binary_search_iter(seq, target): 16 | high, low = len(seq), 0 17 | while low < high: 18 | mid = (high + low) // 2 19 | if target == seq[mid]: 20 | return mid 21 | elif target < seq[mid]: 22 | high = mid 23 | else: 24 | low = mid + 1 25 | return None 26 | -------------------------------------------------------------------------------- /11장_동적_계획법/1_memoized_fib.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | 3 | from benchmark import benchmark 4 | 5 | 6 | def memo(func): 7 | cache = {} 8 | 9 | @wraps(func) 10 | def wrap(*args): 11 | if args not in cache: 12 | cache[args] = func(*args) 13 | return cache[args] 14 | return wrap 15 | 16 | 17 | def fib(n): 18 | if n < 2: 19 | return 1 20 | else: 21 | return fib(n-1) + fib(n-2) 22 | 23 | 24 | @memo 25 | def fib2(n): 26 | if n < 2: 27 | return 1 28 | else: 29 | return fib2(n-1) + fib2(n-2) 30 | 31 | 32 | def fib3(m, n): 33 | if m[n] == 0: 34 | m[n] = fib3(m, n-1) + fib3(m, n-2) 35 | return m[n] 36 | 37 | 38 | @benchmark 39 | def test_fib(n): 40 | print(fib(n)) 41 | 42 | 43 | @benchmark 44 | def test_fib2(n): 45 | print(fib2(n)) 46 | 47 | 48 | @benchmark 49 | def test_fib3(n): 50 | m = [0] * (n+1) 51 | m[0], m[1] = 1, 1 52 | print(fib3(m, n)) 53 | 54 | 55 | if __name__ == "__main__": 56 | n = 35 57 | test_fib(n) 58 | test_fib2(n) 59 | test_fib3(n) 60 | -------------------------------------------------------------------------------- /11장_동적_계획법/benchmark.py: -------------------------------------------------------------------------------- 1 | from functools import wraps 2 | import time 3 | 4 | 5 | def benchmark(method): 6 | @wraps(method) 7 | def timed(*args, **kw): 8 | ts = time.time() 9 | result = method(*args, **kw) 10 | te = time.time() 11 | # print("%r: %2.2f ms" % (method.__name__, (te - ts) * 1000)) 12 | # print(f"{method.__name__}: {((te-ts)*1000):.2f} ms") 13 | print("{0}: {1:0.2f} ms".format(method.__name__, ((te-ts)*1000))) 14 | return result 15 | 16 | return timed 17 | -------------------------------------------------------------------------------- /11장_동적_계획법/functools_wraps.py: -------------------------------------------------------------------------------- 1 | # https://stackoverflow.com/questions/308999/what-does-functools-wraps-do 2 | from functools import wraps 3 | 4 | 5 | def logged(func): 6 | def with_logging(*args, **kwargs): 7 | """with_logging() 함수""" 8 | print(func.__name__ + " 호출") 9 | return func(*args, **kwargs) 10 | return with_logging 11 | 12 | 13 | @logged 14 | def f(x): 15 | """첫 번째, 데커레이터 사용 """ 16 | return x + x * x 17 | 18 | 19 | def f2(x): 20 | """두 번째, 데커레이터 사용 X """ 21 | return x + x * x 22 | 23 | 24 | def logged2(func): 25 | @wraps(func) 26 | def with_logging(*args, **kwargs): 27 | print(func.__name__ + " 호출") 28 | return func(*args, **kwargs) 29 | return with_logging 30 | 31 | 32 | @logged2 33 | def f3(x): 34 | """세 번째, wraps와 데커레이터 사용 """ 35 | return x + x * x 36 | 37 | 38 | if __name__ == "__main__": 39 | print("결과: {0}".format(f(5))) 40 | print("__name__: {0}".format(f.__name__)) 41 | print("__doc__: {0}".format(f.__doc__)) 42 | print("-----------------------------") 43 | f2 = logged(f2) 44 | print("결과: {0}".format(f2(5))) 45 | print("__name__: {0}".format(f2.__name__)) 46 | print("__doc__: {0}".format(f2.__doc__)) 47 | print("-----------------------------") 48 | print("결과: {0}".format(f3(5))) 49 | print("__name__: {0}".format(f3.__name__)) 50 | print("__doc__: {0}".format(f3.__doc__)) 51 | -------------------------------------------------------------------------------- /12장_그래프_기초/1_tree.py: -------------------------------------------------------------------------------- 1 | class SimpleTree(object): 2 | def __init__(self, value=None, children=None): 3 | self.value = value 4 | self.children = children 5 | if self.children is None: 6 | self.children = [] 7 | 8 | def __repr__(self, level=0): 9 | ret = "\t"*level + repr(self.value) + "\n" 10 | for child in self.children: 11 | ret += child.__repr__(level+1) 12 | return ret 13 | 14 | 15 | def main(): 16 | st = SimpleTree('a', [ 17 | SimpleTree('b', 18 | [ 19 | SimpleTree('d'), 20 | SimpleTree('e') 21 | ]), 22 | SimpleTree('c', [ 23 | SimpleTree('h'), 24 | SimpleTree('g') 25 | ]) 26 | ]) 27 | print(st) 28 | 29 | 30 | if __name__ == "__main__": 31 | main() 32 | -------------------------------------------------------------------------------- /12장_그래프_기초/2_bunchclass.py: -------------------------------------------------------------------------------- 1 | 2 | class BunchClass(dict): 3 | def __init__(self, *args, **kwds): 4 | super(BunchClass, self).__init__(*args, **kwds) 5 | self.__dict__ = self 6 | 7 | 8 | def main(): 9 | # 1) 딕셔너리 특수화 10 | bc = BunchClass # ()가 없다. 11 | tree = bc(left=bc(left="Buffy", right="Angel"), 12 | right=bc(left="Willow", right="Xander")) 13 | print(tree) 14 | 15 | # 2) 일반 딕셔너리 16 | tree2 = dict(left=dict(left="Buffy", right="Angel"), 17 | right=dict(left="Willow", right="Xander")) 18 | print(tree2) 19 | 20 | if __name__ == "__main__": 21 | main() 22 | -------------------------------------------------------------------------------- /13장_이진_트리/1_BT_lists.py: -------------------------------------------------------------------------------- 1 | def binary_tree_list(r): 2 | return [r, [], []] 3 | 4 | 5 | def insert_left(root, newBranch): 6 | t = root.pop(1) 7 | if len(t) > 1: 8 | root.insert(1, [newBranch, t, []]) 9 | else: 10 | root.insert(1, [newBranch, [], []]) 11 | return root 12 | 13 | 14 | def insert_right(root, newBranch): 15 | t = root.pop(2) 16 | if len(t) > 1: 17 | root.insert(2, [newBranch, [], t]) 18 | else: 19 | root.insert(2, [newBranch, [], []]) 20 | return root 21 | 22 | 23 | def get_root_val(root): 24 | return root[0] 25 | 26 | 27 | def set_root_val(root, new_val): 28 | root[0] = new_val 29 | 30 | 31 | def get_left_child(root): 32 | return root[1] 33 | 34 | 35 | def get_right_child(root): 36 | return root[2] 37 | 38 | 39 | def main(): 40 | r = binary_tree_list(3) 41 | insert_left(r, 4) 42 | insert_left(r, 5) 43 | insert_right(r, 6) 44 | insert_right(r, 7) 45 | print(get_root_val(r)) 46 | print(get_left_child(r)) 47 | print(get_right_child(r)) 48 | 49 | 50 | if __name__ == "__main__": 51 | main() 52 | -------------------------------------------------------------------------------- /1장_숫자/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/c143f4248734b86f0b1783b6759ba8b9dbebf685/1장_숫자/.DS_Store -------------------------------------------------------------------------------- /1장_숫자/10_finding_prime.py: -------------------------------------------------------------------------------- 1 | import math 2 | import random 3 | 4 | 5 | def finding_prime(number): 6 | num = abs(number) 7 | if num < 4: 8 | return True 9 | for x in range(2, num): 10 | if num % x == 0: 11 | return False 12 | return True 13 | 14 | 15 | def finding_prime_sqrt(number): 16 | num = abs(number) 17 | if num < 4: 18 | return True 19 | for x in range(2, int(math.sqrt(num)) + 1): 20 | if number % x == 0: 21 | return False 22 | return True 23 | 24 | 25 | def finding_prime_fermat(number): 26 | if number <= 102: 27 | for a in range(2, number): 28 | if pow(a, number - 1, number) != 1: 29 | return False 30 | return True 31 | else: 32 | for i in range(100): 33 | a = random.randint(2, number - 1) 34 | if pow(a, number - 1, number) != 1: 35 | return False 36 | return True 37 | 38 | 39 | def test_finding_prime(): 40 | number1 = 17 41 | number2 = 20 42 | assert(finding_prime(number1) is True) 43 | assert(finding_prime(number2) is False) 44 | assert(finding_prime_sqrt(number1) is True) 45 | assert(finding_prime_sqrt(number2) is False) 46 | assert(finding_prime_fermat(number1) is True) 47 | assert(finding_prime_fermat(number2) is False) 48 | print("테스트 통과!") 49 | 50 | 51 | if __name__ == "__main__": 52 | test_finding_prime() 53 | -------------------------------------------------------------------------------- /1장_숫자/11_generate_prime.py: -------------------------------------------------------------------------------- 1 | import math 2 | import random 3 | import sys 4 | 5 | 6 | def finding_prime_sqrt(number): 7 | num = abs(number) 8 | if num < 4: 9 | return True 10 | for x in range(2, int(math.sqrt(num)) + 1): 11 | if number % x == 0: 12 | return False 13 | return True 14 | 15 | 16 | def generate_prime(number=3): 17 | while 1: 18 | p = random.randint(pow(2, number-2), pow(2, number-1)-1) 19 | p = 2 * p + 1 20 | if finding_prime_sqrt(p): 21 | return p 22 | 23 | 24 | if __name__ == "__main__": 25 | if len(sys.argv) < 2: 26 | print("Usage: generate_prime.py number") 27 | sys.exit() 28 | else: 29 | number = int(sys.argv[1]) 30 | print(generate_prime(number)) 31 | -------------------------------------------------------------------------------- /1장_숫자/12_testing_numpy.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | 4 | def testing_numpy(): 5 | ax = np.array([1, 2, 3]) 6 | ay = np.array([3, 4, 5]) 7 | print(ax) 8 | print(ax*2) 9 | print(ax+10) 10 | print(np.sqrt(ax)) 11 | print(np.cos(ax)) 12 | print(ax-ay) 13 | print(np.where(ax < 2, ax, 10)) 14 | 15 | m = np.matrix([ax, ay, ax]) 16 | print(m) 17 | print(m.T) 18 | 19 | grid1 = np.zeros(shape=(10, 10), dtype=float) 20 | grid2 = np.ones(shape=(10, 10), dtype=float) 21 | print(grid1) 22 | print(grid2) 23 | print(grid1[1]+10) 24 | print(grid2[:, 2]*2) 25 | 26 | 27 | if __name__ == "__main__": 28 | testing_numpy() 29 | -------------------------------------------------------------------------------- /1장_숫자/13_testing_numpy_speed.py: -------------------------------------------------------------------------------- 1 | import numpy 2 | import time 3 | 4 | 5 | def trad_version(): 6 | t1 = time.time() 7 | X = range(10000000) 8 | Y = range(10000000) 9 | Z = [] 10 | for i in range(len(X)): 11 | Z.append(X[i] + Y[i]) 12 | return time.time() - t1 13 | 14 | 15 | def numpy_version(): 16 | t1 = time.time() 17 | X = numpy.arange(10000000) 18 | Y = numpy.arange(10000000) 19 | Z = X + Y 20 | return time.time() - t1 21 | 22 | 23 | if __name__ == "__main__": 24 | print(trad_version()) 25 | print(numpy_version()) 26 | -------------------------------------------------------------------------------- /1장_숫자/1_testing_floats.py: -------------------------------------------------------------------------------- 1 | from fractions import Fraction 2 | 3 | 4 | def rounding_floats(number1, places): 5 | return round(number1, places) 6 | 7 | 8 | def float_to_fractions(number): 9 | return Fraction(*number.as_integer_ratio()) 10 | 11 | 12 | def get_denominator(number1, number2): 13 | """ 분모를 반환한다.""" 14 | a = Fraction(number1, number2) 15 | return a.denominator 16 | 17 | 18 | def get_numerator(number1, number2): 19 | """ 분자를 반환한다.""" 20 | a = Fraction(number1, number2) 21 | return a.numerator 22 | 23 | 24 | def test_testing_floats(): 25 | number1 = 1.25 26 | number2 = 1 27 | number3 = -1 28 | number4 = 5/4 29 | number6 = 6 30 | assert(rounding_floats(number1, number2) == 1.2) 31 | assert(rounding_floats(number1*10, number3) == 10) 32 | assert(float_to_fractions(number1) == number4) 33 | assert(get_denominator(number2, number6) == number6) 34 | assert(get_numerator(number2, number6) == number2) 35 | print("테스트 통과!") 36 | 37 | 38 | if __name__ == "__main__": 39 | test_testing_floats() 40 | -------------------------------------------------------------------------------- /1장_숫자/2_convert_to_decimal.py: -------------------------------------------------------------------------------- 1 | def convert_to_decimal(number, base): 2 | multiplier, result = 1, 0 3 | while number > 0: 4 | result += number % 10 * multiplier 5 | multiplier *= base 6 | number = number // 10 7 | return result 8 | 9 | 10 | def test_convert_to_decimal(): 11 | number, base = 1001, 2 12 | assert(convert_to_decimal(number, base) == 9) 13 | print("테스트 통과!") 14 | 15 | 16 | if __name__ == "__main__": 17 | test_convert_to_decimal() 18 | -------------------------------------------------------------------------------- /1장_숫자/3_convert_from_decimal.py: -------------------------------------------------------------------------------- 1 | def convert_from_decimal(number, base): 2 | multiplier, result = 1, 0 3 | while number > 0: 4 | result += number % base * multiplier 5 | multiplier *= 10 6 | number = number // base 7 | return result 8 | 9 | 10 | def test_convert_from_decimal(): 11 | number, base = 9, 2 12 | assert(convert_from_decimal(number, base) == 1001) 13 | print("테스트 통과!") 14 | 15 | 16 | if __name__ == "__main__": 17 | test_convert_from_decimal() 18 | -------------------------------------------------------------------------------- /1장_숫자/4_convert_from_decimal_larger_bases.py: -------------------------------------------------------------------------------- 1 | def convert_from_decimal_larger_bases(number, base): 2 | strings = "0123456789ABCDEFGHIJ" 3 | result = "" 4 | while number > 0: 5 | digit = number % base 6 | result = strings[digit] + result 7 | number = number // base 8 | return result 9 | 10 | 11 | def test_convert_from_decimal_larger_bases(): 12 | number, base = 31, 16 13 | assert(convert_from_decimal_larger_bases(number, base) == "1F") 14 | print("테스트 통과!") 15 | 16 | 17 | if __name__ == "__main__": 18 | test_convert_from_decimal_larger_bases() 19 | -------------------------------------------------------------------------------- /1장_숫자/5_convert_dec_to_any_base_rec.py: -------------------------------------------------------------------------------- 1 | def convert_dec_to_any_base_rec(number, base): 2 | convertString = "012345679ABCDEF" 3 | if number < base: 4 | return convertString[number] 5 | else: 6 | return convert_dec_to_any_base_rec(number // base, base) \ 7 | + convertString[number % base] 8 | 9 | 10 | def test_convert_dec_to_any_base_rec(): 11 | number = 9 12 | base = 2 13 | assert(convert_dec_to_any_base_rec(number, base) == "1001") 14 | print("테스트 통과!") 15 | 16 | 17 | if __name__ == "__main__": 18 | test_convert_dec_to_any_base_rec() 19 | -------------------------------------------------------------------------------- /1장_숫자/6_finding_gcd.py: -------------------------------------------------------------------------------- 1 | def finding_gcd(a, b): 2 | while(b != 0): 3 | result = b 4 | a, b = b, a % b 5 | return result 6 | 7 | 8 | def test_finding_gcd(): 9 | number1 = 21 10 | number2 = 12 11 | assert(finding_gcd(number1, number2) == 3) 12 | print("테스트 통과!") 13 | 14 | 15 | if __name__ == "__main__": 16 | test_finding_gcd() 17 | -------------------------------------------------------------------------------- /1장_숫자/7_testing_random.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | 4 | def testing_random(): 5 | """ random 모듈 테스트 """ 6 | values = [1, 2, 3, 4] 7 | print(random.choice(values)) 8 | print(random.choice(values)) 9 | print(random.choice(values)) 10 | print(random.sample(values, 2)) 11 | print(random.sample(values, 3)) 12 | 13 | """ values 리스트를 섞는다. """ 14 | random.shuffle(values) 15 | print(values) 16 | 17 | """ 0~10의 임의의 정수를 생성한다. """ 18 | print(random.randint(0, 10)) 19 | print(random.randint(0, 10)) 20 | 21 | 22 | if __name__ == "__main__": 23 | testing_random() 24 | -------------------------------------------------------------------------------- /1장_숫자/8_find_fibonacci_seq.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | 4 | def find_fibonacci_seq_iter(n): 5 | if n < 2: 6 | return n 7 | a, b = 0, 1 8 | for i in range(n): 9 | a, b = b, a + b 10 | return a 11 | 12 | 13 | def find_fibonacci_seq_rec(n): 14 | if n < 2: 15 | return n 16 | return find_fibonacci_seq_rec(n - 1) + find_fibonacci_seq_rec(n - 2) 17 | 18 | 19 | def find_fibonacci_seq_form(n): 20 | sq5 = math.sqrt(5) 21 | phi = (1 + sq5) / 2 22 | return int(math.floor(phi ** n / sq5)) 23 | 24 | 25 | def test_find_fib(): 26 | n = 10 27 | assert(find_fibonacci_seq_rec(n) == 55) 28 | assert(find_fibonacci_seq_iter(n) == 55) 29 | assert(find_fibonacci_seq_form(n) == 55) 30 | print("테스트 통과!") 31 | 32 | 33 | if __name__ == "__main__": 34 | test_find_fib() 35 | -------------------------------------------------------------------------------- /1장_숫자/9_find_fibonacci_by_generator.py: -------------------------------------------------------------------------------- 1 | def fib_generator(): 2 | a, b = 0, 1 3 | while True: 4 | yield b 5 | a, b = b, a+b 6 | 7 | 8 | if __name__ == "__main__": 9 | fg = fib_generator() 10 | for _ in range(10): 11 | print(next(fg), end=" ") 12 | -------------------------------------------------------------------------------- /2장_내장_시퀀스_타입/10_combination.py: -------------------------------------------------------------------------------- 1 | def combinations(s): 2 | if len(s) < 2: 3 | return s 4 | res = [] 5 | for i, c in enumerate(s): 6 | res.append(c) # 추가된 부분 7 | for j in combinations(s[:i] + s[i+1:]): 8 | res.append(c + j) 9 | return res 10 | 11 | 12 | if __name__ == "__main__": 13 | result = combinations("abc") 14 | print(result) 15 | -------------------------------------------------------------------------------- /2장_내장_시퀀스_타입/11_palindrome.py: -------------------------------------------------------------------------------- 1 | def is_palindrome(s): 2 | l = s.split(" ") 3 | s2 = ''.join(l) 4 | return s2 == s2[::-1] 5 | 6 | 7 | def is_palindrome2(s): 8 | l = len(s) 9 | f, b = 0, l-1 10 | while f < l // 2: 11 | while s[f] == " ": 12 | f += 1 13 | while s[b] == " ": 14 | b -= 1 15 | if s[f] != s[b]: 16 | return False 17 | f += 1 18 | b -= 1 19 | return True 20 | 21 | 22 | def is_palindrome3(s): 23 | s = s.strip() 24 | if len(s) < 2: 25 | return True 26 | if s[0] == s[-1]: 27 | return is_palindrome(s[1:-1]) 28 | else: 29 | return False 30 | 31 | 32 | if __name__ == "__main__": 33 | str1 = "다시 합창합시다" 34 | str2 = "" 35 | str3 = "hello" 36 | print(is_palindrome(str1)) 37 | print(is_palindrome(str2)) 38 | print(is_palindrome(str3)) 39 | print(is_palindrome2(str1)) 40 | print(is_palindrome2(str2)) 41 | print(is_palindrome2(str3)) 42 | print(is_palindrome3(str1)) 43 | print(is_palindrome3(str2)) 44 | print(is_palindrome3(str3)) 45 | -------------------------------------------------------------------------------- /2장_내장_시퀀스_타입/1_count_unique_words.py: -------------------------------------------------------------------------------- 1 | import string 2 | import sys 3 | 4 | 5 | def count_unique_word(): 6 | words = {} 7 | strip = string.whitespace + string.punctuation + string.digits + "\"'" 8 | for filename in sys.argv[1:]: 9 | with open(filename) as file: 10 | for line in file: 11 | for word in line.lower().split(): 12 | word = word.strip(strip) 13 | if len(word) > 2: 14 | words[word] = words.get(word, 0) + 1 15 | 16 | for word in sorted(words): 17 | print("'{0}': {1}번".format(word, words[word])) 18 | 19 | 20 | if __name__ == "__main__": 21 | count_unique_word() 22 | -------------------------------------------------------------------------------- /2장_내장_시퀀스_타입/2_runtime_lists_with_timeit_module.py: -------------------------------------------------------------------------------- 1 | def test1(): 2 | l = [] 3 | for i in range(1000): 4 | l = l + [i] 5 | 6 | 7 | def test2(): 8 | l = [] 9 | for i in range(1000): 10 | l.append(i) 11 | 12 | 13 | def test3(): 14 | l = [i for i in range(1000)] 15 | 16 | 17 | def test4(): 18 | l = list(range(1000)) 19 | 20 | 21 | if __name__ == "__main__": 22 | import timeit 23 | t1 = timeit.Timer("test1()", "from __main__ import test1") 24 | print("concat ", t1.timeit(number=1000), "milliseconds") 25 | t2 = timeit.Timer("test2()", "from __main__ import test2") 26 | print("append ", t2.timeit(number=1000), "milliseconds") 27 | t3 = timeit.Timer("test3()", "from __main__ import test3") 28 | print("comprehension ", t3.timeit(number=1000), "milliseconds") 29 | t4 = timeit.Timer("test4()", "from __main__ import test4") 30 | print("list range ", t4.timeit(number=1000), "milliseconds") 31 | -------------------------------------------------------------------------------- /2장_내장_시퀀스_타입/3_reversing_string.py: -------------------------------------------------------------------------------- 1 | def revert(s): 2 | if s: 3 | s = s[-1] + revert(s[:-1]) 4 | return s 5 | 6 | 7 | def revert2(string): 8 | return string[::-1] 9 | 10 | 11 | if __name__ == "__main__": 12 | str1 = "안녕 세상!" 13 | str2 = revert(str1) 14 | str3 = revert2(str1) 15 | print(str2) 16 | print(str3) 17 | -------------------------------------------------------------------------------- /2장_내장_시퀀스_타입/4_reversing_words_.py: -------------------------------------------------------------------------------- 1 | def reverser(string1, p1=0, p2=None): 2 | if len(string1) < 2: 3 | return string1 4 | p2 = p2 or len(string1)-1 5 | while p1 < p2: 6 | string1[p1], string1[p2] = string1[p2], string1[p1] 7 | p1 += 1 8 | p2 -= 1 9 | 10 | 11 | def reversing_words_setence_logic(string1): 12 | # 먼저, 문장 전체를 반전한다. 13 | reverser(string1) 14 | # print(string1) 15 | p = 0 16 | start = 0 17 | while p < len(string1): 18 | if string1[p] == u"\u0020": 19 | # 단어를 다시 반전한다(단어를 원위치로 돌려놓는다). 20 | reverser(string1, start, p-1) 21 | # print(string1) 22 | start = p+1 23 | p += 1 24 | # 마지막 단어를 반전한다(단어를 원위치로 돌려놓는다). 25 | reverser(string1, start, p-1) 26 | # print(string1) 27 | return ''.join(string1) 28 | 29 | 30 | if __name__ == "__main__": 31 | str1 = "파이썬 알고리즘 정말 재미있다" 32 | str2 = reversing_words_setence_logic(list(str1)) 33 | print(str2) 34 | -------------------------------------------------------------------------------- /2장_내장_시퀀스_타입/5_reversing_words.py: -------------------------------------------------------------------------------- 1 | def reverse_words_brute(string): 2 | word, sentence = [], [] 3 | for character in string: 4 | if character != " ": 5 | word.append(character) 6 | else: 7 | # 조건문에서 빈 리스트는 False다. 여러 공백이 있는 경우, 조건문을 건너뛴다. 8 | if word: 9 | sentence.append(''.join(word)) 10 | word = [] 11 | 12 | # 마지막 단어가 있다면, 문장에 추가한다. 13 | if word != '': 14 | sentence.append(''.join(word)) 15 | sentence.reverse() 16 | return " ".join(sentence) 17 | 18 | 19 | if __name__ == "__main__": 20 | str1 = "파이썬 알고리즘 정말 재미있다" 21 | str2 = reverse_words_brute(str1) 22 | print(str2) 23 | -------------------------------------------------------------------------------- /2장_내장_시퀀스_타입/6_reversing_words.py: -------------------------------------------------------------------------------- 1 | def reversing_words_slice(word): 2 | new_word = [] 3 | words = word.split(" ") 4 | for word in words[::-1]: 5 | new_word.append(word) 6 | return " ".join(new_word) 7 | 8 | 9 | if __name__ == "__main__": 10 | str1 = "파이썬 알고리즘 정말 재미있다" 11 | str2 = reversing_words_slice(str1) 12 | print(str2) 13 | -------------------------------------------------------------------------------- /2장_내장_시퀀스_타입/7_reversing_words.py: -------------------------------------------------------------------------------- 1 | def reversing_words(str1): 2 | words = str1.split(" ") 3 | rev_set = " ".join(reversed(words)) 4 | return rev_set 5 | 6 | 7 | def reversing_words2(str1): 8 | words = str1.split(" ") 9 | words.reverse() 10 | return " ".join(words) 11 | 12 | 13 | if __name__ == "__main__": 14 | str1 = "파이썬 알고리즘 정말 재미있다" 15 | str2 = reversing_words(str1) 16 | str3 = reversing_words2(str1) 17 | print(str2) 18 | print(str3) 19 | -------------------------------------------------------------------------------- /2장_내장_시퀀스_타입/8_simple_str_compression.py: -------------------------------------------------------------------------------- 1 | def str_compression(s): 2 | count, last = 1, "" 3 | list_aux = [] 4 | for i, c in enumerate(s): 5 | if last == c: 6 | count += 1 7 | else: 8 | if i != 0: 9 | list_aux.append(str(count)) 10 | list_aux.append(c) 11 | count = 1 12 | last = c 13 | list_aux.append(str(count)) 14 | return "".join(list_aux) 15 | 16 | 17 | if __name__ == "__main__": 18 | result = str_compression("aabcccccaaa") 19 | print(result) 20 | -------------------------------------------------------------------------------- /2장_내장_시퀀스_타입/9_permutation.py: -------------------------------------------------------------------------------- 1 | import itertools 2 | 3 | 4 | def perm(s): 5 | if len(s) < 2: 6 | return s 7 | res = [] 8 | for i, c in enumerate(s): 9 | for cc in perm(s[:i] + s[i+1:]): 10 | res.append(c + cc) 11 | return res 12 | 13 | 14 | def perm2(s): 15 | res = itertools.permutations(s) 16 | return ["".join(i) for i in res] 17 | 18 | 19 | if __name__ == "__main__": 20 | val = "012" 21 | print(perm(val)) 22 | print(perm2(val)) 23 | -------------------------------------------------------------------------------- /3장_컬렉션_데이터_구조/10_is_anagram_using_ord.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | 4 | def hash_func(astring): 5 | s = 0 6 | for one in astring: 7 | if one in string.whitespace: 8 | continue 9 | s = s + ord(one) 10 | return s 11 | 12 | 13 | def find_anagram_hash_function(word1, word2): 14 | return hash_func(word1) == hash_func(word2) 15 | 16 | 17 | def test_find_anagram_hash_function(): 18 | word1 = "buffy" 19 | word2 = "bffyu" 20 | word3 = "bffya" 21 | assert(find_anagram_hash_function(word1, word2) is True) 22 | assert(find_anagram_hash_function(word1, word3) is False) 23 | print("테스트 통과!") 24 | 25 | 26 | if __name__ == "__main__": 27 | test_find_anagram_hash_function() 28 | -------------------------------------------------------------------------------- /3장_컬렉션_데이터_구조/11_find_dice_probabilities.py: -------------------------------------------------------------------------------- 1 | from collections import Counter, defaultdict 2 | 3 | 4 | def find_dice_probabilities(S, n_faces=6): 5 | if S > 2 * n_faces or S < 2: 6 | return None 7 | 8 | cdict = Counter() 9 | ddict = defaultdict(list) 10 | 11 | # 두 주사위의 합을 모두 더해서 딕셔너리에 넣는다. 12 | for dice1 in range(1, n_faces+1): 13 | for dice2 in range(1, n_faces+1): 14 | t = [dice1, dice2] 15 | cdict[dice1+dice2] += 1 16 | ddict[dice1+dice2].append(t) 17 | 18 | return [cdict[S], ddict[S]] 19 | 20 | 21 | def test_find_dice_probabilities(): 22 | n_faces = 6 23 | S = 5 24 | results = find_dice_probabilities(S, n_faces) 25 | print(results) 26 | assert(results[0] == len(results[1])) 27 | print("테스트 통과!") 28 | 29 | 30 | if __name__ == "__main__": 31 | test_find_dice_probabilities() 32 | -------------------------------------------------------------------------------- /3장_컬렉션_데이터_구조/12_delete_duplicate_char_str.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | 4 | def delete_unique_word(str1): 5 | table_c = {key: 0 for key in string.ascii_lowercase} 6 | for i in str1: 7 | table_c[i] += 1 8 | for key, value in table_c.items(): 9 | if value > 1: 10 | str1 = str1.replace(key, "") 11 | return str1 12 | 13 | 14 | def test_delete_unique_word(): 15 | str1 = "google" 16 | assert(delete_unique_word(str1) == "le") 17 | print("테스트 통과!") 18 | 19 | 20 | if __name__ == "__main__": 21 | test_delete_unique_word() 22 | -------------------------------------------------------------------------------- /3장_컬렉션_데이터_구조/1_set_operations_with_lists.py: -------------------------------------------------------------------------------- 1 | def remove_dup(l1): 2 | """ 리스트의 중복된 항목을 제거한 후 반환한다. """ 3 | return list(set(l1)) 4 | 5 | 6 | def intersection(l1, l2): 7 | """ 교집합 결과를 반환한다. """ 8 | return list(set(l1) & set(l2)) 9 | 10 | 11 | def union(l1, l2): 12 | """ 합집합 결과를 반환한다. """ 13 | return list(set(l1) | set(l2)) 14 | 15 | 16 | def test_sets_operations_with_lists(): 17 | l1 = [1, 2, 3, 4, 5, 5, 9, 11, 11, 15] 18 | l2 = [4, 5, 6, 7, 8] 19 | l3 = [] 20 | assert(remove_dup(l1) == [1, 2, 3, 4, 5, 9, 11, 15]) 21 | assert(intersection(l1, l2) == [4, 5]) 22 | assert(union(l1, l2) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 15]) 23 | assert(remove_dup(l3) == []) 24 | assert(intersection(l3, l2) == l3) 25 | assert(sorted(union(l3, l2)) == sorted(l2)) 26 | print("테스트 통과!") 27 | 28 | 29 | if __name__ == "__main__": 30 | test_sets_operations_with_lists() 31 | -------------------------------------------------------------------------------- /3장_컬렉션_데이터_구조/2_set_operations_with_dicts.py: -------------------------------------------------------------------------------- 1 | def set_operations_with_dict(): 2 | pairs = [("a", 1), ("b", 2), ("c", 3)] 3 | d1 = dict(pairs) 4 | print("딕셔너리1\t: {0}".format(d1)) 5 | 6 | d2 = {"a": 1, "c": 2, "d": 3, "e": 4} 7 | print("딕셔너리2\t: {0}".format(d2)) 8 | 9 | intersection = d1.keys() & d2.keys() 10 | print("d1 ∩ d2 (키)\t: {0}".format(intersection)) 11 | 12 | intersection_items = d1.items() & d2.items() 13 | print("d1 ∩ d2 (키,값)\t: {0}".format(intersection_items)) 14 | 15 | subtraction1 = d1.keys() - d2.keys() 16 | print("d1 - d2 (키)\t: {0}".format(subtraction1)) 17 | 18 | subtraction2 = d2.keys() - d1.keys() 19 | print("d2 - d1 (키)\t: {0}".format(subtraction2)) 20 | 21 | subtraction_items = d1.items() - d2.items() 22 | print("d1 - d2 (키,값)\t: {0}".format(subtraction_items)) 23 | 24 | """ 딕셔너리의 특정 키를 제외한다. """ 25 | d3 = {key: d2[key] for key in d2.keys() - {"c", "d"}} 26 | print("d2 - {{c, d}}\t: {0}".format(d3)) 27 | 28 | 29 | if __name__ == "__main__": 30 | set_operations_with_dict() 31 | -------------------------------------------------------------------------------- /3장_컬렉션_데이터_구조/3_setdefault_example.py: -------------------------------------------------------------------------------- 1 | def usual_dict(dict_data): 2 | """ dict[key] 사용 """ 3 | newdata = {} 4 | for k, v in dict_data: 5 | if k in newdata: 6 | newdata[k].append(v) 7 | else: 8 | newdata[k] = [v] 9 | return newdata 10 | 11 | 12 | def setdefault_dict(dict_data): 13 | """ setdefault() 메서드 사용 """ 14 | newdata = {} 15 | for k, v in dict_data: 16 | newdata.setdefault(k, []).append(v) 17 | return newdata 18 | 19 | 20 | def test_setdef(): 21 | dict_data = (("key1", "value1"), 22 | ("key1", "value2"), 23 | ("key2", "value3"), 24 | ("key2", "value4"), 25 | ("key2", "value5"),) 26 | print(usual_dict(dict_data)) 27 | print(setdefault_dict(dict_data)) 28 | 29 | 30 | if __name__ == "__main__": 31 | test_setdef() 32 | -------------------------------------------------------------------------------- /3장_컬렉션_데이터_구조/4_runtime_dicts_with_timeit_module.py: -------------------------------------------------------------------------------- 1 | import timeit 2 | import random 3 | 4 | for i in range(10000, 1000001, 20000): 5 | t = timeit.Timer("random.randrange(%d) in x" % i, 6 | "from __main__ import random, x") 7 | x = list(range(i)) # 리스트 8 | lst_time = t.timeit(number=1000) 9 | x = {j: None for j in range(i)} # 딕셔너리 10 | d_time = t.timeit(number=1000) 11 | print("%d,%10.3f,%10.3f" % (i, lst_time, d_time)) 12 | -------------------------------------------------------------------------------- /3장_컬렉션_데이터_구조/5_defaultdict_example.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | 4 | def defaultdict_example(): 5 | pairs = {("a", 1), ("b", 2), ("c", 3)} 6 | 7 | # 일반 딕셔너리 8 | d1 = {} 9 | for key, value in pairs: 10 | if key not in d1: 11 | d1[key] = [] 12 | d1[key].append(value) 13 | print(d1) 14 | 15 | # defaultdict 16 | d2 = defaultdict(list) 17 | for key, value in pairs: 18 | d2[key].append(value) 19 | print(d2) 20 | 21 | 22 | if __name__ == "__main__": 23 | defaultdict_example() 24 | -------------------------------------------------------------------------------- /3장_컬렉션_데이터_구조/6_orderedDict_example.py: -------------------------------------------------------------------------------- 1 | from collections import OrderedDict 2 | 3 | 4 | def orderedDict_example(): 5 | pairs = [("c", 1), ("b", 2), ("a", 3)] 6 | 7 | # 일반 딕셔너리 8 | d1 = {} 9 | for key, value in pairs: 10 | if key not in d1: 11 | d1[key] = [] 12 | d1[key].append(value) 13 | for key in d1: 14 | print(key, d1[key]) 15 | 16 | # OrderedDict 17 | d2 = OrderedDict(pairs) 18 | for key in d2: 19 | print(key, d2[key]) 20 | 21 | 22 | if __name__ == "__main__": 23 | orderedDict_example() 24 | -------------------------------------------------------------------------------- /3장_컬렉션_데이터_구조/7_counterDict_example.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | 4 | def counter_example(): 5 | """ 항목의 발생 횟수를 매핑하는 딕셔너리를 생성한다. """ 6 | seq1 = [1, 2, 3, 5, 1, 2, 5, 5, 2, 5, 1, 4] 7 | seq_counts = Counter(seq1) 8 | print(seq_counts) 9 | 10 | """ 항목의 발생 횟수를 수동으로 갱신하거나, update() 메서드를 사용할 수 있다. """ 11 | seq2 = [1, 2, 3] 12 | seq_counts.update(seq2) 13 | print(seq_counts) 14 | 15 | seq3 = [1, 4, 3] 16 | for key in seq3: 17 | seq_counts[key] += 1 18 | print(seq_counts) 19 | 20 | """ a+b, a-b와 같은 셋 연산을 사용할 수 있다. """ 21 | seq_counts_2 = Counter(seq3) 22 | print(seq_counts_2) 23 | print(seq_counts + seq_counts_2) 24 | print(seq_counts - seq_counts_2) 25 | 26 | 27 | if __name__ == "__main__": 28 | counter_example() 29 | -------------------------------------------------------------------------------- /3장_컬렉션_데이터_구조/8_find_top_N_recurring_words.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | 4 | def find_top_N_recurring_words(seq, N): 5 | dcounter = Counter() 6 | for word in seq.split(): 7 | dcounter[word] += 1 8 | return dcounter.most_common(N) 9 | 10 | 11 | def test_find_top_N_recurring_words(): 12 | seq = "버피 에인절 몬스터 잰더 윌로우 버피 몬스터 슈퍼 버피 에인절" 13 | N = 3 14 | assert(find_top_N_recurring_words(seq, N) == 15 | [("버피", 3), ("에인절", 2), ("몬스터", 2)]) 16 | print("테스트 통과!") 17 | 18 | 19 | if __name__ == "__main__": 20 | test_find_top_N_recurring_words() 21 | -------------------------------------------------------------------------------- /3장_컬렉션_데이터_구조/9_is_anagram.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | 4 | def is_anagram(s1, s2): 5 | counter = Counter() 6 | for c in s1: 7 | counter[c] += 1 8 | for c in s2: 9 | counter[c] -= 1 10 | for i in counter.values(): 11 | if i: 12 | return False 13 | return True 14 | 15 | 16 | def test_is_anagram(): 17 | s1 = "marina" 18 | s2 = "aniram" 19 | assert(is_anagram(s1, s2) is True) 20 | s1 = "google" 21 | s2 = "gouglo" 22 | assert(is_anagram(s1, s2) is False) 23 | print("테스트 통과!") 24 | 25 | 26 | if __name__ == "__main__": 27 | test_is_anagram() 28 | -------------------------------------------------------------------------------- /4장_구조와_모듈/1_sys_example.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | 4 | def main(): 5 | for arg in sys.argv[1:]: 6 | print(arg) 7 | 8 | 9 | if __name__ == "__main__": 10 | main() 11 | -------------------------------------------------------------------------------- /4장_구조와_모듈/2_fib_generator.py: -------------------------------------------------------------------------------- 1 | def fib_generator(): 2 | a, b = 0, 1 3 | while True: 4 | yield b 5 | a, b = b, a+b 6 | 7 | 8 | if __name__ == "__main__": 9 | fib = fib_generator() 10 | print(next(fib)) 11 | print(next(fib)) 12 | print(next(fib)) 13 | print(next(fib)) 14 | -------------------------------------------------------------------------------- /4장_구조와_모듈/3_grep_word_from_files.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | 4 | def grep_word_from_files(): 5 | word = sys.argv[1] 6 | for filename in sys.argv[2:]: 7 | with open(filename) as file: 8 | for lino, line in enumerate(file, start=1): 9 | if word in line: 10 | print("{0}:{1}:{2:.40}".format( 11 | filename, lino, line.rstrip())) 12 | 13 | 14 | if __name__ == "__main__": 15 | if len(sys.argv) < 2: 16 | print("Usage: python {0} [word] [file ...]".format( 17 | sys.argv[0])) 18 | sys.exit() 19 | else: 20 | grep_word_from_files() 21 | -------------------------------------------------------------------------------- /4장_구조와_모듈/4_remove_blank_lines.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | 4 | def read_data(filename): 5 | lines = [] 6 | fh = None 7 | try: 8 | fh = open(filename) 9 | for line in fh: 10 | if line.strip(): 11 | lines.append(line) 12 | except (IOError, OSError) as err: 13 | print(err) 14 | finally: 15 | if fh is not None: 16 | fh.close() 17 | return lines 18 | 19 | 20 | def write_data(lines, filename): 21 | fh = None 22 | try: 23 | fh = open(filename, "w") 24 | for line in lines: 25 | fh.write(line) 26 | except (EnvironmentError) as err: 27 | print(err) 28 | finally: 29 | if fh is not None: 30 | fh.close() 31 | 32 | 33 | def remove_blank_lines(): 34 | if len(sys.argv) < 2: 35 | print("Usage: python {0} [file ...]".format(sys.argv[0])) 36 | 37 | for filename in sys.argv[1:]: 38 | lines = read_data(filename) 39 | if lines: 40 | write_data(lines, filename) 41 | 42 | 43 | if __name__ == "__main__": 44 | remove_blank_lines() 45 | -------------------------------------------------------------------------------- /4장_구조와_모듈/5_remove_blank_lines_with.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | 4 | def read_data(filename): 5 | lines = [] 6 | with open(filename) as fh: 7 | for line in fh: 8 | if line.strip(): 9 | lines.append(line) 10 | return lines 11 | 12 | 13 | def write_data(lines, filename): 14 | fh = None 15 | with open(filename, "w") as fh: 16 | for line in lines: 17 | fh.write(line) 18 | 19 | 20 | def remove_blank_lines(): 21 | if len(sys.argv) < 2: 22 | print("Usage: python {0} [file ...]".format(sys.argv[0])) 23 | 24 | for filename in sys.argv[1:]: 25 | lines = read_data(filename) 26 | if lines: 27 | write_data(lines, filename) 28 | 29 | 30 | if __name__ == "__main__": 31 | remove_blank_lines() 32 | -------------------------------------------------------------------------------- /4장_구조와_모듈/6_change_ext_file.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import shutil 4 | 5 | 6 | def change_file_ext(): 7 | if len(sys.argv) < 2: 8 | print("Usage: python {0} filename.old_ext 'new_ext'".format( 9 | sys.argv[0])) 10 | sys.exit() 11 | 12 | name = os.path.splitext(sys.argv[1])[0] + "." + sys.argv[2] 13 | print(name) 14 | 15 | try: 16 | shutil.copyfile(sys.argv[1], name) 17 | except OSError as err: 18 | print(err) 19 | 20 | 21 | if __name__ == "__main__": 22 | change_file_ext() 23 | -------------------------------------------------------------------------------- /4장_구조와_모듈/hello.py: -------------------------------------------------------------------------------- 1 | hello = "hello" 2 | 3 | 4 | def world(): 5 | return "world" 6 | 7 | 8 | if __name__ == "__main__": 9 | print("{0} 직접 실행됨".format(__name__)) 10 | else: 11 | print("{0} 임포트됨".format(__name__)) 12 | -------------------------------------------------------------------------------- /4장_구조와_모듈/hello.txt: -------------------------------------------------------------------------------- 1 | hello = "hello" 2 | 3 | 4 | def world(): 5 | return "world" 6 | 7 | 8 | if __name__ == "__main__": 9 | print("{0} 직접 실행됨".format(__name__)) 10 | else: 11 | print("{0} 임포트 됨".format(__name__)) 12 | -------------------------------------------------------------------------------- /5장_객체지향_설계/10_adapter_pattern_BETTER.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://github.com/PJUllrich/Design-Patterns 3 | """ 4 | 5 | 6 | class Elf(object): 7 | def nall_nin(self): 8 | print("Elf says: Calling the Overload ...") 9 | 10 | 11 | class Dwarf(object): 12 | def estver_narho(self): 13 | print("Dwarf says: Calling the Overload ...") 14 | 15 | 16 | class Human(object): 17 | def ring_mig(self): 18 | print("Human says: Calling the Overload ...") 19 | 20 | 21 | class ElfAdapter(object): 22 | def __init__(self, elf): 23 | self.elf = elf 24 | 25 | def call_me(self): 26 | self.elf.nall_nin() 27 | 28 | 29 | class DwarfAdapter(object): 30 | def __init__(self, dwarf): 31 | self.dwarf = dwarf 32 | 33 | def call_me(self): 34 | self.dwarf.estver_narho() 35 | 36 | 37 | class HumanAdapter(object): 38 | def __init__(self, human): 39 | self.human = human 40 | 41 | def call_me(self): 42 | self.human.ring_mig() 43 | 44 | 45 | if __name__ == "__main__": 46 | minions = [ElfAdapter(Elf()), DwarfAdapter( 47 | Dwarf()), HumanAdapter(Human())] 48 | 49 | for minion in minions: 50 | minion.call_me() 51 | -------------------------------------------------------------------------------- /5장_객체지향_설계/1_hash_and_eq_NO.py: -------------------------------------------------------------------------------- 1 | class Symbol(object): 2 | def __init__(self, value): 3 | self.value = value 4 | 5 | 6 | if __name__ == "__main__": 7 | x = Symbol("Py") 8 | y = Symbol("Py") 9 | 10 | symbols = set() 11 | symbols.add(x) 12 | symbols.add(y) 13 | 14 | print(x is y) 15 | print(x == y) 16 | print(len(symbols)) 17 | -------------------------------------------------------------------------------- /5장_객체지향_설계/2_hash_and_eq_NO.py: -------------------------------------------------------------------------------- 1 | class Symbol(object): 2 | def __init__(self, value): 3 | self.value = value 4 | 5 | def __eq__(self, other): 6 | if isinstance(self, other.__class__): 7 | return self.value == other.value 8 | else: 9 | return NotImplemented 10 | 11 | 12 | if __name__ == "__main__": 13 | x = Symbol("Py") 14 | y = Symbol("Py") 15 | 16 | symbols = set() 17 | symbols.add(x) 18 | symbols.add(y) 19 | 20 | print(x is y) 21 | print(x == y) 22 | print(len(symbols)) 23 | -------------------------------------------------------------------------------- /5장_객체지향_설계/3_hash_and_eq_OK.py: -------------------------------------------------------------------------------- 1 | class Symbol(object): 2 | def __init__(self, value): 3 | self.value = value 4 | 5 | def __eq__(self, other): 6 | if isinstance(self, other.__class__): 7 | return self.value == other.value 8 | else: 9 | return NotImplemented 10 | 11 | def __hash__(self): 12 | return hash(self.value) 13 | 14 | 15 | if __name__ == "__main__": 16 | x = Symbol("Py") 17 | y = Symbol("Py") 18 | 19 | symbols = set() 20 | symbols.add(x) 21 | symbols.add(y) 22 | 23 | print(x is y) 24 | print(x == y) 25 | print(len(symbols)) 26 | -------------------------------------------------------------------------------- /5장_객체지향_설계/4_benchmark_decorator.py: -------------------------------------------------------------------------------- 1 | import random 2 | import time 3 | 4 | 5 | def benchmark(func): 6 | def wrapper(*args, **kwargs): 7 | t = time.perf_counter() 8 | res = func(*args, **kwargs) 9 | print("{0} {1}".format(func.__name__, time.perf_counter()-t)) 10 | return res 11 | return wrapper 12 | 13 | 14 | @benchmark 15 | def random_tree(n): 16 | temp = [n for n in range(n)] 17 | for i in range(n+1): 18 | temp[random.choice(temp)] = random.choice(temp) 19 | return temp 20 | 21 | 22 | if __name__ == "__main__": 23 | random_tree(10000) 24 | -------------------------------------------------------------------------------- /5장_객체지향_설계/5_class_and_static_decorator.py: -------------------------------------------------------------------------------- 1 | class A(object): 2 | _hello = True 3 | 4 | def foo(self, x): 5 | print("foo({0}, {1}) 실행".format(self, x)) 6 | 7 | @classmethod 8 | def class_foo(cls, x): 9 | print("class_foo({0}, {1}) 실행: {2}".format(cls, x, cls._hello)) 10 | 11 | @staticmethod 12 | def static_foo(x): 13 | print("static_foo({0}) 실행".format(x)) 14 | 15 | 16 | if __name__ == "__main__": 17 | a = A() 18 | a.foo(1) 19 | a.class_foo(2) 20 | A.class_foo(2) 21 | a.static_foo(3) 22 | A.static_foo(3) 23 | -------------------------------------------------------------------------------- /5장_객체지향_설계/6_observer_pattern_with_set.py: -------------------------------------------------------------------------------- 1 | class Subscriber(object): 2 | def __init__(self, name): 3 | self.name = name 4 | 5 | def update(self, message): 6 | print("{0}, {1}".format(self.name, message)) 7 | 8 | 9 | class Publisher(object): 10 | def __init__(self): 11 | self.subscribers = set() 12 | 13 | def register(self, who): 14 | self.subscribers.add(who) 15 | 16 | def unregister(self, who): 17 | self.subscribers.discard(who) 18 | 19 | def dispatch(self, message): 20 | for subscriber in self.subscribers: 21 | subscriber.update(message) 22 | 23 | 24 | if __name__ == "__main__": 25 | pub = Publisher() 26 | 27 | astin = Subscriber("아스틴") 28 | james = Subscriber("제임스") 29 | jeff = Subscriber("제프") 30 | 31 | pub.register(astin) 32 | pub.register(james) 33 | pub.register(jeff) 34 | 35 | pub.dispatch("점심시간입니다.") 36 | pub.unregister(jeff) 37 | pub.dispatch("퇴근시간입니다.") 38 | -------------------------------------------------------------------------------- /5장_객체지향_설계/7_observer_pattern_with_dict.py: -------------------------------------------------------------------------------- 1 | class SubscriberOne(object): 2 | def __init__(self, name): 3 | self.name = name 4 | 5 | def update(self, message): 6 | print("{0}, {1}".format(self.name, message)) 7 | 8 | 9 | class SubscriberTwo(object): 10 | def __init__(self, name): 11 | self.name = name 12 | 13 | def receive(self, message): 14 | print("{0}, {1}".format(self.name, message)) 15 | 16 | 17 | class Publisher(object): 18 | def __init__(self): 19 | self.subscribers = dict() 20 | 21 | def register(self, who, callback=None): 22 | if callback is None: 23 | callback = getattr(who, 'update') 24 | self.subscribers[who] = callback 25 | 26 | def unregister(self, who): 27 | del self.subscribers[who] 28 | 29 | def dispatch(self, message): 30 | for subscriber, callback in self.subscribers.items(): 31 | callback(message) 32 | 33 | 34 | if __name__ == "__main__": 35 | pub = Publisher() 36 | 37 | astin = SubscriberOne("아스틴") 38 | james = SubscriberTwo("제임스") 39 | jeff = SubscriberOne("제프") 40 | 41 | pub.register(astin, astin.update) 42 | pub.register(james, james.receive) 43 | pub.register(jeff) 44 | 45 | pub.dispatch("점심시간입니다.") 46 | pub.unregister(jeff) 47 | pub.dispatch("퇴근시간입니다.") 48 | -------------------------------------------------------------------------------- /5장_객체지향_설계/8_observer_pattern_with_event.py: -------------------------------------------------------------------------------- 1 | class Subscriber(object): 2 | def __init__(self, name): 3 | self.name = name 4 | 5 | def update(self, message): 6 | print("{0}, {1}".format(self.name, message)) 7 | 8 | 9 | class Publisher(object): 10 | def __init__(self, events): 11 | self.subscribers = {event: dict() for event in events} 12 | 13 | def get_subscribers(self, event): 14 | return self.subscribers[event] 15 | 16 | def register(self, event, who, callback=None): 17 | if callback is None: 18 | callback = getattr(who, "update") 19 | self.get_subscribers(event)[who] = callback 20 | 21 | def unregister(self, event, who): 22 | del self.get_subscribers(event)[who] 23 | 24 | def dispatch(self, event, message): 25 | for subscriber, callback in self.get_subscribers(event).items(): 26 | callback(message) 27 | 28 | 29 | if __name__ == "__main__": 30 | pub = Publisher(["점심", "퇴근"]) 31 | 32 | astin = Subscriber("아스틴") 33 | james = Subscriber("제임스") 34 | jeff = Subscriber("제프") 35 | 36 | pub.register("점심", astin) 37 | pub.register("퇴근", astin) 38 | pub.register("퇴근", james) 39 | pub.register("점심", jeff) 40 | 41 | pub.dispatch("점심", "점심시간입니다.") 42 | pub.dispatch("퇴근", "저녁시간 입니다.") 43 | -------------------------------------------------------------------------------- /5장_객체지향_설계/9_adapter_pattern_OK.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://github.com/PJUllrich/Design-Patterns 3 | """ 4 | 5 | 6 | class Elf(object): 7 | def nall_nin(self): 8 | print("Elf says: Calling the Overload ...") 9 | 10 | 11 | class Dwarf(object): 12 | def estver_narho(self): 13 | print("Dwarf says: Calling the Overload ...") 14 | 15 | 16 | class Human(object): 17 | def ring_mig(self): 18 | print("Human says: Calling the Overload ...") 19 | 20 | 21 | if __name__ == "__main__": 22 | minions = [Elf(), Dwarf(), Human()] 23 | 24 | for minion in minions: 25 | if isinstance(minion, Elf): 26 | minion.nall_nin() 27 | elif isinstance(minion, Dwarf): 28 | minion.estver_narho() 29 | else: 30 | minion.ring_mig() 31 | -------------------------------------------------------------------------------- /5장_객체지향_설계/hash_and_eq.py: -------------------------------------------------------------------------------- 1 | class Symbol(object): 2 | def __init__(self, value): 3 | self.value = value 4 | 5 | # def __eq__(self, other): 6 | # if isinstance(self, other.__class__): 7 | # return self.value == other.value 8 | # else: 9 | # return NotImplemented 10 | 11 | # def __hash__(self): 12 | # return hash(self.value) 13 | 14 | symbols = {} 15 | 16 | @staticmethod 17 | def get(key): 18 | if key in Symbol.symbols: 19 | return Symbol.symbols[key] 20 | else: 21 | value = Symbol(key) 22 | Symbol.symbols[key] = value 23 | return value 24 | 25 | 26 | if __name__ == "__main__": 27 | x = Symbol.get("Py") 28 | y = Symbol.get("Py") 29 | 30 | symbols = set() 31 | symbols.add(x) 32 | symbols.add(y) 33 | 34 | print(x is y) 35 | print(x == y) 36 | print(len(symbols)) 37 | -------------------------------------------------------------------------------- /6장_파이썬_고급/1_threading_with_queue.py: -------------------------------------------------------------------------------- 1 | import queue 2 | import threading 3 | 4 | q = queue.Queue() 5 | 6 | 7 | def worker(num): 8 | while True: 9 | item = q.get() 10 | if item is None: 11 | break 12 | # 작업을 처리한다. 13 | print("스레드 {0} : 처리 완료 {1}".format(num+1, item)) 14 | q.task_done() 15 | 16 | 17 | if __name__ == "__main__": 18 | num_worker_threads = 5 19 | threads = [] 20 | for i in range(num_worker_threads): 21 | t = threading.Thread(target=worker, args=(i,)) 22 | t.start() 23 | threads.append(t) 24 | 25 | for item in range(20): 26 | q.put(item) 27 | 28 | # 모든 작업이 끝날 때까지 대기한다(block). 29 | q.join() 30 | 31 | # 워커 스레드를 종료한다(stop). 32 | for i in range(num_worker_threads): 33 | q.put(None) 34 | for t in threads: 35 | t.join() 36 | -------------------------------------------------------------------------------- /6장_파이썬_고급/2_threading_mutex.py: -------------------------------------------------------------------------------- 1 | from threading import Thread, Lock 2 | import threading 3 | 4 | 5 | def worker(mutex, data, thread_safe): 6 | if thread_safe: 7 | mutex.acquire() 8 | try: 9 | print("스레드 {0}: {1}\n".format(threading.get_ident(), data)) 10 | finally: 11 | if thread_safe: 12 | mutex.release() 13 | 14 | 15 | if __name__ == "__main__": 16 | threads = [] 17 | thread_safe = True 18 | mutex = Lock() 19 | for i in range(20): 20 | t = Thread(target=worker, args=(mutex, i, thread_safe)) 21 | t.start() 22 | threads.append(t) 23 | for t in threads: 24 | t.join() 25 | -------------------------------------------------------------------------------- /6장_파이썬_고급/3_threading_semaphore.py: -------------------------------------------------------------------------------- 1 | import threading 2 | import time 3 | 4 | 5 | class ThreadPool(object): 6 | def __init__(self): 7 | self.active = [] 8 | self.lock = threading.Lock() 9 | 10 | def acquire(self, name): 11 | with self.lock: 12 | self.active.append(name) 13 | print("획득: {0} | 스레드 풀: {1}".format(name, self.active)) 14 | 15 | def release(self, name): 16 | with self.lock: 17 | self.active.remove(name) 18 | print("반환: {0} | 스레드 풀: {1}".format(name, self.active)) 19 | 20 | 21 | def worker(semaphore, pool): 22 | with semaphore: 23 | name = threading.currentThread().getName() 24 | pool.acquire(name) 25 | time.sleep(1) 26 | pool.release(name) 27 | 28 | 29 | if __name__ == '__main__': 30 | threads = [] 31 | pool = ThreadPool() 32 | semaphore = threading.Semaphore(3) 33 | for i in range(10): 34 | t = threading.Thread( 35 | target=worker, name="스레드 " + str(i), args=(semaphore, pool)) 36 | t.start() 37 | threads.append(t) 38 | for t in threads: 39 | t.join() 40 | -------------------------------------------------------------------------------- /6장_파이썬_고급/4_threading_with_condition.py: -------------------------------------------------------------------------------- 1 | import threading 2 | 3 | 4 | def consumer(cond): 5 | name = threading.currentThread().getName() 6 | print("{0} 시작".format(name)) 7 | with cond: 8 | print("{0} 대기".format(name)) 9 | cond.wait() 10 | print("{0} 자원 소비".format(name)) 11 | 12 | 13 | def producer(cond): 14 | name = threading.currentThread().getName() 15 | print("{0} 시작".format(name)) 16 | with cond: 17 | print("{0} 자원 생산 후 모든 소비자에게 알림".format(name)) 18 | cond.notifyAll() 19 | 20 | 21 | if __name__ == "__main__": 22 | condition = threading.Condition() 23 | consumer1 = threading.Thread( 24 | name="소비자1", target=consumer, args=(condition,)) 25 | consumer2 = threading.Thread( 26 | name="소비자2", target=consumer, args=(condition,)) 27 | producer = threading.Thread(name="생산자", target=producer, args=(condition,)) 28 | 29 | consumer1.start() 30 | consumer2.start() 31 | producer.start() 32 | -------------------------------------------------------------------------------- /6장_파이썬_고급/5_using_time_module.py: -------------------------------------------------------------------------------- 1 | import time 2 | 3 | 4 | def sumOfN2(n): 5 | start = time.time() 6 | theSum = 0 7 | for i in range(1, n+1): 8 | theSum = theSum + i 9 | end = time.time() 10 | return theSum, end-start 11 | 12 | 13 | if __name__ == "__main__": 14 | n = 5 15 | print("총 합계: %d\t 시간: %10.7f초" % sumOfN2(n)) 16 | n = 200 17 | print("총 합계: %d\t 시간: %10.7f초" % sumOfN2(n)) 18 | -------------------------------------------------------------------------------- /6장_파이썬_고급/coroutine.py: -------------------------------------------------------------------------------- 1 | """ 2 | [코딩도장] 코루틴 3 | https://dojang.io/mod/page/view.php?id=1122 4 | """ 5 | 6 | 7 | def number_coroutine(): 8 | try: 9 | while True: 10 | x = (yield) 11 | print(x) 12 | except GeneratorExit: 13 | print("종료") 14 | 15 | 16 | def sum_coroutine(): 17 | try: 18 | total = 0 19 | while True: 20 | x = (yield total) 21 | if x is None: 22 | return total # raise StopIteration(total) 23 | total += x 24 | except RuntimeError as e: 25 | print(e) 26 | yield total 27 | 28 | 29 | def accumulate(): 30 | while True: 31 | total = yield from sum_coroutine() 32 | print(total) 33 | 34 | 35 | if __name__ == "__main__": 36 | # 1 37 | co = number_coroutine() 38 | next(co) 39 | co.send(1) 40 | co.send(2) 41 | co.send(3) 42 | co.close() 43 | 44 | # 2 45 | sco = sum_coroutine() 46 | print(next(sco)) 47 | print(sco.send(1)) 48 | print(sco.send(2)) 49 | print(sco.send(3)) 50 | print(sco.throw(RuntimeError, "예외")) 51 | 52 | # 3 53 | aco = accumulate() 54 | next(aco) 55 | 56 | for i in range(11): 57 | aco.send(i) 58 | aco.send(None) 59 | -------------------------------------------------------------------------------- /6장_파이썬_고급/event_simple.py: -------------------------------------------------------------------------------- 1 | """ 2 | [한빛미디어] 고성능 파이썬 3 | """ 4 | 5 | from queue import Queue 6 | import time 7 | 8 | eventloop = None 9 | 10 | 11 | class EventLoop(Queue): 12 | def start(self): 13 | while True: 14 | function = self.get() 15 | function() 16 | time.sleep(1) 17 | 18 | 19 | def do_hello(): 20 | global eventloop 21 | print("hello") 22 | eventloop.put(do_world) 23 | 24 | 25 | def do_world(): 26 | global eventloop 27 | print("world") 28 | eventloop.put(do_hello) 29 | 30 | 31 | if __name__ == "__main__": 32 | eventloop = EventLoop() 33 | eventloop.put(do_hello) 34 | eventloop.start() 35 | -------------------------------------------------------------------------------- /6장_파이썬_고급/test_pytest.py: -------------------------------------------------------------------------------- 1 | def func(x): 2 | return x + 1 3 | 4 | 5 | def test_answer(): 6 | assert func(3) == 51 7 | -------------------------------------------------------------------------------- /6장_파이썬_고급/threading_event.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://www.bogotobogo.com/python/Multithread/python_multithreading_Event_Objects_between_Threads.php 3 | """ 4 | 5 | import threading 6 | import time 7 | import logging 8 | 9 | logging.basicConfig(level=logging.DEBUG, 10 | format='(%(threadName)s) %(message)s',) 11 | 12 | 13 | def wait_for_event(event): 14 | logging.debug("wait_for_event 시작") 15 | event_is_set = event.wait() 16 | logging.debug("이벤트 셋: {0}".format(event_is_set)) 17 | 18 | 19 | def wait_for_event_timeout(event, t): 20 | while not event.isSet(): 21 | logging.debug("wait_for_event_timeout 시작") 22 | event_is_set = event.wait(t) 23 | logging.debug("이벤트 셋: {0}".format(event_is_set)) 24 | if event_is_set: 25 | logging.debug("이벤트 수행") 26 | else: 27 | logging.debug("다른 일 수행") 28 | 29 | 30 | if __name__ == "__main__": 31 | event = threading.Event() 32 | t1 = threading.Thread(name="Blocking", 33 | target=wait_for_event, 34 | args=(event,)) 35 | t1.start() 36 | 37 | t2 = threading.Thread(name="Non-Blocking", 38 | target=wait_for_event_timeout, 39 | args=(event, 2)) 40 | t2.start() 41 | 42 | logging.debug("Event.set()이 호출될 때까지 대기") 43 | time.sleep(3) 44 | event.set() 45 | logging.debug("이벤트 설정됨") 46 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/12_hash_table.py: -------------------------------------------------------------------------------- 1 | from linkedListFIFO import LinkedListFIFO 2 | 3 | 4 | class HashTableLL(object): 5 | def __init__(self, size): 6 | self.size = size 7 | self.slots = [] 8 | self._createHashTable() 9 | 10 | def _createHashTable(self): 11 | for i in range(self.size): 12 | self.slots.append(LinkedListFIFO()) 13 | 14 | def _find(self, item): 15 | return item % self.size 16 | 17 | def _add(self, item): 18 | index = self._find(item) 19 | self.slots[index].addNode(item) 20 | 21 | def _delete(self, item): 22 | index = self._find(item) 23 | self.slots[index].deleteNodeByValue(item) 24 | 25 | def _print(self): 26 | for i in range(self.size): 27 | print("슬롯(slot) {0}:".format(i)) 28 | self.slots[i]._printList() 29 | 30 | 31 | def test_hash_tables(): 32 | H1 = HashTableLL(3) 33 | for i in range(0, 20): 34 | H1._add(i) 35 | H1._print() 36 | print("\n항목 0, 1, 2를 삭제합니다.") 37 | H1._delete(0) 38 | H1._delete(1) 39 | H1._delete(2) 40 | H1._print() 41 | 42 | 43 | if __name__ == "__main__": 44 | test_hash_tables() 45 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/13_reverse_string_with_stack.py: -------------------------------------------------------------------------------- 1 | from stack import Stack 2 | 3 | 4 | def reverse_string_with_stack(str1): 5 | s = Stack() 6 | revStr = "" 7 | 8 | for c in str1: 9 | s.push(c) 10 | 11 | while not s.isEmpty(): 12 | revStr += s.pop() 13 | 14 | return revStr 15 | 16 | 17 | if __name__ == "__main__": 18 | str1 = "버피는 천사다." 19 | print(str1) 20 | print(reverse_string_with_stack(str1)) 21 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/14_balance_parenthesis_str_stack.py: -------------------------------------------------------------------------------- 1 | from stack import Stack 2 | 3 | 4 | def balance_par_str_with_stack(str1): 5 | s = Stack() 6 | balanced = True 7 | index = 0 8 | 9 | while index < len(str1) and balanced: 10 | symbol = str1[index] 11 | 12 | if symbol == "(": 13 | s.push(symbol) 14 | else: 15 | if s.isEmpty(): 16 | balanced = False 17 | else: 18 | s.pop() 19 | 20 | index = index + 1 21 | 22 | if balanced and s.isEmpty(): 23 | return True 24 | else: 25 | return False 26 | 27 | 28 | if __name__ == "__main__": 29 | print(balance_par_str_with_stack('((()))')) 30 | print(balance_par_str_with_stack('(()')) 31 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/15_dec2bin_with_stack.py: -------------------------------------------------------------------------------- 1 | from stack import Stack 2 | 3 | 4 | def dec2bin_with_stack(decnum): 5 | s = Stack() 6 | str_aux = "" 7 | 8 | while decnum > 0: 9 | dig = decnum % 2 10 | decnum = decnum // 2 11 | s.push(dig) 12 | 13 | while not s.isEmpty(): 14 | str_aux += str(s.pop()) 15 | 16 | return str_aux 17 | 18 | 19 | if __name__ == "__main__": 20 | decnum = 9 21 | print(dec2bin_with_stack(decnum)) 22 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/17_set_of_stacks.py: -------------------------------------------------------------------------------- 1 | from stack import Stack 2 | 3 | 4 | class SetOfStacks(Stack): 5 | def __init__(self, capacity=4): 6 | self.setofstacks = [] 7 | self.items = [] 8 | self.capacity = capacity 9 | 10 | def push(self, value): 11 | if self.size() >= self.capacity: 12 | self.setofstacks.append(self.items) 13 | self.items = [] 14 | self.items.append(value) 15 | 16 | def pop(self): 17 | value = self.items.pop() 18 | if self.isEmpty() and self.setofstacks: 19 | self.items = self.setofstacks.pop() 20 | return value 21 | 22 | def sizeStack(self): 23 | return len(self.setofstacks) * self.capacity + self.size() 24 | 25 | def __repr__(self): 26 | aux = [] 27 | for s in self.setofstacks: 28 | aux.extend(s) 29 | aux.extend(self.items) 30 | return repr(aux) 31 | 32 | 33 | if __name__ == "__main__": 34 | capacity = 5 35 | stack = SetOfStacks(capacity) 36 | print("스택이 비었나요? {0}".format(stack.isEmpty())) 37 | print("스택에 숫자 0~9를 추가합니다.") 38 | for i in range(10): 39 | stack.push(i) 40 | print(stack) 41 | print("스택 크기: {0}".format(stack.sizeStack())) 42 | print("peek: {0}".format(stack.peek())) 43 | print("pop: {0}".format(stack.pop())) 44 | print("peek: {0}".format(stack.peek())) 45 | print("스택이 비었나요? {0}".format(stack.isEmpty())) 46 | print(stack) 47 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/18_palindrome_checker_with_deque.py: -------------------------------------------------------------------------------- 1 | import string 2 | import collections 3 | 4 | from deque import Deque 5 | 6 | 7 | STRIP = string.whitespace + string.punctuation + "\"'" 8 | 9 | 10 | def palindrome_checker_with_deque(str1): 11 | d1 = Deque() 12 | d2 = collections.deque() 13 | 14 | for s in str1.lower(): 15 | if s not in STRIP: 16 | d2.append(s) 17 | d1.enqueue(s) 18 | 19 | eq1 = True 20 | while d1.size() > 1 and eq1: 21 | if d1.dequeue_front() != d1.dequeue(): 22 | eq1 = False 23 | 24 | eq2 = True 25 | while len(d2) > 1 and eq2: 26 | if d2.pop() != d2.popleft(): 27 | eq2 = False 28 | 29 | return eq1, eq2 30 | 31 | 32 | if __name__ == "__main__": 33 | str1 = "Madam Im Adam" 34 | str2 = "Buffy is a Slayer" 35 | print(palindrome_checker_with_deque(str1)) 36 | print(palindrome_checker_with_deque(str2)) 37 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/1_stack.py: -------------------------------------------------------------------------------- 1 | class Stack(object): 2 | def __init__(self): 3 | self.items = [] 4 | 5 | def isEmpty(self): 6 | return not bool(self.items) 7 | 8 | def push(self, value): 9 | self.items.append(value) 10 | 11 | def pop(self): 12 | value = self.items.pop() 13 | if value is not None: 14 | return value 15 | else: 16 | print("Stack is empty.") 17 | 18 | def size(self): 19 | return len(self.items) 20 | 21 | def peek(self): 22 | if self.items: 23 | return self.items[-1] 24 | else: 25 | print("Stack is empty.") 26 | 27 | def __repr__(self): 28 | return repr(self.items) 29 | 30 | 31 | if __name__ == "__main__": 32 | stack = Stack() 33 | print("스택이 비었나요? {0}".format(stack.isEmpty())) 34 | print("스택에 숫자 0~9를 추가합니다.") 35 | for i in range(10): 36 | stack.push(i) 37 | print("스택 크기: {0}".format(stack.size())) 38 | print("peek: {0}".format(stack.peek())) 39 | print("pop: {0}".format(stack.pop())) 40 | print("peek: {0}".format(stack.peek())) 41 | print("스택이 비었나요? {0}".format(stack.isEmpty())) 42 | print(stack) 43 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/20_find_N_largest_smallest_items_seq.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | 4 | def find_N_largest_items_seq(seq, N): 5 | return heapq.nlargest(N, seq) 6 | 7 | 8 | def find_N_smallest_items_seq(seq, N): 9 | return heapq.nsmallest(N, seq) 10 | 11 | 12 | def find_smallest_items_seq_heap(seq): 13 | heapq.heapify(seq) 14 | return heapq.heappop(seq) 15 | 16 | 17 | def find_smallest_items_seq(seq): 18 | return min(seq) 19 | 20 | 21 | def find_N_smallest_items_seq_sorted(seq, N): 22 | return sorted(seq)[:N] 23 | 24 | 25 | def find_N_largest_items_seq_sorted(seq, N): 26 | return sorted(seq)[len(seq)-N:] 27 | 28 | 29 | def test_find_N_largest_smallest_items_seq(): 30 | seq = [1, 3, 2, 8, 6, 10, 9] 31 | N = 3 32 | assert(find_N_largest_items_seq(seq, N) == [10, 9, 8]) 33 | assert(find_N_largest_items_seq_sorted(seq, N) == [8, 9, 10]) 34 | assert(find_N_smallest_items_seq(seq, N) == [1, 2, 3]) 35 | assert(find_N_smallest_items_seq_sorted(seq, N) == [1, 2, 3]) 36 | assert(find_smallest_items_seq(seq) == 1) 37 | assert(find_smallest_items_seq_heap(seq) == 1) 38 | 39 | print("테스트 통과!") 40 | 41 | 42 | if __name__ == "__main__": 43 | test_find_N_largest_smallest_items_seq() 44 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/21_merge_sorted_seqs.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | 4 | def merge_sorted_seqs(seq1, seq2): 5 | result = [] 6 | for c in heapq.merge(seq1, seq2): 7 | result.append(c) 8 | return result 9 | 10 | 11 | def test_merge_sorted_seqs(): 12 | seq1 = [1, 2, 3, 8, 9, 10] 13 | seq2 = [2, 3, 4, 5, 6, 7, 9] 14 | seq3 = seq1 + seq2 15 | assert(merge_sorted_seqs(seq1, seq2) == sorted(seq3)) 16 | 17 | print("테스트 통과!") 18 | 19 | 20 | if __name__ == "__main__": 21 | test_merge_sorted_seqs() 22 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/22_find_kth_from_the_end.py: -------------------------------------------------------------------------------- 1 | from linkedListFIFO import LinkedListFIFO 2 | from node import Node 3 | 4 | 5 | class KthFromLast(LinkedListFIFO): 6 | def find_kth_to_last(self, k): 7 | p1, p2 = self.head, self.head 8 | i = 0 9 | while p1: 10 | if i > k-1: 11 | try: 12 | p2 = p2.pointer 13 | except AttributeError: 14 | break 15 | p1 = p1.pointer 16 | i += 1 17 | return p2.value 18 | 19 | 20 | if __name__ == "__main__": 21 | ll = KthFromLast() 22 | for i in range(1, 11): 23 | ll.addNode(i) 24 | print("연결 리스트: ", end="") 25 | ll._printList() 26 | k = 3 27 | k_from_last = ll.find_kth_to_last(k) 28 | print("연결 리스트의 끝에서 {0}번째 항목은 {1}입니다.".format(k, k_from_last)) 29 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/23_part_linked_list.py: -------------------------------------------------------------------------------- 1 | from linkedListFIFO import LinkedListFIFO 2 | from node import Node 3 | 4 | 5 | def partList(ll, n): 6 | more = LinkedListFIFO() 7 | less = LinkedListFIFO() 8 | 9 | node = ll.head 10 | 11 | while node: 12 | item = node.value 13 | 14 | if item < n: 15 | less.addNode(item) 16 | 17 | elif item > n: 18 | more.addNode(item) 19 | 20 | node = node.pointer 21 | 22 | less.addNode(n) 23 | nodemore = more.head 24 | 25 | while nodemore: 26 | less.addNode(nodemore.value) 27 | nodemore = nodemore.pointer 28 | 29 | return less 30 | 31 | 32 | if __name__ == "__main__": 33 | ll = LinkedListFIFO() 34 | l = [6, 7, 3, 4, 9, 5, 1, 2, 8] 35 | for i in l: 36 | ll.addNode(i) 37 | 38 | print("분할 전:") 39 | ll._printList() 40 | 41 | print("분할 후:") 42 | newll = partList(ll, 6) 43 | newll._printList() 44 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/25_check_pal.py: -------------------------------------------------------------------------------- 1 | from linkedListFIFO import LinkedListFIFO 2 | from node import Node 3 | 4 | 5 | def isPal(l1): 6 | if len(l1) < 2: 7 | return True 8 | if l1[0] != l1[-1]: 9 | return False 10 | return isPal(l1[1:-1]) 11 | 12 | 13 | def checkllPal(ll): 14 | node = ll.head 15 | l = [] 16 | 17 | while node is not None: 18 | l.append(node.value) 19 | node = node.pointer 20 | 21 | return isPal(l) 22 | 23 | 24 | def test_checkllPal(): 25 | ll = LinkedListFIFO() 26 | l1 = [1, 2, 3, 2, 1] 27 | for i in l1: 28 | ll.addNode(i) 29 | assert(checkllPal(ll) is True) 30 | 31 | ll.addNode(2) 32 | ll.addNode(3) 33 | assert(checkllPal(ll) is False) 34 | 35 | print("테스트 통과!") 36 | 37 | 38 | if __name__ == "__main__": 39 | test_checkllPal() 40 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/27_circular_linked_list.py: -------------------------------------------------------------------------------- 1 | from linkedListFIFO import LinkedListFIFO 2 | from node import Node 3 | 4 | 5 | class CicularLinkedListFIFO(LinkedListFIFO): 6 | def _add(self, value): 7 | self.length += 1 8 | node = Node(value, self.head) 9 | if self.tail: 10 | self.tail.pointer = node 11 | self.tail = node 12 | 13 | 14 | def isCircularll(ll): 15 | p1 = ll.head 16 | p2 = ll.head 17 | 18 | while p2: 19 | try: 20 | p1 = p1.pointer 21 | p2 = p2.pointer.pointer 22 | except: 23 | break 24 | 25 | if p1 == p2: 26 | return True 27 | return False 28 | 29 | 30 | def test_isCircularll(): 31 | ll = LinkedListFIFO() 32 | for i in range(10): 33 | ll.addNode(i) 34 | assert(isCircularll(ll) is False) 35 | 36 | lcirc = CicularLinkedListFIFO() 37 | for i in range(10): 38 | lcirc.addNode(i) 39 | assert(isCircularll(lcirc) is True) 40 | 41 | print("테스트 통과!") 42 | 43 | 44 | if __name__ == "__main__": 45 | test_isCircularll() 46 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/3_queue.py: -------------------------------------------------------------------------------- 1 | class Queue(object): 2 | def __init__(self): 3 | self.items = [] 4 | 5 | def isEmpty(self): 6 | return not bool(self.items) 7 | 8 | def enqueue(self, item): 9 | self.items.insert(0, item) 10 | 11 | def dequeue(self): 12 | value = self.items.pop() 13 | if value is not None: 14 | return value 15 | else: 16 | print("Queue is empty.") 17 | 18 | def size(self): 19 | return len(self.items) 20 | 21 | def peek(self): 22 | if self.items: 23 | return self.items[-1] 24 | else: 25 | print("Queue is empty.") 26 | 27 | def __repr__(self): 28 | return repr(self.items) 29 | 30 | 31 | if __name__ == "__main__": 32 | queue = Queue() 33 | print("큐가 비었나요? {0}".format(queue.isEmpty())) 34 | print("큐에 숫자 0~9를 추가합니다.") 35 | for i in range(10): 36 | queue.enqueue(i) 37 | print("큐 크기: {0}".format(queue.size())) 38 | print("peek: {0}".format(queue.peek())) 39 | print("dequeue: {0}".format(queue.dequeue())) 40 | print("peek: {0}".format(queue.peek())) 41 | print("큐가 비었나요? {0}".format(queue.isEmpty())) 42 | print(queue) 43 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/6_deque.py: -------------------------------------------------------------------------------- 1 | from queue import Queue 2 | 3 | 4 | class Deque(Queue): 5 | def enqueue_back(self, item): 6 | self.items.append(item) 7 | 8 | def dequeue_front(self): 9 | value = self.items.pop(0) 10 | if value is not None: 11 | return value 12 | else: 13 | print("Deque is empty.") 14 | 15 | 16 | if __name__ == "__main__": 17 | deque = Deque() 18 | print("데크(Deque)가 비었나요? {0}".format(deque.isEmpty())) 19 | print("데크에 숫자 0~9를 추가합니다.") 20 | for i in range(10): 21 | deque.enqueue(i) 22 | print("데크 크기: {0}".format(deque.size())) 23 | print("peek: {0}".format(deque.peek())) 24 | print("dequeue: {0}".format(deque.dequeue())) 25 | print("peek: {0}".format(deque.peek())) 26 | print("데크가 비었나요? {0}".format(deque.isEmpty())) 27 | print() 28 | print("데크: {0}".format(deque)) 29 | print("dequeue: {0}".format(deque.dequeue_front())) 30 | print("peek: {0}".format(deque.peek())) 31 | print("데크: {0}".format(deque)) 32 | print("enqueue_back(50)을 수행합니다.") 33 | deque.enqueue_back(50) 34 | print("peek: {0}".format(deque.peek())) 35 | print("데크: {0}".format(deque)) 36 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/8_priority_queue.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | 4 | class PriorityQueue(object): 5 | def __init__(self): 6 | self._queue = [] 7 | self._index = 0 8 | 9 | def push(self, item, priority): 10 | heapq.heappush(self._queue, (-priority, self._index, item)) 11 | self._index += 1 12 | 13 | def pop(self): 14 | return heapq.heappop(self._queue)[-1] 15 | 16 | 17 | class Item(object): 18 | def __init__(self, name): 19 | self.name = name 20 | 21 | def __repr__(self): 22 | return "Item({0!r})".format(self.name) 23 | 24 | 25 | def test_priority_queue(): 26 | """ push와 pop은 모두 O(logn)이다. """ 27 | q = PriorityQueue() 28 | q.push(Item('test1'), 1) 29 | q.push(Item('test2'), 4) 30 | q.push(Item('test3'), 3) 31 | assert(str(q.pop()) == "Item('test2')") 32 | print("테스트 통과!") 33 | 34 | 35 | if __name__ == "__main__": 36 | test_priority_queue() 37 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/9_node.py: -------------------------------------------------------------------------------- 1 | class Node(object): 2 | def __init__(self, value=None, pointer=None): 3 | self.value = value 4 | self.pointer = pointer 5 | 6 | def getData(self): 7 | return self.value 8 | 9 | def getNext(self): 10 | return self.pointer 11 | 12 | def setData(self, newdata): 13 | self.value = newdata 14 | 15 | def setNext(self, newpointer): 16 | self.pointer = newpointer 17 | 18 | 19 | if __name__ == "__main__": 20 | L = Node("a", Node("b", Node("c", Node("d")))) 21 | assert(L.pointer.pointer.value == "c") 22 | 23 | print(L.getData()) 24 | print(L.getNext().getData()) 25 | L.setData("aa") 26 | L.setNext(Node("e")) 27 | print(L.getData()) 28 | print(L.getNext().getData()) 29 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/deque.py: -------------------------------------------------------------------------------- 1 | from queue import Queue 2 | 3 | 4 | class Deque(Queue): 5 | def enqueue_back(self, item): 6 | self.items.append(item) 7 | 8 | def dequeue_front(self): 9 | return self.items.pop(0) 10 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/node.py: -------------------------------------------------------------------------------- 1 | class Node(object): 2 | def __init__(self, value=None, pointer=None): 3 | self.value = value 4 | self.pointer = pointer 5 | 6 | def getData(self): 7 | return self.value 8 | 9 | def getNext(self): 10 | return self.pointer 11 | 12 | def setData(self, newdata): 13 | self.value = newdata 14 | 15 | def setNext(self, newpointer): 16 | self.pointer = newpointer 17 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/queue.py: -------------------------------------------------------------------------------- 1 | class Queue(object): 2 | def __init__(self): 3 | self.items = [] 4 | 5 | def isEmpty(self): 6 | return not bool(self.items) 7 | 8 | def enqueue(self, item): 9 | self.items.insert(0, item) 10 | 11 | def dequeue(self): 12 | return self.items.pop() 13 | 14 | def size(self): 15 | return len(self.items) 16 | 17 | def peek(self): 18 | return self.items[-1] 19 | 20 | def __repr__(self): 21 | return repr(self.items) 22 | -------------------------------------------------------------------------------- /7장_추상_데이터_타입/stack.py: -------------------------------------------------------------------------------- 1 | class Stack(object): 2 | def __init__(self): 3 | self.items = [] 4 | 5 | def isEmpty(self): 6 | return not bool(self.items) 7 | 8 | def push(self, value): 9 | self.items.append(value) 10 | 11 | def pop(self): 12 | value = self.items.pop() 13 | if value is not None: 14 | return value 15 | else: 16 | print("Stack is empty.") 17 | 18 | def size(self): 19 | return len(self.items) 20 | 21 | def peek(self): 22 | if self.items: 23 | return self.items[-1] 24 | else: 25 | print("Stack is empty.") 26 | 27 | def __repr__(self): 28 | return repr(self.items) 29 | -------------------------------------------------------------------------------- /8장_점근적_분석/find_fibonacci_seq.py: -------------------------------------------------------------------------------- 1 | def find_fibonacci_seq_rec(n): 2 | if n < 2: 3 | return n 4 | return find_fibonacci_seq_rec(n - 1) + find_fibonacci_seq_rec(n - 2) 5 | 6 | 7 | if __name__ == "__main__": 8 | print(find_fibonacci_seq_rec(5)) 9 | -------------------------------------------------------------------------------- /9장_정렬/10_heap_sort_2.py: -------------------------------------------------------------------------------- 1 | from heap import Heap 2 | 3 | 4 | def heap_sort2(seq): 5 | s = list(seq) 6 | heap = Heap(s) 7 | res = [] 8 | for _ in range(len(s)): 9 | res.insert(0, heap.extract_max()) 10 | return res 11 | 12 | 13 | def test_heap_sort2(): 14 | seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2] 15 | assert(heap_sort2(seq) == sorted(seq)) 16 | print("테스트 통과!") 17 | 18 | 19 | if __name__ == "__main__": 20 | test_heap_sort2() 21 | -------------------------------------------------------------------------------- /9장_정렬/11_heap_sort_3.py: -------------------------------------------------------------------------------- 1 | def heap_sort3(seq): 2 | for start in range((len(seq)-2)//2, -1, -1): 3 | siftdown(seq, start, len(seq)-1) 4 | for end in range(len(seq)-1, 0, -1): 5 | seq[end], seq[0] = seq[0], seq[end] 6 | siftdown(seq, 0, end - 1) 7 | return seq 8 | 9 | 10 | def siftdown(seq, start, end): 11 | root = start 12 | while True: 13 | child = root * 2 + 1 14 | if child > end: 15 | break 16 | if child + 1 <= end and seq[child] < seq[child + 1]: 17 | child += 1 18 | if seq[root] < seq[child]: 19 | seq[root], seq[child] = seq[child], seq[root] 20 | root = child 21 | else: 22 | break 23 | 24 | 25 | def test_heap_sort(): 26 | seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2] 27 | assert(heap_sort3(seq) == sorted(seq)) 28 | print("테스트 통과!") 29 | 30 | 31 | if __name__ == "__main__": 32 | test_heap_sort() 33 | -------------------------------------------------------------------------------- /9장_정렬/1_bubble_sort.py: -------------------------------------------------------------------------------- 1 | def bubble_sort(seq): 2 | length = len(seq) - 1 3 | for num in range(length, 0, -1): 4 | for i in range(num): 5 | if seq[i] > seq[i+1]: 6 | seq[i], seq[i+1] = seq[i+1], seq[i] 7 | print(seq) 8 | return seq 9 | 10 | 11 | def test_bubble_sort(): 12 | seq = [11, 3, 28, 43, 9, 4] 13 | assert(bubble_sort(seq) == sorted(seq)) 14 | print("테스트 통과!") 15 | 16 | 17 | if __name__ == "__main__": 18 | test_bubble_sort() 19 | -------------------------------------------------------------------------------- /9장_정렬/2_selection_sort.py: -------------------------------------------------------------------------------- 1 | # def selection_sort(seq): 2 | # for i in range(len(seq) - 1, 0, -1): 3 | # max_j = i 4 | # for j in range(max_j): 5 | # if seq[j] > seq[max_j]: 6 | # max_j = j 7 | # seq[i], seq[max_j] = seq[max_j], seq[i] 8 | # return seq 9 | 10 | 11 | def selection_sort(seq): 12 | length = len(seq) 13 | for i in range(length-1): 14 | min_j = i 15 | for j in range(i+1, length): 16 | if seq[min_j] > seq[j]: 17 | min_j = j 18 | seq[i], seq[min_j] = seq[min_j], seq[i] 19 | print(seq) 20 | return seq 21 | 22 | 23 | def test_selection_sort(): 24 | seq = [11, 3, 28, 43, 9, 4] 25 | assert(selection_sort(seq) == sorted(seq)) 26 | print("테스트 통과!") 27 | 28 | 29 | if __name__ == "__main__": 30 | test_selection_sort() 31 | -------------------------------------------------------------------------------- /9장_정렬/3_insertion_sort.py: -------------------------------------------------------------------------------- 1 | def insertion_sort(seq): 2 | for i in range(1, len(seq)): 3 | j = i 4 | while j > 0 and seq[j-1] > seq[j]: 5 | seq[j-1], seq[j] = seq[j], seq[j-1] 6 | j -= 1 7 | # print(seq) 8 | return seq 9 | 10 | 11 | def insertion_sort_rec(seq, i=None): 12 | if i is None: 13 | i = len(seq) - 1 14 | if i == 0: 15 | return i 16 | insertion_sort_rec(seq, i-1) 17 | j = i 18 | while j > 0 and seq[j-i] > seq[j]: 19 | seq[j-1], seq[j] = seq[j], seq[j-1] 20 | j -= 1 21 | return seq 22 | 23 | 24 | def test_insertion_sort(): 25 | seq = [11, 3, 28, 43, 9, 4] 26 | assert(insertion_sort(seq) == sorted(seq)) 27 | assert(insertion_sort_rec(seq) == sorted(seq)) 28 | print("테스트 통과!") 29 | 30 | 31 | if __name__ == "__main__": 32 | test_insertion_sort() 33 | -------------------------------------------------------------------------------- /9장_정렬/4_gnome_sort.py: -------------------------------------------------------------------------------- 1 | def gnome_sort(seq): 2 | i = 0 3 | while i < len(seq): 4 | if i == 0 or seq[i-1] <= seq[i]: 5 | i += 1 6 | else: 7 | seq[i], seq[i-1] = seq[i-1], seq[i] 8 | i -= 1 9 | print(seq) 10 | return seq 11 | 12 | 13 | def test_gnome_sort(): 14 | seq = [11, 3, 28, 43, 9, 4] 15 | assert(gnome_sort(seq) == sorted(seq)) 16 | print("테스트 통과!") 17 | 18 | 19 | if __name__ == "__main__": 20 | test_gnome_sort() 21 | -------------------------------------------------------------------------------- /9장_정렬/5_count_sort.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | 4 | def count_sort_dict(a): 5 | b, c = [], defaultdict(list) 6 | for x in a: 7 | c[x].append(x) 8 | for k in range(min(c), max(c) + 1): 9 | b.extend(c[k]) 10 | return b 11 | 12 | 13 | def test_count_sort(): 14 | seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2, 5, 4, 1, 5, 3] 15 | assert(count_sort_dict(seq) == sorted(seq)) 16 | print("테스트 통과!") 17 | 18 | 19 | if __name__ == "__main__": 20 | test_count_sort() 21 | -------------------------------------------------------------------------------- /9장_정렬/8_find_k_largest_seq_quicksort.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | 4 | def swap(seq, x, y): 5 | seq[x], seq[y] = seq[y], seq[x] 6 | 7 | 8 | def quick_select(seq, k, left=None, right=None): 9 | left = left or 0 10 | right = right or len(seq) - 1 11 | ipivot = random.randint(left, right) 12 | pivot = seq[ipivot] 13 | 14 | # 피벗을 정렬 범위 밖으로 이동한다. 15 | swap(seq, ipivot, right) 16 | swapIndex, i = left, left 17 | while i < right: 18 | if seq[i] < pivot: 19 | swap(seq, i, swapIndex) 20 | swapIndex += 1 21 | i += 1 22 | 23 | # 피벗 위치를 확정한다. 24 | swap(seq, right, swapIndex) 25 | # 피벗 위치를 확인한다. 26 | rank = len(seq) - swapIndex 27 | if k == rank: 28 | return seq[swapIndex] 29 | elif k < rank: 30 | return quick_select(seq, k, left=swapIndex+1, right=right) 31 | else: 32 | return quick_select(seq, k, left=left, right=swapIndex-1) 33 | 34 | 35 | def find_k_largest_seq_quickselect(seq, k): 36 | # k번째로 큰 값을 찾는다. 37 | kth_largest = quick_select(seq, k) 38 | 39 | # k번째보다 큰 값을 저장한다. 40 | result = [] 41 | for item in seq: 42 | if item >= kth_largest: 43 | result.append(item) 44 | return result 45 | 46 | 47 | if __name__ == "__main__": 48 | seq = [3, 10, 4, 5, 1, 8, 9, 11, 5] 49 | k = 3 50 | print(find_k_largest_seq_quickselect(seq, k)) 51 | -------------------------------------------------------------------------------- /9장_정렬/9_heap_sort_1.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | 4 | def heap_sort1(seq): 5 | h = [] 6 | for value in seq: 7 | heapq.heappush(h, value) 8 | return [heapq.heappop(h) for i in range(len(h))] 9 | 10 | 11 | def test_heap_sort1(): 12 | seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2] 13 | assert(heap_sort1(seq) == sorted(seq)) 14 | print("테스트 통과!") 15 | 16 | 17 | if __name__ == "__main__": 18 | test_heap_sort1() 19 | -------------------------------------------------------------------------------- /9장_정렬/a.dat: -------------------------------------------------------------------------------- 1 | 1 2 | 3 3 | 5 4 | 6 5 | 8 6 | -------------------------------------------------------------------------------- /9장_정렬/b.dat: -------------------------------------------------------------------------------- 1 | 1 2 | 3 3 | 5 4 | 7 5 | -------------------------------------------------------------------------------- /9장_정렬/c.dat: -------------------------------------------------------------------------------- 1 | 2 2 | 3 3 | 4 4 | 5 -------------------------------------------------------------------------------- /9장_정렬/heap.py: -------------------------------------------------------------------------------- 1 | class Heap(object): 2 | def __init__(self, data=None): 3 | self.data = data or [] 4 | for i in range(len(data)//2, -1, -1): 5 | self.__max_heapify__(i) 6 | 7 | def __repr__(self): 8 | return (f'{self.data}') 9 | 10 | def parent(self, i): 11 | return i >> 1 12 | 13 | def left_child(self, i): 14 | return (i << 1) + 1 15 | 16 | def right_child(self, i): 17 | return (i << 1) + 2 18 | 19 | def __max_heapify__(self, i): 20 | largest = i 21 | left = self.left_child(i) 22 | right = self.right_child(i) 23 | n = len(self.data) 24 | largest = (left < n and self.data[left] > self.data[i]) and left or i 25 | largest = (right < n and self.data[right] 26 | > self.data[largest]) and right or largest 27 | if i is not largest: 28 | self.data[i], self.data[largest] = self.data[largest], self.data[i] 29 | self.__max_heapify__(largest) 30 | 31 | def extract_max(self): 32 | n = len(self.data) 33 | max_element = self.data[0] 34 | self.data[0] = self.data[n - 1] 35 | self.data = self.data[:n - 1] 36 | self.__max_heapify__(0) 37 | return max_element 38 | -------------------------------------------------------------------------------- /HALEIWA.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/c143f4248734b86f0b1783b6759ba8b9dbebf685/HALEIWA.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## ✨ 파이썬 자료구조와 알고리즘 ✨ 2 | 3 |

4 | 5 |

6 | 7 | * 🛒 [예스24](http://www.yes24.com/Product/Goods/74971408) 8 | 9 | * 📚 [원서 다운로드](https://github.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/blob/master/ebook/book_second_edition.pdf) 10 | 11 | * 폴더 이름 1장_xxx ~ 14장_xxx 부분이 책 내용입니다. 그 외 나머지 폴더 및 파일은 원서 저장소를 포크한 부분입니다. 12 | 13 | ## License 14 | Creative Commons License
15 | 16 | This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/). 17 | -------------------------------------------------------------------------------- /README_old.md: -------------------------------------------------------------------------------- 1 | ## ✨ Algorithms & Data Structures in Python (Book, Hanbit Media, Inc.) ✨ 2 | 3 | * Including Python solutions for every exercises from "Cracking the Code Interview". 4 | * #### 📚[Download the digital book here.](https://github.com/bt3gl/Python-and-Algorithms-and-Data-Structures/blob/master/ebook/book_second_edition.pdf) 5 | 6 | ![](HALEIWA.jpg) 7 | 8 | 9 | ## ✨ Installation: 10 | 11 | The snippets are designed to be used individually. However, If you want to install all fo the libraries in your [virtualenv](https://coderwall.com/p/8-aeka), do this: 12 | 13 | ``` 14 | $ pip install -r requirements.txt 15 | ``` 16 | 17 | 18 | 19 | ---- 20 | 21 | 22 | ## License 23 | 24 | When making a reference to my work, please use my [website](http://bt3gl.github.io/index.html). 25 | 26 | Creative Commons License
27 | 28 | This work is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](http://creativecommons.org/licenses/by-sa/4.0/). 29 | -------------------------------------------------------------------------------- /ebook/book_second_edition.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/c143f4248734b86f0b1783b6759ba8b9dbebf685/ebook/book_second_edition.pdf -------------------------------------------------------------------------------- /interview_problems/balanced.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def balance_par_str_with_stack(str1): 7 | i, stack = 0, [] 8 | 9 | while i < len(str1): 10 | symbol = str1[i] 11 | if symbol == "(": 12 | stack.append(symbol) 13 | elif symbol == ")": 14 | stack.pop() 15 | i += 1 16 | return not stack 17 | 18 | 19 | 20 | if __name__ == "__main__": 21 | print(balance_par_str_with_stack('((()))')) 22 | print(balance_par_str_with_stack('(()')) -------------------------------------------------------------------------------- /interview_problems/check_anagram.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | from collections import Counter 6 | 7 | def check_if_anagram(word1, word2): 8 | counter = Counter() 9 | 10 | for c in word1: 11 | counter[c] += 1 12 | 13 | for c in word2: 14 | counter[c] -= 1 15 | 16 | for values in counter.values(): 17 | if values != 0: 18 | return False 19 | 20 | return True 21 | 22 | 23 | 24 | if __name__ == "__main__": 25 | word1 = 'abc' 26 | word2 = 'bca' 27 | assert(check_if_anagram(word1, word2) == True) 28 | 29 | word2 = 'bcd' 30 | assert(check_if_anagram(word1, word2) == False) 31 | 32 | word1 = '' 33 | word2 = '' 34 | assert(check_if_anagram(word1, word2) == True) 35 | 36 | word1 = 'a' 37 | word2 = 'a' 38 | assert(check_if_anagram(word1, word2) == True) -------------------------------------------------------------------------------- /interview_problems/combination.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | def combination(array): 6 | if len(array) < 2: 7 | return set(array) 8 | 9 | result = set() 10 | for index, item in enumerate(array): 11 | new_array = array[:index] + array[index+1:] 12 | result.add(item) 13 | for perm in combination(new_array): 14 | new_item = ''.join(sorted(item + perm)) 15 | result.add(new_item) 16 | 17 | return result 18 | 19 | 20 | 21 | if __name__ == "__main__": 22 | array = ['a', 'b', 'c'] 23 | result = set(['a', 'ac', 'ab', 'abc', 'bc', 'c', 'b']) 24 | assert(combination(array) == result) 25 | 26 | array = [''] 27 | result = set(['']) 28 | assert(combination(array) == result) 29 | 30 | array = ['a'] 31 | result = set(['a']) 32 | assert(combination(array) == result) -------------------------------------------------------------------------------- /interview_problems/hash_table.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | class HashTable(object): 7 | def __init__(self, slots=10): 8 | self.slots = slots 9 | self.table = [] 10 | self.create_table() 11 | 12 | # Get the slot 13 | def hash_key(self, value): 14 | return hash(value)%self.slots 15 | 16 | # When creating the table, add list struct 17 | # to each slot 18 | def create_table(self): 19 | for i in range(self.slots): 20 | self.table.append([]) 21 | 22 | # Method to add a item in the right slot 23 | def add_item(self, value): 24 | key = self.hash_key(value) 25 | self.table[key].append(value) 26 | 27 | # Aux: print table 28 | def print_table(self): 29 | for key in range(self.slots): 30 | print "Key is {0}, value is {1}.".format(key, self.table[key]) 31 | 32 | # Aux: find item 33 | def find_item(self, item): 34 | item_hash = self.hash_key(item) 35 | return item in self.table[item_hash] 36 | 37 | 38 | if __name__ == "__main__": 39 | dic = HashTable(5) 40 | for i in range(1, 40, 2): 41 | dic.add_item(i) 42 | 43 | dic.print_table() 44 | assert(dic.find_item(20) == False) 45 | assert(dic.find_item(21) == True) -------------------------------------------------------------------------------- /interview_problems/longest_common_prefix.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def longest_common_substring(s1, s2): 7 | p1 = 0 8 | aux, lcp = '', '' 9 | string1 = max(s1, s2) 10 | string2 = min(s1, s2) 11 | 12 | while p1 < len(string1): 13 | p2 = 0 14 | while p2 < len(string2) and p1+p2 < len(string1): 15 | if string1[p1+p2] == string2[p2]: 16 | aux += string1[p1+p2] 17 | else: 18 | if len(lcp) < len(aux): 19 | lcp = aux 20 | aux = '' 21 | p2 += 1 22 | p1 += 1 23 | 24 | return lcp 25 | 26 | 27 | 28 | if __name__ == "__main__": 29 | str1 = 'hasfgeaae' 30 | str2 = 'bafgekk' 31 | result = 'fge' 32 | assert(longest_common_substring(str1, str2) == result) -------------------------------------------------------------------------------- /interview_problems/longest_increasing_subsequence.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def longest_increasing_subsequence(seq): 7 | result, aux = [], [] 8 | seq.append(-float('infinity')) 9 | 10 | for i, value in enumerate(seq[:-1]): 11 | aux.append(value) 12 | if value > seq[i+1]: 13 | if len(result) < len(aux): 14 | result = aux[:] 15 | aux = [] 16 | return result 17 | 18 | 19 | 20 | if __name__ == "__main__": 21 | seq = [10, -12, 2, 3, -3, 5, -1, 2, -10] 22 | result = [-12, 2, 3] 23 | assert(longest_increasing_subsequence(seq) == result) 24 | 25 | seq = [2] 26 | result = [2] 27 | assert(longest_increasing_subsequence(seq) == result) 28 | 29 | seq = [] 30 | result = [] 31 | assert(longest_increasing_subsequence(seq) == result) -------------------------------------------------------------------------------- /interview_problems/merge_sort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # AKA: do you believe in magic? 3 | 4 | __author__ = "bt3" 5 | 6 | def merge_sort(array): 7 | if len(array) < 2: 8 | return array 9 | 10 | # divide 11 | mid = len(array)//2 12 | left = merge_sort(array[:mid]) 13 | right = merge_sort(array[mid:]) 14 | 15 | # merge 16 | result = [] 17 | i, j = 0, 0 18 | 19 | while i < len(left) and j < len(right): 20 | if left[i] < right[j]: 21 | result.append(left[i]) 22 | i += 1 23 | else: 24 | result.append(right[j]) 25 | j+= 1 26 | 27 | # make sure nothing is left behind 28 | if left[i:]: 29 | result.extend(left[i:]) 30 | if right[j:]: 31 | result.extend(right[j:]) 32 | 33 | return result 34 | 35 | 36 | 37 | 38 | if __name__ == "__main__": 39 | array = [3, 1, 6, 0, 7, 19, 7, 2, 22] 40 | sorted = [0, 1, 2, 3, 6, 7, 7, 19, 22] 41 | assert(merge_sort(array) == sorted) 42 | 43 | array = [] 44 | assert(merge_sort(array) == array) 45 | 46 | array = [1] 47 | assert(merge_sort(array) == array) -------------------------------------------------------------------------------- /interview_problems/permutation.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def permutation(array): 7 | if len(array) < 2: 8 | return [array] 9 | 10 | result = [] 11 | for index, letter in enumerate(array): 12 | new_array = array[:index] + array[index+1:] 13 | for perm in permutation(new_array): 14 | result.append(letter + perm) 15 | 16 | return result 17 | 18 | 19 | 20 | if __name__ == "__main__": 21 | word = 'abc' 22 | result = ['abc', 'acb', 'bac', 'bca', 'cab', 'cba'] 23 | assert(permutation(word) == result) 24 | 25 | word = '' 26 | result = [''] 27 | assert(permutation(word) == result) 28 | 29 | word = 'a' 30 | result = ['a'] 31 | assert(permutation(word) == result) -------------------------------------------------------------------------------- /interview_problems/queue.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | class Queue(object): 7 | def __init__(self): 8 | self.enq = [] 9 | self.deq = [] 10 | 11 | def enqueue(self, item): 12 | return self.enq.append(item) 13 | 14 | def deque(self): 15 | if not self.deq: 16 | while self.enq: 17 | self.deq.append(self.enq.pop()) 18 | return self.deq.pop() 19 | 20 | def peak(self): 21 | if not self.deq: 22 | while self.enq: 23 | self.deq.append(self.enq.pop()) 24 | if self.deq: 25 | return self.deq[-1] 26 | 27 | def size(self): 28 | return len(self.enq) + len(self.deq) 29 | 30 | def isempty(self): 31 | return not (self.enq + self.deq) 32 | 33 | 34 | if __name__ == "__main__": 35 | q = Queue() 36 | for i in range(1,11): 37 | q.enqueue(i) 38 | print 'Size:', q.size() 39 | print 'Is empty?', q.isempty() 40 | print 'Peak: ', q.peak() 41 | print 42 | print 'Dequeuing...' 43 | for i in range(10): 44 | print q.deque() 45 | print 'Size:', q.size() 46 | print 'Is empty?', q.isempty() 47 | print 'Peak: ', q.peak() -------------------------------------------------------------------------------- /interview_problems/quick_sort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | def quick_sort(array): 6 | if len(array) < 2: 7 | return array 8 | 9 | # partition 10 | ipivot = len(array)//2 11 | pivot = array[ipivot] 12 | new_array = array[:ipivot] + array[ipivot+1:] 13 | 14 | left = [x for x in new_array if x <= pivot] 15 | right = [x for x in new_array if x > pivot] 16 | 17 | return quick_sort(left) + [pivot] + quick_sort(right) 18 | 19 | 20 | 21 | 22 | if __name__ == "__main__": 23 | array = [3, 1, 6, 0, 7, 19, 7, 2, 22] 24 | sorted = [0, 1, 2, 3, 6, 7, 7, 19, 22] 25 | assert(quick_sort(array) == sorted) 26 | 27 | array = [] 28 | assert(quick_sort(array) == array) 29 | 30 | array = [1] 31 | assert(quick_sort(array) == array) -------------------------------------------------------------------------------- /interview_problems/reverse_str.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | def reverse_str_inplace(_str): 6 | if len(_str) < 2: 7 | return _str 8 | return _str[-1] + reverse_str(_str[1:-1]) + _str[0] 9 | 10 | 11 | def reverse_str(_str): 12 | result = '' 13 | j = len(_str) - 1 14 | 15 | while j >= 0: 16 | result += _str[j] 17 | 18 | return result 19 | 20 | 21 | if __name__ == "__main__": 22 | _str = '' 23 | result = '' 24 | assert(reverse_str(_str) == result) 25 | assert(reverse_str_inplace(_str) == result) 26 | 27 | _str = 'a' 28 | result = 'a' 29 | assert(reverse_str(_str) == result) 30 | assert(reverse_str_inplace(_str) == result) 31 | 32 | _str = 'abcde' 33 | result = 'edcba' 34 | assert(reverse_str(_str) == result) 35 | assert(reverse_str_inplace(_str) == result) 36 | 37 | _str = 'abcdef' 38 | result = 'fedcba' 39 | assert(reverse_str(_str) == result) 40 | assert(reverse_str_inplace(_str) == result) -------------------------------------------------------------------------------- /interview_problems/stack.py: -------------------------------------------------------------------------------- 1 | 2 | #!/usr/bin/env python 3 | 4 | __author__ = "bt3" 5 | 6 | 7 | class Stack(object): 8 | def __init__(self): 9 | self.content = [] 10 | 11 | def push(self, value): 12 | self.content.append(value) 13 | 14 | def pop(self): 15 | if self.content: 16 | return self.content.pop() 17 | else: 18 | return 'Empty List. ' 19 | 20 | def size(self): 21 | return len(self.content) 22 | 23 | def isEmpty(self): 24 | return not bool(self.content) 25 | 26 | def peek(self): 27 | if self.content: 28 | return self.content[-1] 29 | else: 30 | print("Stack is empty.") 31 | 32 | 33 | if __name__ == "__main__": 34 | q = Stack() 35 | 36 | for i in range(10): 37 | q.push(i) 38 | for i in range(11): 39 | print q.pop() 40 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==0.10.1 2 | SQLAlchemy==0.9.7 3 | bpython==0.13.1 4 | coverage==3.7.1 5 | curtsies==0.0.34 6 | graphviz==0.4.2 7 | ipython==0.13.2 8 | matplotlib==1.3.1 9 | nose==1.3.0 10 | numpy==1.8.2 11 | scapy==2.2.0 12 | scikit-learn==0.14.1 13 | scipy==0.12.1 -------------------------------------------------------------------------------- /source_code/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/c143f4248734b86f0b1783b6759ba8b9dbebf685/source_code/.DS_Store -------------------------------------------------------------------------------- /source_code/USEFUL/advanced/lru_cache.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | from functools import lru_cache 7 | 8 | 9 | @lru_cache(maxsize=20) 10 | def fib(n): 11 | if n < 2: 12 | return n 13 | return fib(n-1) + fib(n-2) 14 | 15 | 16 | if __name__ == "__main__": 17 | print([fib(n) for n in range(10)]) 18 | print(fib.cache_info()) 19 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_OrderedDict.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | from collections import OrderedDict 6 | 7 | def OrderedDict_example(): 8 | """ show some examples for OrderedDict """ 9 | """ keep the order of insertion. 10 | maintains a doubly linked list, so size is more than twice than normal dict""" 11 | 12 | 13 | pairs = [('a', 1), ('b',2), ('c',3)] 14 | 15 | d1 = {} 16 | for key, value in pairs: 17 | if key not in d1: 18 | d1[key] = [] 19 | d1[key].append(value) 20 | for key in d1: 21 | print(key, d1[key]) 22 | 23 | d2 = OrderedDict(pairs) 24 | for key in d2: 25 | print(key, d2[key]) 26 | 27 | 28 | if __name__ == "__main__": 29 | OrderedDict_example() 30 | 31 | 32 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_args.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | def simple2(a, *args): 6 | print args 7 | 8 | def simple(*args): 9 | print args 10 | 11 | def simple3(**kwargs): 12 | print kwargs 13 | 14 | 15 | simple(1, 2, 3) 16 | simple2(1, 2, 3) 17 | simple3(x=1, y=2) 18 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_benchmark_decorator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | import random 7 | 8 | def benchmark(func): 9 | import time 10 | def wrapper(*args, **kwargs): 11 | t = time.clock() 12 | res = func(*args, **kwargs) 13 | print("\t%s" % func.__name__, time.clock()-t) 14 | return res 15 | return wrapper 16 | 17 | 18 | @benchmark 19 | def random_tree(n): 20 | temp = [n for n in range(n)] 21 | for i in range(n+1): 22 | temp[random.choice(temp)] = random.choice(temp) 23 | return temp 24 | 25 | 26 | if __name__ == "__main__": 27 | random_tree(10000) 28 | 29 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_comp_lists.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | a = [3, 4, 5, 6, 7] 6 | 7 | 8 | # Filter elements greater than 4 9 | 10 | # Bad: 11 | 12 | b = [] 13 | for i in a: 14 | if i > 4: 15 | b.append(i) 16 | print b 17 | 18 | # Good: 19 | print [i for i in a if i > 4] 20 | 21 | # Or: 22 | print filter(lambda x: x > 4, a) 23 | 24 | 25 | # Add three to all list members: 26 | 27 | # Bad 28 | b = [] 29 | for i in range(len(a)): 30 | b.append(a[i] + 3) 31 | print b 32 | 33 | # Good: 34 | print [i + 3 for i in a] 35 | 36 | # Or: 37 | print map(lambda i: i + 3, a) -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_counter.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | from collections import Counter 6 | 7 | def Counter_example(): 8 | """ it is a dictionary that maps the items to the number of occurrences """ 9 | seq1 = [1, 2, 3, 5, 1, 2, 5, 5, 2, 5, 1, 4] 10 | seq_counts = Counter(seq1) 11 | print(seq_counts) 12 | 13 | """ we can increment manually or use the update() method """ 14 | seq2 = [1, 2, 3] 15 | seq_counts.update(seq2) 16 | print(seq_counts) 17 | 18 | seq3 = [1, 4, 3] 19 | for key in seq3: 20 | seq_counts[key] += 1 21 | print(seq_counts) 22 | 23 | """ also, we can use set operations such as a-b or a+b """ 24 | seq_counts_2 = Counter(seq3) 25 | print(seq_counts_2) 26 | print(seq_counts + seq_counts_2) 27 | print(seq_counts - seq_counts_2) 28 | 29 | if __name__ == "__main__": 30 | Counter_example() 31 | 32 | 33 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_decorators.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | 7 | def logger(func): 8 | def inner(*args): #1 9 | print "Arguments were: {0}".format(args) 10 | return func(*args) 11 | return inner 12 | 13 | @logger 14 | def foo(x, y): 15 | return x+y 16 | 17 | print foo(1, 2) 18 | 19 | 20 | def sum(func): 21 | s = 0 22 | for i in func(): 23 | s += i 24 | return s 25 | 26 | @sum 27 | def interate(): 28 | a = [] 29 | for i in range(10): 30 | a.append(i) 31 | return a 32 | 33 | print interate 34 | 35 | # which is the same as 36 | def interate(): 37 | a = [] 38 | for i in range(10): 39 | a.append(i) 40 | return a 41 | 42 | print sum(interate) -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_defaultdict.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | from collections import defaultdict 6 | 7 | def defaultdict_example(): 8 | """ show some examples for defaultdicts """ 9 | pairs = {('a', 1), ('b',2), ('c',3)} 10 | 11 | d1 = {} 12 | for key, value in pairs: 13 | if key not in d1: 14 | d1[key] = [] 15 | d1[key].append(value) 16 | print(d1) 17 | 18 | d2 = defaultdict(list) 19 | for key, value in pairs: 20 | d2[key].append(value) 21 | print(d2) 22 | 23 | 24 | if __name__ == "__main__": 25 | defaultdict_example() 26 | 27 | 28 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_doctest.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | __author__ = "bt3" 4 | 5 | """ 6 | The doctest module automatically runs any statement beginning with >>> 7 | and compares the following line with the output from the interpreter. 8 | 9 | >>> 1 == 1 10 | False 11 | """ 12 | 13 | if __name__ == "__main__": 14 | import doctest 15 | doctest.testmod() -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_fractions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | from fractions import Fraction 7 | 8 | def rounding_floats(number1, places): 9 | return round(number1, places) 10 | 11 | 12 | def float_to_fractions(number): 13 | return Fraction(*number.as_integer_ratio()) 14 | 15 | 16 | def get_denominator(number1, number2): 17 | a = Fraction(number1, number2) 18 | return a.denominator 19 | 20 | 21 | def get_numerator(number1, number2): 22 | a = Fraction(number1, number2) 23 | return a.numerator 24 | 25 | 26 | def test_testing_floats(module_name='this module'): 27 | number1 = 1.25 28 | number2 = 1 29 | number3 = -1 30 | number4 = 5/4 31 | number6 = 6 32 | assert(rounding_floats(number1, number2) == 1.2) 33 | assert(rounding_floats(number1*10, number3) == 10) 34 | assert(float_to_fractions(number1) == number4) 35 | assert(get_denominator(number2, number6) == number6) 36 | assert(get_numerator(number2, number6) == number2) 37 | 38 | s = 'Tests in {name} have {con}!' 39 | print(s.format(name=module_name, con='passed')) 40 | 41 | 42 | if __name__ == "__main__": 43 | test_testing_floats() 44 | 45 | 46 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_generator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def interate(x): 7 | for i in range(x): 8 | yield i 9 | 10 | def gen1(): 11 | a = interate(10) 12 | print a.next() 13 | print a.next() 14 | print a.next() 15 | 16 | 17 | def reverse(data): 18 | for i in range(len(data)-1, -1, -1): 19 | yield data[i] 20 | 21 | def gen2(): 22 | for c in reverse('awesome'): 23 | print c 24 | 25 | if __name__ == "__main__": 26 | gen1() 27 | gen2() 28 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_lambda.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | test = lambda x: x**2 7 | print test(3) -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_logging.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | import logging 6 | 7 | LOG_FILENAME = 'logging_example.out' 8 | logging.basicConfig(filename=LOG_FILENAME, 9 | level=logging.DEBUG, 10 | ) 11 | 12 | logging.debug('This message should go to the log file') 13 | 14 | f = open(LOG_FILENAME, 'rt') 15 | try: 16 | body = f.read() 17 | finally: 18 | f.close() 19 | 20 | print 'FILE:' 21 | print body -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_numpy.py: -------------------------------------------------------------------------------- 1 | 2 | #!/usr/bin/env python 3 | 4 | __author__ = "bt3" 5 | 6 | import time 7 | import numpy as np 8 | 9 | def testing_numpy(): 10 | """ tests many features of numpy """ 11 | ax = np.array([1,2,3]) 12 | ay = np.array([3,4,5]) 13 | print(ax) 14 | print(ax*2) 15 | print(ax+10) 16 | print(np.sqrt(ax)) 17 | print(np.cos(ax)) 18 | print(ax-ay) 19 | print(np.where(ax<2, ax, 10)) 20 | 21 | m = np.matrix([ax, ay, ax]) 22 | print(m) 23 | print(m.T) 24 | 25 | grid1 = np.zeros(shape=(10,10), dtype=float) 26 | grid2 = np.ones(shape=(10,10), dtype=float) 27 | print(grid1) 28 | print(grid2) 29 | print(grid1[1]+10) 30 | print(grid2[:,2]*2) 31 | 32 | 33 | def trad_version(): 34 | t1 = time.time() 35 | X = range(10000000) 36 | Y = range(10000000) 37 | Z = [] 38 | for i in range(len(X)): 39 | Z.append(X[i] + Y[i]) 40 | return time.time() - t1 41 | 42 | def numpy_version(): 43 | t1 = time.time() 44 | X = np.arange(10000000) 45 | Y = np.arange(10000000) 46 | Z = X + Y 47 | return time.time() - t1 48 | 49 | 50 | 51 | if __name__ == "__main__": 52 | testing_numpy() 53 | print(trad_version()) 54 | print(numpy_version()) 55 | 56 | 57 | """ 58 | 3.23564291 59 | 0.0714290142059 60 | """ 61 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_open_files.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | filename = raw_input('Enter a file name: ') 6 | try: 7 | f = open(filename, "r") 8 | except: 9 | print 'There is no file named', filename 10 | 11 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_queue.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | import Queue 6 | 7 | q = Queue.Queue() 8 | 9 | for i in range(10): 10 | q.put(i) 11 | 12 | for i in range(10): 13 | print q.get(i) 14 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_random.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | import random 6 | 7 | def testing_random(): 8 | """ testing the module random""" 9 | values = [1, 2, 3, 4] 10 | print(random.choice(values)) 11 | print(random.choice(values)) 12 | print(random.choice(values)) 13 | print(random.sample(values, 2)) 14 | print(random.sample(values, 3)) 15 | 16 | """ shuffle in place """ 17 | random.shuffle(values) 18 | print(values) 19 | 20 | """ create random integers """ 21 | print(random.randint(0,10)) 22 | print(random.randint(0,10)) 23 | 24 | 25 | if __name__ == "__main__": 26 | testing_random() 27 | 28 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_setdefault.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def usual_dict(dict_data): 7 | newdata = {} 8 | for k, v in dict_data: 9 | if k in newdata: 10 | newdata[k].append(v) 11 | else: 12 | newdata[k] = [v] 13 | return newdata 14 | 15 | 16 | def setdefault_dict(dict_data): 17 | newdata = {} 18 | for k, v in dict_data: 19 | newdata.setdefault(k, []).append(v) 20 | return newdata 21 | 22 | 23 | def test_setdef(module_name='this module'): 24 | dict_data = (('key1', 'value1'), 25 | ('key1', 'value2'), 26 | ('key2', 'value3'), 27 | ('key2', 'value4'), 28 | ('key2', 'value5'),) 29 | print(usual_dict(dict_data)) 30 | print(setdefault_dict(dict_data)) 31 | 32 | s = 'Tests in {name} have {con}!' 33 | print(s.format(name=module_name, con='passed')) 34 | 35 | 36 | if __name__ == "__main__": 37 | test_setdef() 38 | 39 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_sets.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | def difference(l1): 6 | """ return the list with duplicate elements removed """ 7 | return list(set(l1)) 8 | 9 | def intersection(l1, l2): 10 | """ return the intersection of two lists """ 11 | return list(set(l1) & set(l2)) 12 | 13 | def union(l1, l2): 14 | """ return the union of two lists """ 15 | return list(set(l1) | set(l2)) 16 | 17 | 18 | def test_sets_operations_with_lists(): 19 | l1 = [1,2,3,4,5,9,11,15] 20 | l2 = [4,5,6,7,8] 21 | l3 = [] 22 | assert(difference(l1) == [1, 2, 3, 4, 5, 9, 11, 15]) 23 | assert(difference(l2) == [8, 4, 5, 6, 7]) 24 | assert(intersection(l1, l2) == [4,5]) 25 | assert(union(l1, l2) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 15]) 26 | assert(difference(l3) == []) 27 | assert(intersection(l3, l2) == l3) 28 | assert(sorted(union(l3, l2)) == sorted(l2)) 29 | print('Tests passed!') 30 | 31 | 32 | if __name__ == "__main__": 33 | test_sets_operations_with_lists() 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_socket.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | __author__ = "bt3" 5 | 6 | 7 | import socket 8 | 9 | 10 | def netcat(hostname, port, content): 11 | 12 | s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 13 | 14 | s.connect((hostname, port)) 15 | s.sendall(content) 16 | 17 | adata = [] 18 | while 1: 19 | data = s.recv(1024) 20 | if data == '': 21 | break 22 | adata.append(data) 23 | 24 | s.close() 25 | return adata 26 | 27 | 28 | 29 | if __name__ == "__main__": 30 | 31 | PORT = 12345 32 | HOSTNAME = '54.209.5.48' 33 | 34 | message = netcat(HOSTNAME, PORT, 'Hello!')[1] 35 | print message -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_string_format.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | foo = 'foo' 7 | bar = 'bar' 8 | 9 | print '%s%s' % (foo, bar) # It is OK 10 | print '{0}{1}'.format(foo, bar) # It is better 11 | print '{foo}{bar}'.format(foo=foo, bar=bar) # It is best -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_subprocess.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | import subprocess,os 6 | 7 | os.system('ls') 8 | subprocess.call(['ls', '-1'], shell=True) 9 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_telnet.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | __author__ = "bt3" 5 | 6 | 7 | from telnetlib import Telnet 8 | 9 | 10 | # examples of telnet connections 11 | PORT = 12345 12 | HOST = '54.209.5.48' 13 | 14 | # creating connection 15 | tn = Telnet(HOST ,PORT) 16 | 17 | # reading input 18 | msg_in2 = tn.read_all().dec_msg() 19 | tn.read_until(b'psifer text: ') 20 | 21 | # writing outputs 22 | tn.write(msg.encode() + b'\n') 23 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_testing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | 7 | def test_doctest(): 8 | """ 9 | >>> 1 == 1 10 | False 11 | """ 12 | pass 13 | 14 | if __name__ == "__main__": 15 | import doctest 16 | doctest.testmod() 17 | 18 | ##### 19 | 20 | import unittest 21 | 22 | class BasicsTestCase(unittest.TestCase): 23 | 24 | def test_find_name(self): 25 | self.assertTrue(1 == 1) 26 | self.assertFalse(1 == 2) 27 | 28 | if __name__ == "__main__": 29 | unittest.main() 30 | 31 | 32 | 33 | ##### 34 | 35 | # content of test_example.py, run with $ py.test 36 | # 37 | # run tests over the directory 38 | # $ nosetest 39 | 40 | 41 | def func(x): 42 | return x + 1 43 | 44 | def test_answer(): 45 | assert func(3) == 4 46 | 47 | -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_threads.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | import threading 6 | 7 | def worker(num): 8 | """thread worker function""" 9 | print 'Worker: %s' % num 10 | return 11 | 12 | threads = [] 13 | for i in range(5): 14 | t = threading.Thread(target=worker, args=(i,)) 15 | threads.append(t) 16 | t.start() -------------------------------------------------------------------------------- /source_code/USEFUL/basic_examples/example_time.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | __author__ = "bt3" 4 | 5 | """ a simple example of how to time a function """ 6 | 7 | import time 8 | 9 | def sumOfN2(n): 10 | start = time.time() 11 | theSum = 0 12 | for i in range(1,n+1): 13 | theSum = theSum + i 14 | end = time.time() 15 | return theSum,end-start 16 | 17 | 18 | 19 | if __name__ == "__main__": 20 | n = 5 21 | print("Sum is %d and required %10.7f seconds"%sumOfN2(n)) 22 | n = 200 23 | print("Sum is %d and required %10.7f seconds"%sumOfN2(n)) 24 | 25 | -------------------------------------------------------------------------------- /source_code/USEFUL/dynamic_programming/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/c143f4248734b86f0b1783b6759ba8b9dbebf685/source_code/USEFUL/dynamic_programming/__init__.py -------------------------------------------------------------------------------- /source_code/USEFUL/dynamic_programming/memo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | from functools import wraps 7 | from do_benchmark import benchmark 8 | 9 | def memo(func): 10 | """ an example of dynamic programming using a memoizing decorator """ 11 | cache = {} 12 | @wraps(func) 13 | def wrap(*args): 14 | if args not in cache: 15 | cache[args] = func(*args) 16 | return cache[args] 17 | return wrap 18 | 19 | @memo 20 | def find_fibonacci_seq_rec(n): 21 | """ implements the nth fibonacci value in a recursive exponential runtime """ 22 | if n < 2: return n 23 | return find_fibonacci_seq_rec(n - 1) + find_fibonacci_seq_rec(n - 2) 24 | 25 | def test_memo(): 26 | n = 50 27 | # find_fibonacci_seq_rec = memo(find_fibonacci_seq_rec) 28 | # @benchmark 29 | print(find_fibonacci_seq_rec(n)) 30 | 31 | 32 | if __name__ == "__main__": 33 | test_memo() 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /source_code/USEFUL/oop/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/c143f4248734b86f0b1783b6759ba8b9dbebf685/source_code/USEFUL/oop/__init__.py -------------------------------------------------------------------------------- /source_code/USEFUL/useful_with_files/change_ext_file.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | __author__ = "bt3" 5 | 6 | 7 | import os 8 | import sys 9 | import shutil 10 | 11 | def change_file_ext(): 12 | """ read a file and an extension from the command line and produces a copy with its extension changed""" 13 | if len(sys.argv) < 2: 14 | print("Usage: change_ext.py filename.old_ext 'new_ext'") 15 | sys.exit() 16 | 17 | name = os.path.splitext(sys.argv[1])[0] + "." + sys.argv[2] 18 | print (name) 19 | 20 | try: 21 | shutil.copyfile(sys.argv[1], name) 22 | except OSError as err: 23 | print (err) 24 | 25 | 26 | 27 | if __name__ == "__main__": 28 | change_file_ext() 29 | 30 | 31 | -------------------------------------------------------------------------------- /source_code/USEFUL/useful_with_files/count_unique_words_files.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | import collections 7 | import string 8 | import sys 9 | 10 | def count_unique_word_file(): 11 | if len(sys.argv) < 2: 12 | print "Usage: python count_unique_word.py NAMEFILE" 13 | 14 | words = collections.defaultdict(int) 15 | strip = string.whitespace + string.punctuation + string.digits + "\"'" 16 | for filename in sys.argv[1:]: 17 | with open(filename) as file: 18 | for line in file: 19 | for word in line.lower().split(): 20 | word = word.strip(strip) 21 | if len(word) > 2: 22 | words[word] = +1 23 | for word in sorted(words): 24 | print("'{0}' occurs {1} times.".format(word, words[word])) 25 | 26 | 27 | if __name__ == "__main__": 28 | count_unique_word_file() -------------------------------------------------------------------------------- /source_code/USEFUL/useful_with_files/count_unique_words_frequency.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | import collections 7 | import sys 8 | 9 | def count_unique_word_freq(): 10 | return collections.Counter(\ 11 | sys.stdin.read().lower().split()).most_common(n) 12 | 13 | 14 | if __name__ == "__main__": 15 | count_unique_word_freq() -------------------------------------------------------------------------------- /source_code/USEFUL/useful_with_files/grep_word_from_files.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | __author__ = "bt3" 5 | 6 | import sys 7 | 8 | def grep_word_from_files(): 9 | """ using iterator enumerate to create a grep command """ 10 | word = sys.argv[1] 11 | for filename in sys.argv[2:]: 12 | with open(filename) as file: 13 | for lino, line in enumerate(file, start=1): 14 | if word in line: 15 | print("{0}:{1}:{2:.40}".format(filename, lino, line.rstrip())) 16 | 17 | 18 | if __name__ == "__main__": 19 | if len(sys.argv) < 2: 20 | print("Usage: grep_word_from_files.py word infile1 [infile2...]") 21 | sys.exit() 22 | else: 23 | grep_word_from_files() 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /source_code/USEFUL/useful_with_files/remove_blank_lines.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | 4 | __author__ = "bt3" 5 | 6 | 7 | 8 | import os 9 | import sys 10 | 11 | def read_data(filename): 12 | lines = [] 13 | fh = None 14 | try: 15 | fh = open(filename) 16 | for line in fh: 17 | if line.strip(): 18 | lines.append(line) 19 | except (IOError, OSError) as err: 20 | print(err) 21 | finally: 22 | if fh is not None: 23 | fh.close() 24 | return lines 25 | 26 | 27 | def write_data(lines, filename): 28 | fh = None 29 | try: 30 | fh = open(filename, "w") 31 | for line in lines: 32 | fh.write(line) 33 | except (EnvironmentError) as err: 34 | print(err) 35 | finally: 36 | if fh is not None: 37 | fh.close() 38 | 39 | 40 | def remove_blank_lines(): 41 | """ read a list of filenames on the command line and for each one produces another file with the same content but with no blank lines """ 42 | 43 | if len(sys.argv) < 2: 44 | print ("Usage: noblank.py infile1 [infile2...]") 45 | 46 | for filename in sys.argv[1:]: 47 | lines = read_data(filename) 48 | if lines: 49 | write_data(lines, filename) 50 | 51 | 52 | if __name__ == "__main__": 53 | remove_blank_lines() 54 | 55 | -------------------------------------------------------------------------------- /source_code/abstract_structures/HashTable.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | class HashTable(object): 7 | def __init__(self, slots=10): 8 | self.slots = slots 9 | self.table = [] 10 | self.create_table() 11 | 12 | def hash_key(self, value): 13 | return hash(value)%self.slots 14 | 15 | def create_table(self): 16 | for i in range(self.slots): 17 | self.table.append([]) 18 | 19 | def add_item(self, value): 20 | key = self.hash_key(value) 21 | self.table[key].append(value) 22 | 23 | def print_table(self): 24 | for key in range(len(self.table)): 25 | print "Key is %s, value is %s." %(key, self.table[key]) 26 | 27 | def find_item(self, item): 28 | pos = self.hash_key(item) 29 | if item in self.table[pos]: 30 | return True 31 | else: 32 | return False 33 | 34 | if __name__ == "__main__": 35 | dic = HashTable(5) 36 | for i in range(1, 40, 2): 37 | dic.add_item(i) 38 | 39 | dic.print_table() 40 | assert(dic.find_item(20) == False) 41 | assert(dic.find_item(21) == True) 42 | -------------------------------------------------------------------------------- /source_code/abstract_structures/Queue.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # Time: 5 min 3 | 4 | __author__ = "bt3" 5 | 6 | 7 | class Queue(object): 8 | def __init__(self): 9 | self.enq = [] 10 | self.deq = [] 11 | 12 | def enqueue(self, item): 13 | return self.enq.append(item) 14 | 15 | def deque(self): 16 | if not self.deq: 17 | while self.enq: 18 | self.deq.append(self.enq.pop()) 19 | return self.deq.pop() 20 | 21 | def peak(self): 22 | if not self.deq: 23 | while self.enq: 24 | self.deq.append(self.enq.pop()) 25 | if self.deq: 26 | return self.deq[-1] 27 | 28 | def size(self): 29 | return len(self.enq) + len(self.deq) 30 | 31 | def isempty(self): 32 | return not (self.enq + self.deq) 33 | 34 | if __name__ == "__main__": 35 | q = Queue() 36 | for i in range(1,11): 37 | q.enqueue(i) 38 | print 'Size:', q.size() 39 | print 'Is empty?', q.isempty() 40 | print 'Peak: ', q.peak() 41 | print 42 | print 'Dequeuing...' 43 | for i in range(10): 44 | print q.deque() 45 | print 'Size:', q.size() 46 | print 'Is empty?', q.isempty() 47 | print 'Peak: ', q.peak() -------------------------------------------------------------------------------- /source_code/abstract_structures/__init__.py: -------------------------------------------------------------------------------- 1 | __all__=["hash_tables", "heap", "linked_list", "queues", "stacks"] -------------------------------------------------------------------------------- /source_code/abstract_structures/heap/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/c143f4248734b86f0b1783b6759ba8b9dbebf685/source_code/abstract_structures/heap/__init__.py -------------------------------------------------------------------------------- /source_code/abstract_structures/heap/merge_sorted_seqs.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | import heapq 6 | 7 | 8 | def merge_sorted_seq(seq1, seq2): 9 | """ merge two sorted sequences with little ovehead. the result 10 | will be sorted, which is different of doing just +""" 11 | result = [] 12 | for c in heapq.merge(seq1, seq2): 13 | result.append(c) 14 | return result 15 | 16 | 17 | def test_merge_sorted_seq(module_name='this module'): 18 | seq1 = [1, 2, 3, 8, 9, 10] 19 | seq2 = [2, 3, 4, 5, 6, 7, 9] 20 | seq3 = seq1 + seq2 21 | assert(merge_sorted_seqseq1, seq2) == sorted(seq3)) 22 | 23 | 24 | 25 | if __name__ == "__main__": 26 | test_merge_sorted_seq() 27 | 28 | -------------------------------------------------------------------------------- /source_code/abstract_structures/heap/priority_queue.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | import heapq 6 | 7 | class PriorityQueue(object): 8 | """ implements a priority queue class """ 9 | def __init__(self): 10 | self._queue = [] 11 | self._index = 0 # comparying same priority level 12 | 13 | def push(self, item, priority): 14 | heapq.heappush(self._queue, (-priority, self._index, item)) 15 | self._index += 1 16 | 17 | def pop(self): 18 | return heapq.heappop(self._queue)[-1] 19 | 20 | 21 | class Item: 22 | def __init__(self, name): 23 | self.name = name 24 | def __repr__(self): 25 | return "Item({!r})".format(self.name) 26 | 27 | 28 | def test_PriorityQueue(): 29 | """ push and pop are all O(logN) """ 30 | q = PriorityQueue() 31 | q.push(Item('test1'), 1) 32 | q.push(Item('test2'), 4) 33 | q.push(Item('test3'), 3) 34 | assert(str(q.pop()) == "Item('test2')") 35 | 36 | 37 | if __name__ == "__main__": 38 | test_PriorityQueue() 39 | 40 | 41 | -------------------------------------------------------------------------------- /source_code/abstract_structures/linked_list/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/c143f4248734b86f0b1783b6759ba8b9dbebf685/source_code/abstract_structures/linked_list/__init__.py -------------------------------------------------------------------------------- /source_code/abstract_structures/linked_list/circular_ll.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ implement a function to see whether a linked list is circular. 7 | To implement this, we just need two pointers with different 8 | paces (for example, one goes twice faster)""" 9 | 10 | from linked_list_fifo import LinkedListFIFO 11 | from node import Node 12 | 13 | 14 | class cicularLinkedListFIFO(LinkedListFIFO): 15 | def _add(self, value): 16 | self.length += 1 17 | node = Node(value, self.head) 18 | if self.tail: 19 | self.tail.pointer = node 20 | self.tail = node 21 | 22 | 23 | 24 | 25 | def isCircularll(ll): 26 | p1 = ll.head 27 | p2 = ll.head 28 | 29 | while p2: 30 | try: 31 | p1 = p1.pointer 32 | p2 = p2.pointer.pointer 33 | except: 34 | break 35 | 36 | if p1 == p2: 37 | return True 38 | return False 39 | 40 | 41 | 42 | if __name__ == "__main__": 43 | 44 | ll = LinkedListFIFO() 45 | for i in range(10): 46 | ll.addNode(i) 47 | ll._printList() 48 | 49 | print(isCircularll(ll)) 50 | 51 | lcirc = cicularLinkedListFIFO() 52 | for i in range(10): 53 | lcirc.addNode(i) 54 | print(isCircularll(lcirc)) 55 | 56 | -------------------------------------------------------------------------------- /source_code/abstract_structures/linked_list/find_kth_from_the_end.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ Find the mth-to-last element of a linked list. 7 | One option is having two pointers, separated by m. P1 start at the roots 8 | (p1 = self.root) and p2 is m-behinf pointer, which is created when p1 is at m. 9 | When p1 reach the end, p2 is the node. """ 10 | 11 | from linked_list_fifo import LinkedListFIFO 12 | from node import Node 13 | 14 | 15 | class LinkedListFIFO_find_kth(LinkedListFIFO): 16 | 17 | 18 | def find_kth_to_last(self, k): 19 | p1, p2 = self.head, self.head 20 | i = 0 21 | while p1: 22 | if i > k: 23 | try: 24 | p2 = p2.pointer 25 | except: 26 | break 27 | p1 = p1.pointer 28 | i += 1 29 | return p2.value 30 | 31 | 32 | 33 | if __name__ == "__main__": 34 | ll = LinkedListFIFO_find_kth() 35 | for i in range(1, 11): 36 | ll.addNode(i) 37 | print('The Linked List:') 38 | print(ll._printList()) 39 | k = 3 40 | k_from_last = ll.find_kth_to_last(k) 41 | print("The %dth element to the last of the LL of size %d is %d" %(k, ll.length, k_from_last)) 42 | 43 | -------------------------------------------------------------------------------- /source_code/abstract_structures/linked_list/node.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | class Node(object): 6 | def __init__(self, value=None, pointer=None): 7 | self.value = value 8 | self.pointer = pointer 9 | 10 | def getData(self): 11 | return self.value 12 | 13 | def getNext(self): 14 | return self.pointer 15 | 16 | def setData(self, newdata): 17 | self.value = newdata 18 | 19 | def setNext(self, newpointer): 20 | self.pointer = newpointer 21 | 22 | 23 | 24 | if __name__ == "__main__": 25 | L = Node("a", Node("b", Node("c", Node("d")))) 26 | assert(L.pointer.pointer.value=='c') 27 | 28 | print(L.getData()) 29 | print(L.getNext().getData()) 30 | L.setData('aa') 31 | L.setNext(Node('e')) 32 | print(L.getData()) 33 | print(L.getNext().getData()) 34 | -------------------------------------------------------------------------------- /source_code/abstract_structures/linked_list/part_linked_list.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ This function divides a linked list in a value, where everything smaller than this value 6 | goes to the front, and everything large goes to the back:""" 7 | 8 | 9 | from linked_list_fifo import LinkedListFIFO 10 | from node import Node 11 | 12 | 13 | def partList(ll, n): 14 | 15 | more = LinkedListFIFO() 16 | less = LinkedListFIFO() 17 | 18 | node = ll.head 19 | 20 | while node: 21 | item = node.value 22 | 23 | if item < n: 24 | less.addNode(item) 25 | 26 | elif item > n: 27 | more.addNode(item) 28 | 29 | node = node.pointer 30 | 31 | less.addNode(n) 32 | nodemore = more.head 33 | 34 | while nodemore: 35 | less.addNode(nodemore.value) 36 | nodemore = nodemore.pointer 37 | 38 | return less 39 | 40 | 41 | 42 | 43 | if __name__ == "__main__": 44 | 45 | ll = LinkedListFIFO() 46 | l = [6, 7, 3, 4, 9, 5, 1, 2, 8] 47 | for i in l: 48 | ll.addNode(i) 49 | 50 | print('Before Part') 51 | ll._printList() 52 | 53 | print('After Part') 54 | newll = partList(ll, 6) 55 | newll._printList() 56 | 57 | 58 | -------------------------------------------------------------------------------- /source_code/abstract_structures/queues/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/c143f4248734b86f0b1783b6759ba8b9dbebf685/source_code/abstract_structures/queues/__init__.py -------------------------------------------------------------------------------- /source_code/abstract_structures/queues/deque.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ a class for a double ended queue (also inefficient) """ 6 | 7 | from queue import Queue 8 | 9 | class Deque(Queue): 10 | 11 | def enqueue_back(self, item): 12 | self.items.append(item) 13 | 14 | def dequeue_front(self): 15 | return self.items.pop(0) 16 | 17 | 18 | 19 | if __name__ == "__main__": 20 | queue = Deque() 21 | print("Is the queue empty? ", queue.isEmpty()) 22 | print("Adding 0 to 10 in the queue...") 23 | for i in range(10): 24 | queue.enqueue(i) 25 | print("Queue size: ", queue.size()) 26 | print("Queue peek : ", queue.peek()) 27 | print("Dequeue...", queue.dequeue()) 28 | print("Queue peek: ", queue.peek()) 29 | print("Is the queue empty? ", queue.isEmpty()) 30 | print(queue) 31 | 32 | print("\nNow using the dequeue methods...") 33 | print("Dequeue from front...", queue.dequeue_front()) 34 | print("Queue peek: ", queue.peek()) 35 | print(queue) 36 | print("Queue from back...") 37 | queue.enqueue_back(50) 38 | print("Queue peek: ", queue.peek()) 39 | print(queue) 40 | -------------------------------------------------------------------------------- /source_code/abstract_structures/queues/palindrome_checker_with_deque.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ Using our deque class and Python's deque class """ 7 | 8 | 9 | import string 10 | import collections 11 | 12 | from deque import Deque 13 | 14 | 15 | STRIP = string.whitespace + string.punctuation + "\"'" 16 | 17 | def palindrome_checker_with_deque(str1): 18 | 19 | d1 = Deque() 20 | d2 = collections.deque() 21 | 22 | for s in str1.lower(): 23 | if s not in STRIP: 24 | d2.append(s) 25 | d1.enqueue(s) 26 | 27 | 28 | eq1 = True 29 | while d1.size() > 1 and eq1: 30 | if d1.dequeue_front() != d1.dequeue(): 31 | eq1 = False 32 | 33 | eq2 = True 34 | while len(d2) > 1 and eq2: 35 | if d2.pop() != d2.popleft(): 36 | eq2 = False 37 | 38 | return eq1, eq2 39 | 40 | 41 | 42 | 43 | if __name__ == "__main__": 44 | str1 = 'Madam Im Adam' 45 | str2 = 'Buffy is a Slayer' 46 | print(palindrome_checker_with_deque(str1)) 47 | print(palindrome_checker_with_deque(str2)) -------------------------------------------------------------------------------- /source_code/abstract_structures/stacks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/c143f4248734b86f0b1783b6759ba8b9dbebf685/source_code/abstract_structures/stacks/__init__.py -------------------------------------------------------------------------------- /source_code/abstract_structures/stacks/dec2bin_with_stack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """transform a decimal number to a binary number with a stack """ 7 | 8 | 9 | from stack import Stack 10 | 11 | def dec2bin_with_stack(decnum): 12 | 13 | s = Stack() 14 | str_aux = '' 15 | 16 | while decnum > 0: 17 | dig = decnum % 2 18 | decnum = decnum//2 19 | s.push(dig) 20 | 21 | while not s.isEmpty(): 22 | str_aux += str(s.pop()) 23 | 24 | return str_aux 25 | 26 | 27 | 28 | if __name__ == "__main__": 29 | decnum = 9 30 | assert(dec2bin_with_stack(decnum) == '1001') 31 | -------------------------------------------------------------------------------- /source_code/abstract_structures/stacks/reverse_string_with_stack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ Uses a stack to reverse a string """ 7 | 8 | from stack import Stack 9 | 10 | def reverse_string_with_stack(str1): 11 | 12 | s = Stack() 13 | revStr = '' 14 | 15 | for c in str1: 16 | s.push(c) 17 | 18 | while not s.isEmpty(): 19 | revStr += s.pop() 20 | 21 | return revStr 22 | 23 | 24 | 25 | if __name__ == "__main__": 26 | str1 = 'Buffy is a Slayer!' 27 | print(str1) 28 | print(reverse_string_with_stack(str1)) 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /source_code/abstract_structures/stacks/towers_of_hanoi.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | 7 | """ Implement the 'towers of hanoi'""" 8 | 9 | from linked_stack import Stack, Node 10 | 11 | 12 | def moveTop(s1, s3): 13 | 14 | s3.append(s1.pop()) 15 | 16 | 17 | def moveDisks(n, s1, s3, s2): 18 | 19 | if n < 1: return 20 | moveDisks(n - 1, s1, s2, s3) 21 | moveTop(s1, s3) 22 | moveDisks(n -1, s2, s3, s1) 23 | 24 | 25 | 26 | def towersOfHanoi(n): 27 | s1 = [x+1 for x in range(n)] 28 | s2 = [] 29 | s3 = [] 30 | print('The first stick is {0} and the third stick has {1}'.format(s1, s3)) 31 | 32 | moveDisks(n, s1, s3, s2) 33 | 34 | print('The first stick is {0} and the third stick has {1}'.format(s1, s3)) 35 | 36 | return s3 37 | 38 | 39 | 40 | if __name__ == "__main__": 41 | towersOfHanoi(6) 42 | -------------------------------------------------------------------------------- /source_code/bitwise/bit_array.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ Example of how to use a bit array in python as a "counter" dict""" 6 | 7 | def print_dupl_ba(l1): 8 | """ 9 | >>> l1 = [0, 1, 2, 3, 4, 2, 6, 7, 8, 9] 10 | >>> print_dupl_ba(l1) 11 | 2 12 | """ 13 | 14 | bs = bytearray(10) 15 | for i in range(len(l1)): 16 | if i == l1[i]: 17 | bs[i] = 1 18 | for index, bit in enumerate(bs): 19 | if bit == 0: 20 | return l1[index] 21 | return None 22 | 23 | 24 | 25 | if __name__ == "__main__": 26 | import doctest 27 | doctest.testmod() 28 | 29 | -------------------------------------------------------------------------------- /source_code/bitwise/bitwise.txt: -------------------------------------------------------------------------------- 1 | BIT-WISE 2 | ---------------------- 3 | 4 | 1. To find a number: 5 | 11000101 is 2^0+2^2+2^6+2^7 = 197 6 | 7 | 8 | 2. Left shifting: 9 | 0010 1011 << 4 ---> 1011 000 10 | 11 | 12 | 3. Right shifting: 13 | 0010 1011 >> 4 ---> 0000 0010 14 | or it can be filled with the copy of the first bit, instead of 0: 15 | 1011 0010 >> 4 ---> 1111 1011 16 | 17 | 18 | 4. XOR can cancels out: 19 | 15 ^ 12 ^ 15 = 12 20 | 21 | 22 | 5. 2^x: 23 | left-shift 1 by x: 24 | 0000 0001 << x 25 | 26 | so if x = 2, 2^2 = 4 -> 100 27 | 28 | 0000 0001 << 2 ---> 0000 0100 29 | 30 | 31 | 6. Is power of 2? 32 | just do x&(x-1). 33 | if 0 --> yes! 34 | -------------------------------------------------------------------------------- /source_code/bitwise/clear_bits.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ Clear a bit in a binary number. 6 | Like the reverse of set bit: 7 | 1) first create a number filled of 1s, 8 | with 0 at i (can create 0001000 and ~) 9 | 2) AND the number so it clears the ith bit 10 | """ 11 | 12 | 13 | 14 | def clear_bit(num, i): 15 | mask = ~ (1 << i) # -0b10001 16 | return bin(num & mask) 17 | 18 | 19 | def clear_all_bits_from_i_to_0(num, i): 20 | mask = ~ ( (1 << (i+1)) - 1) 21 | return bin(num & mask) 22 | 23 | 24 | def clear_all_bits_from_most_sig_to_1(num, i): 25 | mask = ( 1 << i) -1 26 | return bin(num & mask) 27 | 28 | 29 | if __name__ == "__main__": 30 | num = int('10010000', 2) 31 | print clear_bit(num, 4) # '0b10000000' 32 | 33 | num = int('10010011', 2) 34 | print clear_all_bits_from_i_to_0(num, 2) # '0b10010000' 35 | 36 | num = int('1110011', 2) 37 | print clear_all_bits_from_most_sig_to_1(num, 2) #'0b11' 38 | -------------------------------------------------------------------------------- /source_code/bitwise/find_bit_len.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ Find how many bits a int has: 6 | 1) Start with a mask of 1 7 | 2) Mask with AND 8 | 3) if result (if true): count += 1 9 | (obs: to find the int of a bin do int('1001', 2)) and to show in bin 10 | do bin(int)) 11 | """ 12 | 13 | 14 | def find_bit_len(int_num): 15 | lenght = 0 16 | while int_num: 17 | int_num >>= 1 18 | lenght += 1 19 | return lenght 20 | 21 | 22 | if __name__ == "__main__": 23 | for i in range(17): 24 | print(find_bit_len(i)) 25 | print i.bit_length() 26 | -------------------------------------------------------------------------------- /source_code/bitwise/find_how_many_1_binary.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ Find how many 1s in the binary: 6 | 1) Start with a mask of 1 7 | 2) Mask with AND 8 | 3) if result (if true): count += 1 9 | (obs: to find the int of a bin do int('1001', 10 | 2)) and to show in bin do bin(int)) 11 | """ 12 | 13 | 14 | def find_how_many_1_in_a_binary(n): 15 | """ 16 | >>> find_how_many_1_in_a_binary(9) 17 | 2 18 | """ 19 | 20 | counter = 0 21 | while n: 22 | if n & 1: 23 | counter += 1 24 | n >>= 1 25 | return counter 26 | 27 | 28 | 29 | if __name__ == "__main__": 30 | import doctest 31 | doctest.testmod() 32 | 33 | -------------------------------------------------------------------------------- /source_code/bitwise/get_bit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ Get a bit in a binary number: 6 | 1) Shifts 1 over by i bits 7 | 2) make an AND with the number 8 | 3) all the other than the bit at i are clean, now compare to 0 9 | 4) if the new value is not 0, bit i is 1 10 | """ 11 | 12 | 13 | def get_bit(num, i): 14 | mask = 1 << i 15 | return num & mask != 0 16 | 17 | 18 | if __name__ == "__main__": 19 | num = int('0100100', 2) 20 | get_bit(num, 0) # 0 21 | get_bit(num, 1) # 0 22 | get_bit(num, 2) # 1 23 | get_bit(num, 3) # 0 24 | get_bit(num, 4) # 0 25 | get_bit(num, 5) # 1 26 | get_bit(num, 6) # 0 27 | 28 | -------------------------------------------------------------------------------- /source_code/bitwise/get_float_rep_bin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ Given a real number between 0 and 1 (eg: 0.72), this method print the binary 6 | representation. If the Number cannot be represented accurately in binary, with at 7 | most 32 chars, print error: 8 | """ 9 | 10 | def get_float_rep(num): 11 | """ 12 | >>> get_float_rep(0.72) 13 | ('Error 2', '.1011100001010001111010111000010') 14 | >>> get_float_rep(0.1) 15 | ('Error 2', '.0001100110011001100110011001100') 16 | >>> get_float_rep(0.5) 17 | '.1' 18 | """ 19 | 20 | if num >= 1 or num <= 0: return 'Error 1' 21 | result = '.' 22 | while num: 23 | if len(result) >= 32: return 'Error 2', result 24 | r = num*2 25 | if r >= 1: 26 | result += '1' 27 | num = r - 1 28 | else: 29 | result += '0' 30 | num = r 31 | return result 32 | 33 | 34 | if __name__ == "__main__": 35 | import doctest 36 | doctest.testmod() 37 | 38 | -------------------------------------------------------------------------------- /source_code/bitwise/insert_small_bin_into_big_bin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ Given two 32-bit numbers, N and M, and two bit positions, i and j, this 7 | method insert M into N such that M starts at bit j and ends at bit i: 8 | 1) clear the bits j thru i in N' 9 | 2) shift M so that it lines up with bits j thru i 10 | 3) merge M and N 11 | """ 12 | 13 | def insert_small_bin_into_big_bin(M, N, i, j): 14 | """ 15 | >>> N = 0b10000000000 16 | >>> M = 0b10011 17 | >>> j = 6 18 | >>> i = 2 19 | >>> insert_small_bin_into_big_bin(M, N, i, j) 20 | '0b10001001100' 21 | """ 22 | 23 | allOnes = ~0 24 | left = allOnes << (j+1) # 1110000 25 | right = ( (1 << i) - 1) # 0000111 26 | mask = left | right # 1110111 27 | N_cleared = N & mask 28 | M_shifted = M << i 29 | 30 | return bin( N_cleared | M_shifted) 31 | 32 | 33 | if __name__ == "__main__": 34 | import doctest 35 | doctest.testmod() 36 | 37 | -------------------------------------------------------------------------------- /source_code/bitwise/next_with_same_num_1s.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ Give a positive int, print the next smallest and next largest ints with 7 | same number of 1 bits. 8 | The brute force is: 9 | 1) find number of 1 bits 10 | 2) loop above and down until find same, checking for each 11 | """ 12 | 13 | 14 | 15 | def print_prev_same_1s(num): 16 | n1s = find_num_1s(num) 17 | # find prev 18 | i = num-1 19 | while True: 20 | n1s_here = find_num_1s(i) 21 | if n1s_here == n1s: 22 | return bin(i) 23 | i -= 1 24 | if i < 0: 25 | return None 26 | 27 | def print_next_same_1s(num): 28 | n1s = find_num_1s(num) 29 | # find next 30 | i = num+1 31 | while True: 32 | n1s_here = find_num_1s(i) 33 | if n1s_here == n1s: 34 | return bin(i) 35 | i += 1 36 | if i < 0: 37 | return None 38 | 39 | 40 | 41 | def find_num_1s(num): 42 | counter = 0 43 | while num: 44 | if num & 1: 45 | counter += 1 46 | num >>= 1 47 | return counter 48 | 49 | 50 | 51 | 52 | 53 | if __name__ == "__main__": 54 | num = 0b1001 55 | n = '0b1010' 56 | p = '0b110' 57 | print_prev_same_1s(num) == p 58 | print_next_same_1s(num) == n 59 | 60 | -------------------------------------------------------------------------------- /source_code/bitwise/num_bits_to_convert_2_nums.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ This method returns the number of bits that are necessary to change to convert two 7 | numbers A and B: 8 | 1) XOR 9 | 2) count 1s 10 | """ 11 | 12 | def count_bits_swap2(a, b): 13 | count = 0 14 | m = a^b 15 | while m: 16 | count +=1 17 | m = m & (m-1) 18 | return count 19 | 20 | 21 | 22 | def count_bits_swap(a, b): 23 | m = a^b 24 | return count_1s(m) 25 | 26 | 27 | def count_1s(m): 28 | count = 0 29 | while m: 30 | if m& 1 : 31 | count +=1 32 | m >>= 1 33 | return count 34 | 35 | 36 | if __name__ == "__main__": 37 | a = int('10010000', 2) 38 | b = int('01011010', 2) 39 | print count_bits_swap(a, b) #4 40 | print count_bits_swap2(a, b) #4 41 | -------------------------------------------------------------------------------- /source_code/bitwise/set_bit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | 7 | """ Set a bit in a binary number: 8 | 1) Shifts 1 over by i bits 9 | 2) make an OR with the number, only the value at bit i will change and all the others bit 10 | of the mask are zero so will not affect the num 11 | """ 12 | 13 | 14 | def set_bit(num, i): 15 | mask = 1 << i 16 | return bin( num | mask ) 17 | 18 | 19 | if __name__ == "__main__": 20 | num = int('0100100', 2) 21 | print set_bit(num, 0) #'0b100101' 22 | print set_bit(num, 1) #'0b100110' 23 | print set_bit(num, 2) # nothing change '0b100100' 24 | print set_bit(num, 3) #'0b101100' 25 | print set_bit(num, 4) #'0b110100' 26 | print set_bit(num, 5) # nothing change '0b100100' 27 | -------------------------------------------------------------------------------- /source_code/bitwise/swap_in_place.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ 6 | swapping values in place without extra memory 7 | """ 8 | 9 | 10 | def swap_bit(a, b): 11 | """ 12 | >>> swap_bit(14, 73) 13 | (73, 14) 14 | """ 15 | a = a^b 16 | b = a^b 17 | a = a^b 18 | return a, b 19 | 20 | 21 | if __name__ == "__main__": 22 | import doctest 23 | doctest.testmod() -------------------------------------------------------------------------------- /source_code/bitwise/swap_odd_even.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ Swap odd and even bits in a smart way in a binary: 7 | 1) first for odds, take n and move the odd: 8 | (a) Mask all odd bits with 10101010 (0xAA) 9 | (b) shift by right by 1 10 | 2) do the same to ints with 01010101 11 | 3) merge 12 | """ 13 | 14 | 15 | 16 | def swap_odd_even(num): 17 | """ 18 | >>> num = 0b11011101 19 | >>> result = '0b1101110' 20 | >>> swap_odd_even(num) == result 21 | True 22 | """ 23 | 24 | mask_odd = 0xAA # 0b10101010 25 | mask_even = 0x55 # 0b1010101 26 | odd = num & mask_odd 27 | odd >>= 1 28 | even = num & mask_even 29 | even >>= 1 30 | return bin(odd | even) 31 | 32 | 33 | 34 | if __name__ == "__main__": 35 | import doctest 36 | doctest.testmod() 37 | 38 | -------------------------------------------------------------------------------- /source_code/bitwise/update_bit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ This method merges set bit and clean bit: 6 | 1) first clear the bit at i using a mask such as 1110111 7 | 2) then shift the intended value v by i bits 8 | 3) this will create a number with bit i to v and all other to 0 9 | 4) finally update the ith bit with or 10 | """ 11 | 12 | 13 | 14 | def update_bit(num, i, v): 15 | mask = ~ (1 << i) 16 | return bin( (num & mask) | (v << i) ) 17 | 18 | 19 | if __name__ == "__main__": 20 | num = int('10010000', 2) 21 | print update_bit(num, 2, 1) # '0b10010100' 22 | 23 | -------------------------------------------------------------------------------- /source_code/builtin_structures/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/c143f4248734b86f0b1783b6759ba8b9dbebf685/source_code/builtin_structures/__init__.py -------------------------------------------------------------------------------- /source_code/builtin_structures/anagram.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | from collections import Counter 7 | 8 | def is_anagram(s1, s2): 9 | """ 10 | >>> is_anagram('cat', 'tac') 11 | True 12 | >>> is_anagram('cat', 'hat') 13 | False 14 | """ 15 | counter = Counter() 16 | for c in s1: 17 | counter[c] += 1 18 | 19 | for c in s2: 20 | counter[c] -= 1 21 | 22 | for i in counter.values(): 23 | if i: 24 | return False 25 | 26 | return True 27 | 28 | """ verify if words are anagrams by comparing a sum of Unicode code 29 | point of the character""" 30 | 31 | def get_unicode_sum(word): 32 | s = 0 33 | for p in word: 34 | s += ord(p) 35 | return s 36 | 37 | 38 | def is_anagram2(word1, word2): 39 | """ 40 | >>> is_anagram2('cat', 'tac') 41 | True 42 | >>> is_anagram2('cat', 'hat') 43 | False 44 | """ 45 | return get_unicode_sum(word1) == get_unicode_sum(word2) 46 | 47 | 48 | if __name__ == "__main__": 49 | import doctest 50 | doctest.testmod() 51 | 52 | -------------------------------------------------------------------------------- /source_code/builtin_structures/balance.txt: -------------------------------------------------------------------------------- 1 | __author__ = "bt3" 2 | 3 | 4 | This is the classic "you have 8 balls/coins, which are the same weight, except for one which is slightly heavier than the others. You also have an old-style balance. What is the fewest number of weighings to find the heavy coin/ball? 5 | 6 | Answer: 2! You need to use every information available: 7 | Weight 3 x 3 balls/coins. 8 | If they weight the same: weight the 2 balls/coins left outside. 9 | Else, measure 2 of the 3 heavier balls/coins. -------------------------------------------------------------------------------- /source_code/builtin_structures/balance_symbols.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ 6 | Given a N different open and close braces in a string "( { [ } ] )". 7 | How do you check whether the string has matching braces. 8 | """ 9 | 10 | from collections import Counter 11 | def check_if_balance(string): 12 | """ 13 | >>> check_if_balance('{[[(])}]') 14 | True 15 | >>> check_if_balance('{[[()}]') 16 | False 17 | >>> check_if_balance('') 18 | True 19 | """ 20 | table = Counter() 21 | for i in string: 22 | 23 | index = str(ord(i))[0] 24 | if i in '{[(': 25 | table[index] += 1 26 | 27 | elif i in ')}]': 28 | table[index] -= 1 29 | 30 | for i in table.values(): 31 | if i !=-0: 32 | return False 33 | return True 34 | 35 | 36 | 37 | if __name__ == "__main__": 38 | import doctest 39 | doctest.testmod() 40 | 41 | -------------------------------------------------------------------------------- /source_code/builtin_structures/check_if_3_numbers_sum_to_zero.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ Determine if an Array of integers contains 3 numbers that sum to 0 """ 7 | 8 | from collections import defaultdict 9 | 10 | def find_3_number(array): 11 | """ 12 | >>> find_3_number([1,5,56,11,-3,-12]) 13 | 1 11 -12 14 | True 15 | >>> find_3_number([] ) 16 | False 17 | """ 18 | hash_ = defaultdict() 19 | for i in array: 20 | hash_[i] = 1 21 | 22 | for i, x in enumerate(array): 23 | for y in array[i+1:]: 24 | if -(x+y) in hash_: 25 | print x, y, -(x+y) 26 | return True 27 | 28 | return False 29 | 30 | 31 | 32 | 33 | if __name__ == "__main__": 34 | import doctest 35 | doctest.testmod() 36 | 37 | -------------------------------------------------------------------------------- /source_code/builtin_structures/check_non_overlapping_intervals.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ 7 | given an array of intervals, return max number of non-overlapping intervals 8 | """ 9 | 10 | from collections import defaultdict 11 | 12 | def non_overlapping(array): 13 | """ 14 | >>> non_overlapping([(1,2), (2,5), (1, 6)]) 15 | [[(1, 2), (2, 5)]] 16 | >>> non_overlapping([(1,4), (2,5), (3, 6)]) 17 | [] 18 | """ 19 | total = [] 20 | 21 | for i, t in enumerate(array): 22 | start = t[0] 23 | end = t[1] 24 | for tt in array[i+1:] : 25 | if end <= tt[0]: 26 | total.append([(start, end), (tt[0], tt[1])]) 27 | 28 | return total 29 | 30 | 31 | 32 | if __name__ == "__main__": 33 | import doctest 34 | doctest.testmod() 35 | 36 | -------------------------------------------------------------------------------- /source_code/builtin_structures/count_unique_words_On2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | import collections 6 | import string 7 | import sys 8 | 9 | 10 | def count_unique_word(): 11 | 12 | words = collections.defaultdict(int) 13 | 14 | strip = string.whitespace + string.punctuation + string.digits + "\"'" 15 | 16 | for filename in sys.argv[1:]: 17 | with open(filename) as file: 18 | for line in file: 19 | for word in line.lower().split(): 20 | word = word.strip(strip) 21 | if len(word) > 2: 22 | words[word] = +1 23 | 24 | for word in sorted(words): 25 | print("'{0}' occurs {1} times.".format(word, words[word])) 26 | 27 | -------------------------------------------------------------------------------- /source_code/builtin_structures/delete_duplicate_char_str.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ find and delete all the duplicate characters in a string """ 6 | 7 | from collections import Counter 8 | 9 | def delete_unique(str1): 10 | """ 11 | >>> delete_unique("Trust no one") 12 | 'on' 13 | >>> delete_unique("Mulder?") 14 | '' 15 | """ 16 | 17 | str_strip = ''.join(str1.split()) 18 | repeat = Counter() 19 | 20 | for c in str_strip: 21 | repeat[c] += 1 22 | 23 | result = '' 24 | for c, count in repeat.items(): 25 | if count > 1: 26 | result += c 27 | 28 | return result 29 | 30 | 31 | def removing_duplicates_seq(str1): 32 | """ 33 | >>> delete_unique("Trust no one") 34 | 'on' 35 | >>> delete_unique("Mulder?") 36 | '' 37 | """ 38 | seq = str1.split() 39 | result = set() 40 | for item in seq: 41 | if item not in result: 42 | #yield item 43 | result.add(item) 44 | return result 45 | 46 | 47 | if __name__ == "__main__": 48 | import doctest 49 | doctest.testmod() 50 | -------------------------------------------------------------------------------- /source_code/builtin_structures/fibonacci.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def fib_generator(): 7 | a, b = 0, 1 8 | 9 | while True: 10 | yield b 11 | a, b = b, a+b 12 | 13 | 14 | def fib(n): 15 | """ 16 | >>> fib(2) 17 | 1 18 | >>> fib(5) 19 | 5 20 | >>> fib(7) 21 | 13 22 | """ 23 | if n < 3: 24 | return 1 25 | 26 | a, b = 0, 1 27 | count = 1 28 | 29 | while count < n: 30 | count += 1 31 | a, b = b, a+b 32 | 33 | return b 34 | 35 | 36 | def fib_rec(n): 37 | """ 38 | >>> fib_rec(2) 39 | 1 40 | >>> fib_rec(5) 41 | 5 42 | >>> fib_rec(7) 43 | 13 44 | """ 45 | if n < 3: 46 | return 1 47 | return fib_rec(n - 1) + fib_rec(n - 2) 48 | 49 | 50 | 51 | 52 | if __name__ == "__main__": 53 | import doctest 54 | doctest.testmod() 55 | 56 | fib = fib_generator() 57 | print(next(fib)) 58 | print(next(fib)) 59 | print(next(fib)) 60 | print(next(fib)) 61 | -------------------------------------------------------------------------------- /source_code/builtin_structures/find_0_MxN_replace_cols_rows.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def find_0_MxN(m): 7 | """ find 0s in a matrix and replace the col and row to 0s: 8 | >>> m1 = [[1,2,3,4], [5,6,7,8], [9,10,11,12], [13,14,15,16]] 9 | >>> find_0_MxN(m1) 10 | [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] 11 | >>> m2 = [[1, 2, 3, 4], [0, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]] 12 | >>> find_0_MxN(m2) 13 | [[0, 2, 3, 4], [0, 0, 0, 0], [0, 10, 11, 12], [0, 14, 15, 16]] 14 | """ 15 | index = [] 16 | 17 | for row in range(len(m)): 18 | for col in range(len(m[0])): 19 | if m[row][col] == 0: 20 | index.append((row, col)) 21 | for i in index: 22 | row = i[0] 23 | col = i[1] 24 | for i in range(len(m)): 25 | m[row][i] = 0 26 | for i in range(len(m[0])): 27 | m[i][col] = 0 28 | 29 | return m 30 | 31 | 32 | if __name__ == "__main__": 33 | import doctest 34 | doctest.testmod() 35 | 36 | -------------------------------------------------------------------------------- /source_code/builtin_structures/find_dice_probabilities.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ 6 | given 2 dice, determine number of ways to sum S if all dice are rolled 7 | """ 8 | 9 | from collections import Counter, defaultdict 10 | 11 | def find_dice_probabilities(S=5, n_faces=6): 12 | if S > 2*n_faces or S < 2: 13 | return None 14 | 15 | cdict = Counter() 16 | ddict = defaultdict(list) 17 | 18 | for dice1 in range(1, n_faces+1): 19 | for dice2 in range(1, n_faces+1): 20 | t = [dice1, dice2] 21 | cdict[dice1+dice2] += 1 22 | ddict[dice1+dice2].append( t) 23 | 24 | return [cdict[S], ddict[S]] 25 | 26 | 27 | 28 | 29 | 30 | if __name__ == "__main__": 31 | results = find_dice_probabilities() 32 | assert(results[0] == len(results[1])) 33 | -------------------------------------------------------------------------------- /source_code/builtin_structures/find_edit_distance.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ computes the edit distance between two strings """ 7 | 8 | 9 | def find_edit_distance(str1, str2): 10 | """ 11 | >>> s = 'sunday' 12 | >>> t = 'saturday' 13 | >>> find_edit_distance(s, t) 14 | 3 15 | """ 16 | 17 | m = len(str1) 18 | n = len(str2) 19 | diff = lambda c1, c2: 0 if c1 == c2 else 1 20 | 21 | E = [[0] * (n + 1) for i in range(m + 1)] 22 | 23 | for i in range(m + 1): 24 | E[i][0] = i 25 | 26 | for j in range(1, n + 1): 27 | E[0][j] = j 28 | 29 | for i in range(1, m + 1): 30 | for j in range(1, n + 1): 31 | E[i][j] = min(E[i-1][j] + 1, E[i][j-1] + 1, E[i-1][j-1] + diff(str1[i-1], str2[j-1])) 32 | 33 | return E[m][n] 34 | 35 | 36 | 37 | if __name__ == "__main__": 38 | import doctest 39 | doctest.testmod() 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /source_code/builtin_structures/find_first_non_repetead_char.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | from collections import Counter 6 | 7 | def find_non_rep_char(s1): 8 | """ 9 | >>> s1 = 'aabbcceff' 10 | >>> find_non_rep_char(s1) 11 | e 12 | >>> find_non_rep_char('ccc') 13 | """ 14 | 15 | aux_dict = Counter() 16 | 17 | for i in s1: 18 | aux_dict[i] += 1 19 | 20 | for k, v in aux_dict.items(): 21 | if v < 2: 22 | print k 23 | 24 | 25 | 26 | if __name__ == "__main__": 27 | import doctest 28 | doctest.testmod() 29 | 30 | -------------------------------------------------------------------------------- /source_code/builtin_structures/find_gcd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | 7 | def finding_gcd(a, b): 8 | """ implements the greatest common divider algorithm """ 9 | while(b != 0): 10 | result = b 11 | a, b = b, a % b 12 | return result 13 | 14 | 15 | def test_finding_gcd(): 16 | number1 = 21 17 | number2 = 12 18 | assert(finding_gcd(number1, number2) == 3) 19 | print('Tests passed!') 20 | 21 | if __name__ == "__main__": 22 | test_finding_gcd() 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /source_code/builtin_structures/find_if_substr.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def find_substr(s1, s2): 7 | 8 | if len(s1) < len(s2): 9 | bs = s2 10 | ss = s1 11 | else: 12 | bs = s1 13 | ss = s2 14 | 15 | ps = 0 16 | 17 | for c in bs: 18 | 19 | if ss[ps] == c: 20 | ps += 1 21 | else: 22 | ps = 0 23 | 24 | if ps == len(ss)-1: 25 | return True 26 | 27 | return False 28 | 29 | 30 | 31 | if __name__ == "__main__": 32 | s1 = 'buffy is a vampire slayer' 33 | s2 = 'vampire' 34 | s3 = 'angel' 35 | assert(find_substr(s2, s1) == True) 36 | assert(find_substr(s3, s1) == False) -------------------------------------------------------------------------------- /source_code/builtin_structures/find_if_unique_char.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | 7 | import collections 8 | 9 | def find_if_unique_chars(word): 10 | """ 11 | >>> find_if_unique_chars('abcde') 12 | True 13 | >>> find_if_unique_chars('abcae') 14 | False 15 | """ 16 | 17 | unique = True 18 | 19 | counter = collections.Counter() 20 | 21 | for c in word: 22 | if not counter[c]: 23 | counter[c] += 1 24 | else: 25 | unique = False 26 | 27 | return unique 28 | 29 | 30 | if __name__ == "__main__": 31 | import doctest 32 | doctest.testmod() -------------------------------------------------------------------------------- /source_code/builtin_structures/find_largest_sum.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | 7 | """ 8 | You are given an array of integers (both positive and negative). 9 | Find the contiguous sequence with the largest sum. 10 | """ 11 | 12 | 13 | def find_largest_sum(array): 14 | """ 15 | >>> find_largest_sum([-1, 2, -3, 5, 3, 1, -16, 7, 1, -13, 1]) 16 | 9 17 | >>> find_largest_sum([]) 18 | 0 19 | >>> find_largest_sum([1]) 20 | 1 21 | """ 22 | 23 | sum_ = 0 24 | sum_here = 0 25 | 26 | for i in array: 27 | 28 | sum_here += i 29 | 30 | if sum_here < 0: 31 | sum_here = 0 32 | 33 | if sum_ < sum_here: 34 | sum_ = sum_here 35 | 36 | return sum_ 37 | 38 | 39 | 40 | if __name__ == "__main__": 41 | import doctest 42 | doctest.testmod() -------------------------------------------------------------------------------- /source_code/builtin_structures/find_longest_inc_subseq.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ find the longest continuous increasing subsequence""" 6 | 7 | 8 | def find_long_con_inc(seq): 9 | """ 10 | >>> find_long_con_inc([1, -2, 3, 5, 1, -1, 4, -1, 6]) 11 | [-2, 3, 5] 12 | >>> find_long_con_inc([1, 3, -2, 3, 5, 6]) 13 | [-2, 3, 5, 6] 14 | >>> find_long_con_inc([1, 3, 4, -13, 2, 5, 8, -1, 2,-17]) 15 | [-13, 2, 5, 8] 16 | """ 17 | 18 | res, aux = [], [] 19 | seq.append(-float('infinity')) 20 | 21 | for i, n in enumerate(seq[:-1]): 22 | aux.append(n) 23 | if n > seq[i+1]: 24 | if len(res) < len(aux): 25 | res = aux[:] 26 | aux = [] 27 | 28 | return res 29 | 30 | 31 | 32 | if __name__ == "__main__": 33 | import doctest 34 | doctest.testmod() 35 | -------------------------------------------------------------------------------- /source_code/builtin_structures/find_longest_str_unique_chars.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ 7 | given a string, find longest string with unique characters 8 | """ 9 | 10 | def find_longest(string): 11 | """ 12 | >>> find_longest('abfgrhgtrdsandwejfhdasjcbdsjvrejwghireeej') 13 | 'wejfhdas' 14 | >>> find_longest('abcabcabcabcdefabcccc') 15 | 'defabc' 16 | """ 17 | maxs = '' 18 | result = '' 19 | 20 | for c in string: 21 | if c in result: 22 | if len(maxs) < len(result): 23 | maxs = result 24 | result = '' 25 | else: 26 | result += c 27 | 28 | if result and len(maxs) < len(result): 29 | maxs = result 30 | 31 | return maxs 32 | 33 | 34 | 35 | if __name__ == "__main__": 36 | import doctest 37 | doctest.testmod() 38 | 39 | -------------------------------------------------------------------------------- /source_code/builtin_structures/find_non_repeating_number.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | from collections import defaultdict 7 | 8 | 9 | def find_unique_number(array): 10 | """ 11 | >>> find_unique_number([1, 3, 6, 1, 5, 6, 9, 3, 7]) 12 | [1, 6, 3] 13 | >>> find_unique_number([1, 3, 5, 6, 9, 7]) 14 | [] 15 | """ 16 | 17 | table = defaultdict() 18 | total = [] 19 | 20 | for i in array: 21 | if i in table: 22 | total.append(i) 23 | else: 24 | table[i] = 1 25 | 26 | return total 27 | 28 | 29 | 30 | 31 | if __name__ == "__main__": 32 | import doctest 33 | doctest.testmod() -------------------------------------------------------------------------------- /source_code/builtin_structures/find_product_without_division.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """Given an array of numbers, replace each number with the product of all 6 | the numbers in the array except the number itself *without* using division 7 | """ 8 | 9 | 10 | def find_product_without_division(seq): 11 | """ 12 | >>> seq = [2,3,4] 13 | >>> find_product_without_division(seq) 14 | [12, 8, 6] 15 | """ 16 | 17 | forw = [] 18 | bacw = [] 19 | 20 | for i in range(len(seq)): 21 | 22 | prod_f, prod_b = 1, 1 23 | 24 | for next in range(i+1, len(seq)): 25 | prod_f *= seq[next] 26 | 27 | for before in range(0, i): 28 | prod_b *= seq[before] 29 | 30 | forw.append(prod_f) 31 | bacw.append(prod_b) 32 | 33 | for i in range(len(seq)): 34 | seq[i] = forw[i] * bacw[i] 35 | 36 | return seq 37 | 38 | 39 | 40 | if __name__ == "__main__": 41 | import doctest 42 | doctest.testmod() -------------------------------------------------------------------------------- /source_code/builtin_structures/find_top_N_recurring_words.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | from collections import Counter 6 | 7 | def find_top_N_recurring_words(seq, N): 8 | """ find the top N recurring words in a file: 9 | 1) use a hash table to find counts 10 | 2) sort the list on base of the maximum counts 11 | 3) return the last N words 12 | """ 13 | 14 | dcounter = Counter() 15 | for word in seq.split(): 16 | dcounter[word] += 1 17 | 18 | return dcounter.most_common(N) 19 | 20 | 21 | 22 | if __name__ == "__main__": 23 | seq = 'buffy angel monster xander a willow gg buffy the monster super buffy angel' 24 | N = 3 25 | assert(find_top_N_recurring_words(seq, N) == [('buffy', 3), ('monster', 2), ('angel', 2)]) 26 | 27 | 28 | -------------------------------------------------------------------------------- /source_code/builtin_structures/get_float_rep_bin.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ Given a real number between 0 and 1 (eg: 0.72), this method print the 7 | binary representation. If the Number cannot be represented accurately 8 | in binary, with at exit most 32 chars, print error: 9 | """ 10 | 11 | def get_float_rep(num): 12 | if num >= 1 or num <= 0: return 'Error 1' 13 | result = '.' 14 | while num: 15 | if len(result) >= 32: return 'Error 2', result 16 | r = num*2 17 | if r >= 1: 18 | result += '1' 19 | num = r - 1 20 | else: 21 | result += '0' 22 | num = r 23 | return result 24 | 25 | 26 | if __name__ == "__main__": 27 | print get_float_rep(0.72) #('Error 2', '.1011100001010001111010111000010') 28 | print get_float_rep(0.1) # ('Error 2', '.0001100110011001100110011001100') 29 | print get_float_rep(0.5) #'.1' 30 | -------------------------------------------------------------------------------- /source_code/builtin_structures/max_subarray_stocks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | 7 | def beating_stock(array): 8 | 9 | imin = 0 10 | 11 | # first deal is just buying in the next day (1) 12 | deal = [array[1] - array[imin], imin, 1] 13 | 14 | for i, d in enumerate(array): 15 | 16 | deal_here = d - array[imin] 17 | 18 | if deal_here > deal[0]: 19 | deal = [deal_here, imin, i] 20 | 21 | elif d < array[imin]: 22 | imin = i 23 | 24 | return deal[0], array[deal[1]], array[deal[2]] 25 | 26 | 27 | def beating_stock2(array): 28 | 29 | deal = 0 30 | min_value = array[0] 31 | 32 | for i, d in enumerate(array): 33 | 34 | deal_here = d - min_value 35 | 36 | if deal_here > deal: 37 | deal = deal_here 38 | 39 | else: 40 | if min_value > array[i]: 41 | min_value = array[i] 42 | 43 | return deal 44 | 45 | 46 | 47 | if __name__ == "__main__": 48 | array = [7, 2, 3, 6, 5, 8, 5, 3, 4] 49 | 50 | deal = beating_stock(array) 51 | print("Profit: %d, buying at %d, selling at %d." %(deal[0], deal[1], deal[2])) 52 | 53 | deal = beating_stock2(array) 54 | print "Profit: " + str(deal) -------------------------------------------------------------------------------- /source_code/builtin_structures/number_of_zeros_factorial.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | 7 | How to know how many 0 are in 100! 8 | 9 | You look for the primes that multiply to 10, i.e. 2 and 5. 10 | 11 | There are more 5 than 2s so you can count the fives. 12 | 13 | there is 100/5 = 20, so 20 5s. However, there are two 5s in 25, 50, 75 and 100. 14 | 15 | result: 20+4 = 24 -------------------------------------------------------------------------------- /source_code/builtin_structures/palindrome.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | from collections import defaultdict 7 | 8 | 9 | def is_palindrome(array): 10 | """ 11 | >>> is_palindrome('subi no onibus') 12 | True 13 | >>> is_palindrome('helllo there') 14 | False 15 | >>> is_palindrome('h') 16 | True 17 | >>> is_palindrome('') 18 | True 19 | """ 20 | array = array.strip(" ") 21 | if len(array) < 2: 22 | return True 23 | 24 | if array[0] == array[-1]: 25 | return is_palindrome(array[1:-1]) 26 | else: 27 | return False 28 | 29 | 30 | if __name__ == "__main__": 31 | import doctest 32 | doctest.testmod() 33 | -------------------------------------------------------------------------------- /source_code/builtin_structures/permutations_alphanumeric.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ Write code to generate all possible case permutations of a given 7 | lower-cased string 8 | """ 9 | 10 | def alpha_permutation(string): 11 | """ 12 | >>> alpha_permutation('0ab') 13 | ['0Ab', '0Ab', '0ab', '0ab', '0Ba', '0Ba', '0ba', '0ba', 'ab0', 'a0b', 'a0b', 'b0a', 'b0a', 'ba0'] 14 | >>> alpha_permutation('') 15 | '' 16 | """ 17 | 18 | if len(string) < 2: 19 | return string 20 | 21 | result = [] 22 | 23 | for i, c in enumerate(string): 24 | rest = string[i+1:] + string[:i] 25 | for cc in alpha_permutation(rest): 26 | if cc.isalpha(): 27 | result.append(c.upper() + cc) 28 | result.append(c + cc) 29 | 30 | return result 31 | 32 | 33 | 34 | if __name__ == "__main__": 35 | import doctest 36 | doctest.testmod() 37 | 38 | -------------------------------------------------------------------------------- /source_code/builtin_structures/primes.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ 7 | find prime factors of a number. 8 | """ 9 | 10 | import math 11 | import random 12 | 13 | def find_prime_factors(n): 14 | """ 15 | >>> find_prime_factors(14) 16 | [2, 7] 17 | >>> find_prime_factors(19) 18 | [] 19 | """ 20 | 21 | divisors = [d for d in range(2, n//2 + 1) if n % d == 0] 22 | primes = [d for d in divisors if is_prime(d)] 23 | 24 | return primes 25 | 26 | 27 | def is_prime(n): 28 | for j in range(2, int(math.sqrt(n))): 29 | if (n % j) == 0: 30 | return False 31 | return True 32 | 33 | 34 | """ return a n-bit prime """ 35 | def generate_prime(number=3): 36 | while 1: 37 | p = random.randint(pow(2, number-2), pow(2, number-1)-1) 38 | p = 2 * p + 1 39 | if find_prime_factors(p): 40 | return p 41 | 42 | 43 | 44 | if __name__ == "__main__": 45 | import doctest 46 | doctest.testmod() 47 | 48 | -------------------------------------------------------------------------------- /source_code/builtin_structures/prod_other_ints.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def get_products_of_all_except_at_index(array): 7 | """ 8 | >>> a = [1, 7, 3, 4] 9 | >>> get_products_of_all_except_at_index(a) 10 | [84, 12, 28, 21] 11 | """ 12 | total = 1 13 | for n in array: 14 | total *= n 15 | 16 | new_array = [] 17 | for n in array: 18 | if n is not 0: 19 | item = total/n 20 | new_array.append(item) 21 | else: 22 | new_array.append(n) 23 | 24 | return new_array 25 | 26 | if __name__ == "__main__": 27 | import doctest 28 | doctest.testmod() -------------------------------------------------------------------------------- /source_code/builtin_structures/ransom_note.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | 7 | from collections import Counter 8 | 9 | def check_if_ransom_note(magazines, note): 10 | count = Counter() 11 | pm, pn = 0, 0 12 | 13 | while pn < len(note) and pm < len(magazines): 14 | char_note = note[pn] 15 | if count[char_note]>0: 16 | count[char_note] -= 1 17 | pn += 1 18 | else: 19 | char_magazine = magazines[pm] 20 | count[char_magazine] += 1 21 | pm +=1 22 | 23 | return pn == len(note) 24 | 25 | 26 | 27 | if __name__ == "__main__": 28 | 29 | magazines1 = "avfegthhgrebvkdsvnijnvyijfdmckdsmovkmmfvskumvl;cdkmioswckofjbkreenyukjemjgnmkmvkmnvdkmvkr g gmvdvmldm vldfkmbldkmlvdkm" 30 | magazines2 = "adfsfa" 31 | note = "you should disobey" 32 | 33 | print(check_if_ransom_note(magazines1, note)) 34 | print(check_if_ransom_note(magazines2, note)) 35 | -------------------------------------------------------------------------------- /source_code/builtin_structures/reverse_string.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def revert(string): 7 | """ 8 | >>> s = 'hello' 9 | >>> revert(s) 10 | 'olleh' 11 | >>> revert('') 12 | '' 13 | """ 14 | return string[::-1] 15 | 16 | 17 | 18 | def reverse_string_inplace(s): 19 | """ 20 | >>> s = 'hello' 21 | >>> reverse_string_inplace(s) 22 | 'olleh' 23 | >>> reverse_string_inplace('') 24 | '' 25 | """ 26 | if s: 27 | s = s[-1] + reverse_string_inplace(s[:-1]) 28 | return s 29 | 30 | 31 | 32 | 33 | 34 | 35 | if __name__ == "__main__": 36 | import doctest 37 | doctest.testmod() -------------------------------------------------------------------------------- /source_code/builtin_structures/reverse_words.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def reversing_words(word): 7 | """ 8 | >>> reversing_words('buffy is awesome') 9 | 'awesome is buffy' 10 | """ 11 | new_word = [] 12 | 13 | words = word.split(" ") 14 | for word in words[::-1]: 15 | new_word.append(word) 16 | 17 | return " ".join(new_word) 18 | 19 | 20 | def reversing_words2(s): 21 | """ 22 | >>> reversing_words2('buffy is awesome') 23 | 'awesome is buffy' 24 | """ 25 | words = s.split() 26 | return " ".join(reversed(words)) 27 | 28 | 29 | def reversing_words3(s): 30 | """ 31 | >>> reversing_words('buffy is awesome') 32 | 'awesome is buffy' 33 | """ 34 | words = s.split(" ") 35 | words.reverse() 36 | return " ".join(words) 37 | 38 | 39 | if __name__ == "__main__": 40 | import doctest 41 | doctest.testmod() 42 | -------------------------------------------------------------------------------- /source_code/builtin_structures/rotate_NxN.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | def rotate_NxN(m): 6 | n = len(m) 7 | for layer in range(n//2): 8 | first = layer 9 | last = n - 1 - layer 10 | for i in range(first, last): 11 | offset = i - first 12 | top = m[first][i] 13 | m[first][i] = m[last-offset][first] 14 | m[last-offset][first] = m[last][last-offset] 15 | m[last][last-offset] = m[i][last] 16 | m[i][last] = top 17 | return m 18 | 19 | 20 | 21 | def main(): 22 | m = [[1,2],[3,4]] 23 | mr = [[3,1],[4,2]] 24 | assert(rotate_NxN(m) == mr) 25 | m2 = [[1,2,3],[4,5,6],[7,8,9]] 26 | print(rotate_NxN(m2)) 27 | 28 | if __name__ == "__main__": 29 | main() 30 | 31 | -------------------------------------------------------------------------------- /source_code/builtin_structures/search_entry_matrix.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ Search an Entry in a Matrix where the Rows and columns are Sorted 7 | In this 2D matrix, every row is increasingly sorted from left to right, 8 | and every column is increasingly sorted from top to bottom. 9 | The runtime is O(m+n). 10 | """ 11 | 12 | def find_elem_matrix_bool(m1, value): 13 | 14 | found = False 15 | row = 0 16 | col = len(m1[0]) - 1 17 | 18 | while row < len(m1) and col >= 0: 19 | 20 | if m1[row][col] == value: 21 | found = True 22 | break 23 | elif m1[row][col] > value: 24 | col-=1 25 | else: 26 | row+=1 27 | 28 | return found 29 | 30 | 31 | 32 | def test_find_elem_matrix_bool(module_name='this module'): 33 | m1 = [[1,2,8,9], [2,4,9,12], [4,7,10,13], [6,8,11,15]] 34 | assert(find_elem_matrix_bool(m1,8) == True) 35 | assert(find_elem_matrix_bool(m1,3) == False) 36 | m2 = [[0]] 37 | assert(find_elem_matrix_bool(m2,0) == True) 38 | 39 | 40 | if __name__ == "__main__": 41 | test_find_elem_matrix_bool() 42 | 43 | -------------------------------------------------------------------------------- /source_code/builtin_structures/simple_str_comprension.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | from collections import Counter 7 | 8 | def str_comp(s): 9 | """ 10 | >>> s1 = 'aabcccccaaa' 11 | >>> str_comp(s1) 12 | 'a2b1c5a3' 13 | >>> str_comp('') 14 | '' 15 | """ 16 | 17 | count, last = 1, '' 18 | list_aux = [] 19 | for i, c in enumerate(s): 20 | if last == c: 21 | count += 1 22 | else: 23 | if i != 0: 24 | list_aux.append(str(count)) 25 | list_aux.append(c) 26 | count = 1 27 | last = c 28 | list_aux.append(str(count)) 29 | return ''.join(list_aux) 30 | 31 | 32 | if __name__ == "__main__": 33 | import doctest 34 | doctest.testmod() 35 | -------------------------------------------------------------------------------- /source_code/builtin_structures/sum_two_numbers_as_strings.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ 7 | find the sum of two integers represented as strings, 8 | return the sum as string, i.e "123" and "456" would return "579" 9 | """ 10 | 11 | 12 | def get_number(s): 13 | count = 1 14 | num = 0 15 | p = len(s) -1 16 | while p >= 0: 17 | num = num + int(s[p])*count 18 | count *= 10 19 | p -= 1 20 | return num 21 | 22 | 23 | def sum_string(s1, s2): 24 | """ 25 | >>> sum_string('10', '5') 26 | '15' 27 | >>> sum_string('0', '1') 28 | '1' 29 | >>> sum_string('123', '456') 30 | '579' 31 | """ 32 | 33 | n1 = get_number(s1) 34 | n2 = get_number(s2) 35 | return str(n2 + n1) 36 | 37 | 38 | if __name__ == "__main__": 39 | import doctest 40 | doctest.testmod() 41 | 42 | -------------------------------------------------------------------------------- /source_code/searching_and_sorting/searching/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/c143f4248734b86f0b1783b6759ba8b9dbebf685/source_code/searching_and_sorting/searching/__init__.py -------------------------------------------------------------------------------- /source_code/searching_and_sorting/searching/find_max_unimodal_array.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | def find_max_unimodal_array(A): 6 | if len(A) <= 2 : 7 | return None 8 | left = 0 9 | right = len(A)-1 10 | 11 | while right > left +1: 12 | 13 | mid = (left + right)//2 14 | if A[mid] > A[mid-1] and A[mid] > A[mid+1]: 15 | return A[mid] 16 | elif A[mid] > A[mid-1] and A[mid] < A[mid+1]: 17 | left = mid 18 | else: 19 | right = mid 20 | 21 | return None 22 | 23 | 24 | def test_find_max_unimodal_array(): 25 | seq = [1, 2, 5, 6, 7, 10, 12, 9, 8, 7, 6] 26 | assert(find_max_unimodal_array(seq) == 12) 27 | print('Tests passed!') 28 | 29 | 30 | if __name__ == "__main__": 31 | test_find_max_unimodal_array() 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /source_code/searching_and_sorting/searching/find_sqrt_bin_search.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ implement square root using binary search """ 6 | 7 | 8 | def find_sqrt_bin_search(n, error=0.001): 9 | lower = n < 1 and n or 1 10 | upper = n < 1 and 1 or n 11 | mid = lower + (upper - lower) / 2.0 12 | square = mid * mid 13 | while abs(square - n) > error: 14 | if square < n: 15 | lower = mid 16 | else: 17 | upper = mid 18 | mid = lower + (upper - lower) / 2.0 19 | square = mid * mid 20 | return mid 21 | 22 | 23 | def test_ind_sqrt_bin_search(): 24 | number = 9 25 | assert(find_sqrt_bin_search(number) == 3) 26 | print('Tests passed!') 27 | 28 | 29 | if __name__ == "__main__": 30 | test_ind_sqrt_bin_search() 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /source_code/searching_and_sorting/searching/ordered_sequential_search.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | 7 | def ordered_sequential_search(seq, n): 8 | """ an example of sequential search in an ordered seq: 9 | it improves the performance if the item is not present """ 10 | item = 0 11 | for item in seq: 12 | if item > n: return False 13 | if item == n: return True 14 | return False 15 | 16 | 17 | def test_ordered_sequential_search(module_name='this module'): 18 | seq = [1, 2, 4, 5, 6, 8, 10] 19 | n1 = 10 20 | n2 = 7 21 | assert(ordered_sequential_search(seq, n1) == True) 22 | assert(ordered_sequential_search(seq, n2) == False) 23 | 24 | s = 'Tests in {name} have {con}!' 25 | print(s.format(name=module_name, con='passed')) 26 | 27 | 28 | if __name__ == "__main__": 29 | test_ordered_sequential_search() 30 | 31 | 32 | """ 33 | Case Best Case Worst Case Average Case 34 | item is present 1 n n/2 35 | item not present 1 n n/2 36 | """ 37 | -------------------------------------------------------------------------------- /source_code/searching_and_sorting/searching/sequential_search.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def sequential_search(seq, n): 7 | """ an example of sequential search (for items stored in a collection) """ 8 | for item in seq: 9 | if item == n: return True 10 | return False 11 | 12 | 13 | def test_sequential_search(module_name='this module'): 14 | seq = [1, 5, 6, 8, 3] 15 | n1 = 5 16 | n2 = 7 17 | assert(sequential_search(seq, n1) == True) 18 | assert(sequential_search(seq, n2) == False) 19 | 20 | s = 'Tests in {name} have {con}!' 21 | print(s.format(name=module_name, con='passed')) 22 | 23 | 24 | if __name__ == "__main__": 25 | test_sequential_search() 26 | 27 | 28 | """ 29 | Case Best Case Worst Case Average Case 30 | item is present 1 n n2 31 | item is not present n n n 32 | """ -------------------------------------------------------------------------------- /source_code/searching_and_sorting/sorting/1.dat: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 5 6 | -------------------------------------------------------------------------------- /source_code/searching_and_sorting/sorting/2.dat: -------------------------------------------------------------------------------- 1 | 3 2 | 5 3 | 6 4 | 7 5 | -------------------------------------------------------------------------------- /source_code/searching_and_sorting/sorting/3.dat: -------------------------------------------------------------------------------- 1 | 1 2 | 3 3 | 5 4 | 8 5 | -------------------------------------------------------------------------------- /source_code/searching_and_sorting/sorting/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/c143f4248734b86f0b1783b6759ba8b9dbebf685/source_code/searching_and_sorting/sorting/__init__.py -------------------------------------------------------------------------------- /source_code/searching_and_sorting/sorting/bubble_sort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def bubble_sort(seq): 7 | """ 8 | Implementation of bubble sort. 9 | O(n2) and thus highly ineffective. 10 | """ 11 | size = len(seq) -1 12 | for num in range(size, 0, -1): 13 | for i in range(num): 14 | if seq[i] > seq[i+1]: 15 | temp = seq[i] 16 | seq[i] = seq[i+1] 17 | seq[i+1] = temp 18 | return seq 19 | 20 | 21 | def test_bubble_sort(module_name='this module'): 22 | seq = [4, 5, 2, 1, 6, 2, 7, 10, 13, 8] 23 | assert(bubble_sort(seq) == sorted(seq)) 24 | 25 | 26 | if __name__ == "__main__": 27 | test_bubble_sort() 28 | 29 | -------------------------------------------------------------------------------- /source_code/searching_and_sorting/sorting/count_sort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | 7 | from collections import defaultdict 8 | 9 | def count_sort_dict(a): 10 | """ an example of counting sort using default dictionaries """ 11 | b, c = [], defaultdict(list) 12 | for x in a: 13 | c[x].append(x) # we could have used key = lambda x:x 14 | for k in range(min(c), max(c) + 1): 15 | b.extend(c[k]) 16 | return b 17 | 18 | 19 | def test_count_sort(): 20 | seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2, 5, 4, 1, 5, 3] 21 | assert(count_sort_dict(seq) == sorted(seq)) 22 | 23 | 24 | if __name__ == "__main__": 25 | test_count_sort() 26 | 27 | 28 | -------------------------------------------------------------------------------- /source_code/searching_and_sorting/sorting/gnome_sort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def gnome_sort(seq): 7 | """ sort a sequence using the gnome sort alg """ 8 | i = 0 9 | while i < len(seq): 10 | if i ==0 or seq[i-1] <= seq[i]: 11 | i += 1 12 | else: 13 | seq[i], seq[i-1] = seq[i-1], seq[i] 14 | i -= 1 15 | return seq 16 | 17 | 18 | def test_gnome_sort(): 19 | seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2, 5, 4, 1, 5, 3] 20 | assert(gnome_sort(seq) == sorted(seq)) 21 | 22 | 23 | if __name__ == "__main__": 24 | test_gnome_sort() 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /source_code/searching_and_sorting/sorting/heap.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | class Heap(object): 7 | def __init__(self, data): 8 | self.data = data 9 | for i in range(len(data)/2, -1, -1): 10 | self.__max_heapify__(i) 11 | 12 | 13 | def parent(self, i): 14 | return i >> 1 15 | 16 | 17 | def left_child(self, i): 18 | return (i << 1) + 1 19 | 20 | 21 | def right_child(self, i): 22 | return (i << 1) + 2 # +2 instead of +1 because it's 0-indexed. 23 | 24 | 25 | def __max_heapify__(self, i): 26 | largest = i 27 | left = self.left_child(i) 28 | right = self.right_child(i) 29 | n = len(self.data) 30 | largest = (left < n and self.data[left] > self.data[i]) and left or i 31 | largest = (right < n and self.data[right] > self.data[largest]) and right or largest 32 | if i != largest: 33 | self.data[i], self.data[largest] = self.data[largest], self.data[i] 34 | self.__max_heapify__(largest) 35 | 36 | 37 | def extract_max(self): 38 | n = len(self.data) 39 | max_element = self.data[0] 40 | self.data[0] = self.data[n - 1] 41 | self.data = self.data[:n - 1] 42 | self.__max_heapify__(0) 43 | return max_element 44 | 45 | 46 | -------------------------------------------------------------------------------- /source_code/searching_and_sorting/sorting/insertion_sort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | 7 | 8 | def insertion_sort(seq): 9 | """ sort a sequence using the insertion sort alg """ 10 | for i in range(1, len(seq)): 11 | j = i 12 | while j > 0 and seq[j-1] > seq[j]: 13 | seq[j-1], seq[j] = seq[j], seq[j-1] 14 | j -= 1 15 | return seq 16 | 17 | 18 | def insertion_sort_rec(seq, i = None): 19 | """ sort a sequence using the recursive insertion sort alg """ 20 | if i == None: i = len(seq) -1 21 | if i == 0: return i 22 | insertion_sort_rec(seq, i-1) 23 | j = i 24 | while j > 0 and seq[j-i] > seq[j]: 25 | seq[j-1], seq[j] = seq[j], seq[j-1] 26 | j -= 1 27 | return seq 28 | 29 | 30 | def test_insertion_sort(): 31 | seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2, 5, 4, 1, 5, 3] 32 | assert(insertion_sort(seq) == sorted(seq)) 33 | assert(insertion_sort_rec(seq) == sorted(seq)) 34 | 35 | 36 | if __name__ == "__main__": 37 | test_insertion_sort() 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /source_code/searching_and_sorting/sorting/merge_and_sort_two_arrays.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | """ 6 | You have two arrays with N integers in them. Merge those arrays using a 7 | recursive algorithm so that the integers in the final array are sorted. 8 | """ 9 | 10 | def merge_arrays(a1, a2): 11 | """ 12 | >>> merge_arrays([5, 4, 3], [6, 2, 9]) 13 | [2, 3, 4, 5, 6, 9] 14 | >>> merge_arrays([2, 6], [6, 2]) 15 | [2, 2, 6, 6] 16 | >>> merge_arrays([], []) 17 | [] 18 | """ 19 | # if they are not sorted yet 20 | a1.sort() 21 | a2.sort() 22 | 23 | merge = [] 24 | p1, p2 = 0, 0 25 | 26 | while p1 < len(a1) and p2 < len(a2): 27 | if a1[p1] <= a2[p2]: 28 | merge.append(a1[p1]) 29 | p1 += 1 30 | else: 31 | merge.append(a2[p2]) 32 | p2 +=1 33 | 34 | if a1[p1:]: 35 | merge.extend(a1[p1:]) 36 | 37 | if a2[p2:]: 38 | merge.extend(a2[p2:]) 39 | 40 | return merge 41 | 42 | 43 | if __name__ == "__main__": 44 | import doctest 45 | doctest.testmod() 46 | 47 | -------------------------------------------------------------------------------- /source_code/searching_and_sorting/sorting/merge_sort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def merge_sort(array): 7 | """ 8 | >>> merge_sort([3 ,5, 1, 2, 10, 6]) 9 | [1, 2, 3, 5, 6, 10] 10 | """ 11 | if len(array) < 2: 12 | return array 13 | 14 | mid = len(array)//2 15 | left = merge_sort(array[:mid]) 16 | right = merge_sort(array[mid:]) 17 | 18 | res = [] 19 | i, j = 0, 0 20 | while i < len(left) and j < len(right): 21 | if left[i] <= right[j]: 22 | res.append(left[i]) 23 | i += 1 24 | else: 25 | res.append(right[j]) 26 | j += 1 27 | 28 | if left[i:]: 29 | res.extend(left[i:]) 30 | if right[j:]: 31 | res.extend(right[j:]) 32 | return res 33 | 34 | 35 | 36 | """ Merge sort for files """ 37 | def merge_files(list_files): 38 | result = [] 39 | final = [] 40 | for filename in list_files: 41 | aux = [] 42 | with open(filename, 'r') as file: 43 | for line in file: 44 | aux.append(int(line)) 45 | result.append(aux) 46 | final.extend(result.pop()) 47 | for l in result: 48 | final = merge(l, final) 49 | return final 50 | 51 | 52 | if __name__ == "__main__": 53 | import doctest 54 | doctest.testmod() -------------------------------------------------------------------------------- /source_code/searching_and_sorting/sorting/quick_sort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def qs(array): 7 | """ 8 | >>> qs([4,1,6,2,7,9,3]) 9 | [1, 2, 3, 4, 6, 7, 9] 10 | """ 11 | if len(array) < 2: 12 | return array 13 | 14 | piv = len(array)//2 15 | piv_element = array[piv] 16 | new_array = array[:piv] + array[piv+1:] 17 | 18 | left = [a for a in new_array if a <= piv_element] 19 | right = [a for a in new_array if a > piv_element] 20 | 21 | return qs(left) + [array[piv]] + qs(right) 22 | 23 | 24 | 25 | # we can also divide them into two functions 26 | def partition(seq): 27 | pi,seq = seq[0],seq[1:] 28 | lo = [x for x in seq if x <= pi] 29 | hi = [x for x in seq if x > pi] 30 | return lo, pi, hi 31 | 32 | def quick_sort_divided(seq): 33 | """ 34 | >>> quick_sort_divided([4,1,6,2,7,9,3]) 35 | [1, 2, 3, 4, 6, 7, 9] 36 | """ 37 | if len(seq) < 2: 38 | return seq 39 | lo, pi, hi = partition(seq) 40 | return quick_sort_divided(lo) + [pi] + quick_sort_divided(hi) 41 | 42 | 43 | 44 | if __name__ == "__main__": 45 | import doctest 46 | doctest.testmod() -------------------------------------------------------------------------------- /source_code/searching_and_sorting/sorting/selection_sort.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | def selection_sort(seq): 7 | """ sort a sequence using the selection sort alg """ 8 | for i in range(len(seq) -1, 0, -1): 9 | max_j = i 10 | for j in range(max_j): 11 | if seq[j] > seq[max_j]: 12 | max_j = j 13 | seq[i], seq[max_j] = seq[max_j], seq[i] 14 | return seq 15 | 16 | 17 | def test_selection_sort(): 18 | seq = [3, 5, 2, 6, 8, 1, 0, 3, 5, 6, 2] 19 | assert(selection_sort(seq) == sorted(seq)) 20 | 21 | 22 | if __name__ == "__main__": 23 | test_selection_sort() 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /source_code/searching_and_sorting/sorting/sort_anagrams_together.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ A method to sort an array so that all the anagrams are together. 7 | Since we only want the anagrams to be grouped, we can use a 8 | dictionary for this task. This algorithm is O(n). 9 | """ 10 | 11 | from collections import defaultdict 12 | 13 | def sort_anagrams_together(l1): 14 | """ 15 | >>> l1 = ['hat', 'ball', 'tha', 'cut', 'labl', 'hta', 'cool', 'cuy', 'uct'] 16 | >>> sort_anagrams_together(l1) 17 | ['cuy', 'cut', 'uct', 'cool', 'ball', 'labl', 'hat', 'tha', 'hta'] 18 | """ 19 | result = [] 20 | 21 | dict_aux = defaultdict(list) 22 | for word in l1: 23 | key = ''.join(sorted(word)) 24 | dict_aux[key].append(word) 25 | 26 | for key in dict_aux: 27 | result.extend(dict_aux[key]) 28 | 29 | return result 30 | 31 | if __name__ == "__main__": 32 | import doctest 33 | doctest.testmod() 34 | 35 | -------------------------------------------------------------------------------- /source_code/trees/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AstinCHOI/Python-and-Algorithms-and-Data-Structures/c143f4248734b86f0b1783b6759ba8b9dbebf685/source_code/trees/__init__.py -------------------------------------------------------------------------------- /source_code/trees/bunchclass.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | class BunchClass(dict): 6 | def __init__(self, *args, **kwds): 7 | super(BunchClass, self).__init__(*args, **kwds) 8 | self.__dict__ = self 9 | 10 | 11 | def main(): 12 | """ {'right': {'right': 'Xander', 'left': 'Willow'}, 'left': {'right': 'Angel', 'left': 'Buffy'}}""" 13 | bc = BunchClass # notice the absence of () 14 | tree = bc(left = bc(left="Buffy", right="Angel"), right = bc(left="Willow", right="Xander")) 15 | print(tree) 16 | 17 | if __name__ == "__main__": 18 | main() 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /source_code/trees/check_if_balanced.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | from binary_search_tree import BST, Node 6 | from binary_tree import BT, Node 7 | 8 | 9 | 10 | def isBalanced(node, left=0, right=0): 11 | if not node: 12 | return (left - right) < 2 13 | 14 | return isBalanced(node.left, left+1, right) and \ 15 | isBalanced(node.right, left, right+1) 16 | 17 | 18 | 19 | 20 | if __name__ == "__main__": 21 | bt = BST() 22 | for i in range(1, 10): 23 | bt.add(i) 24 | 25 | assert(isBalanced(bt.root) == True) 26 | 27 | bt = BT() 28 | for i in range(1, 10): 29 | bt.add(i) 30 | 31 | assert(isBalanced(bt.root) == False) 32 | -------------------------------------------------------------------------------- /source_code/trees/check_largest_item.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | from binary_search_tree import BST, Node 7 | 8 | def largest(node): 9 | 10 | if node.right: 11 | return largest(node.right) 12 | return node.item 13 | 14 | 15 | if __name__ == "__main__": 16 | 17 | 18 | bst = BST() 19 | l = [10, 5, 6, 3, 8, 2, 1, 11, 9, 4] 20 | for i in l: 21 | bst.add(i) 22 | 23 | print(largest(bst.root)) 24 | -------------------------------------------------------------------------------- /source_code/trees/simple_tree.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = "bt3" 4 | 5 | 6 | """ A class for a simple tree """ 7 | 8 | class SimpleTree(object): 9 | 10 | def __init__(self, value=None, children = None): 11 | self.value = value 12 | self.children = children 13 | if self.children == None: 14 | self.children = [] 15 | 16 | def __repr__(self, level=0): 17 | ret = "\t"*level+repr(self.value)+"\n" 18 | for child in self.children: 19 | ret += child.__repr__(level+1) 20 | return ret 21 | 22 | 23 | 24 | def main(): 25 | """ 26 | 'a' 27 | 'b' 28 | 'd' 29 | 'e' 30 | 'c' 31 | 'h' 32 | 'g' 33 | """ 34 | st = SimpleTree('a', [SimpleTree('b', [SimpleTree('d'), SimpleTree('e')] ), SimpleTree('c', [SimpleTree('h'), SimpleTree('g')]) ]) 35 | print(st) 36 | 37 | 38 | if __name__ == "__main__": 39 | main() 40 | 41 | 42 | --------------------------------------------------------------------------------