Repository: keon/algorithms
Pull request #435 (2018-10-26 22:34:07)

Add k closest points to origin
(Put an `X` inside the `[ ]` to denote check mark `[X]`.)


- [x] **If creating a new file :**
  - [x] added links to it in the README files ?
  - [x] included tests with it ?
  - [x] added description (overview of algorithm, time and space compleixty, and possible edge case) in docstrings ?

- [ ] **if done some changes :**
  - [ ] wrote short description in the PR explaining what the changes do ?
  - [ ] Fixes #[issue number] if related to any issue

- [ ] **other**



Patch:
diff --git a/CONTRIBUTING_ES.md b/CONTRIBUTING_ES.md
new file mode 100644
index 0000000..578b1d4
--- /dev/null
+++ b/CONTRIBUTING_ES.md
@@ -0,0 +1,62 @@
+# Contribuyendo
+
+Nos encantan los pull requests de todos. Al contribuir a este repositorio, usted acepta cumplir con el [Código de Conducta](CODE_OF_CONDUCT.md).
+
+## Comenzando
+
+* Primero haga un [fork][fork] del repositorio y luego clónelo usando:
+
+    git clone git@github.com:your-username/algorithms.git  
+
+* Después de eso, crea una git branch para tus cambios. Por ejemplo:  
+  * add_XXX Si agregara nuevos algoritmos o estructuras de datos.  
+  * fix_XXX Si arreglará un error en un determinado algoritmo o estructura de datos.  
+  * test_XXX Si escribiste una o más pruebas.  
+  * doc_XXX Si ha editado o añadido a la documentación.
+
+Usted puede contribuir:
+- Implementando nuevos algoritmos en el repositorio. Asegúrese de ponerlo en la sección correcta (ej. [array](array), [dp](dp), etc). Cree una nueva sección para él si no cae en ninguna. Asegúrese de que su implementación funciona.  
+- Optimizando o mejorando los algoritmos existentes.
+- Añadiendo una solución diferente para el problema.
+- Encontrando y corrigiendo errores.
+- Añadiendo ejemplos para explicar mejor los algoritmos.
+- Añadiendo casos de prueba.
+- Mejorando la documentación.
+
+## Pull Requests
+Haga push a su fork y [envie un pull request][pr].
+
+Revisaremos y sugeriremos algunos cambios, mejoras o alternativas. Algunas cosas que aumentarán la posibilidad de que su pull request sea aceptado:
+
+
+* Todos los algoritmos deben estar escritos en **Python 3**.
+(Hay algunos algoritmos todavía con la sintaxis de _Python 2_. Puede comenzar con la conversión de [aquellos][issue120] a _Python 3_.)
+* Escribir código limpio y comprensible.
+* Comente correctamente el código y explique brevemente qué está haciendo el algoritmo en los [docstrings][docstr].
+* También puede explicar la salida usando un ejemplo mínimo.
+* Trate de incluir también un par de casos de prueba para el algoritmo.
+* Escriba un [buen mensaje en el commit][commit].
+
+
+## Issues
+Envíe un [nuevo issue][newissue] si hay un algoritmo por agregar, o si se encontró un error en un algoritmo existente.  Antes de enviar un nuevo issue, revise lo [issues existentes][issues] para evitar crear duplicados. También, considere resolver problemas actuales o contribuir a la discusión sobre un tema.
+
+## Colaboradores
+Puedes pedir ayuda o aclaraciones a los colaboradores.
+[Keon Kim](https://github.com/keon)
+
+[Rahul Goswami](https://github.com/goswami-rahul)
+
+[Ankit Agarwal](https://github.com/ankit167)
+
+[Hai Hoang Dang](https://github.com/danghai)
+
+[Saad](https://github.com/SaadBenn)
+
+[fork]: https://help.github.com/articles/fork-a-repo/
+[docstr]: https://www.python.org/dev/peps/pep-0257/#multi-line-docstrings
+[commit]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
+[pr]: https://github.com/keon/algorithms/compare/
+[newissue]: https://github.com/keon/algorithms/issues/new
+[issue120]: https://github.com/keon/algorithms/issues/120
+[issues]: https://github.com/keon/algorithms/issues/
diff --git a/README.md b/README.md
index aecd53b..1d905d0 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 <p align="center"><img src="https://raw.githubusercontent.com/keon/algorithms/master/docs/source/_static/logo/logotype1blue.png"></p>
 
-English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md)
+English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md)
 
 [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms)
 [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms)
@@ -158,6 +158,7 @@ If you want to uninstall algorithms, it is as simple as:
     - [skyline](algorithms/heap/skyline.py)
     - [sliding_window_max](algorithms/heap/sliding_window_max.py)
     - [binary_heap](algorithms/heap/binary_heap.py)
+    - [k_closest_points](algorithms/heap/k_closest_points.py)
 - [linkedlist](algorithms/linkedlist)
     - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py)
     - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py)
@@ -203,6 +204,7 @@ If you want to uninstall algorithms, it is as simple as:
     - [rsa](algorithms/maths/rsa.py)
     - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py)
     - [summing_digits](algorithms/maths/summing_digits.py)
+    - [hailstone](algorithms/maths/hailstone.py)
 - [matrix](algorithms/matrix)
     - [sudoku_validator](algorithms/matrix/sudoku_validator.py)
     - [bomb_enemy](algorithms/matrix/bomb_enemy.py)
diff --git a/README_CN.md b/README_CN.md
index ee40545..aec110a 100644
--- a/README_CN.md
+++ b/README_CN.md
@@ -1,6 +1,6 @@
 <p align="center"><img src="https://raw.githubusercontent.com/keon/algorithms/master/docs/source/_static/logo/logotype1blue.png"></p>
 
-[English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md)
+[English](README.md) | 简体中文 | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md)
 
 [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms)
 [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms)
diff --git a/README_ES.md b/README_ES.md
new file mode 100644
index 0000000..cd6ee82
--- /dev/null
+++ b/README_ES.md
@@ -0,0 +1,376 @@
+<p align="center"><img src="https://raw.githubusercontent.com/keon/algorithms/master/docs/source/_static/logo/logotype1blue.png"></p>
+
+[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | Español
+
+[![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms)
+[![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms)
+[![Build Status](https://travis-ci.org/keon/algorithms.svg?branch=master)](https://travis-ci.org/keon/algorithms)
+[![Coverage Status](https://coveralls.io/repos/github/keon/algorithms/badge.svg?branch=master)](https://coveralls.io/github/keon/algorithms?branch=master)
+
+Estructuras de datos y algoritmos en Python
+=========================================
+
+Ejemplo de implementaciones mínimas y limpias de estructuras de datos y algoritmos en Python 3.
+
+## Contribuciones
+¡Gracias por su interés en contribuir! Hay muchas maneras de contribuir a este proyecto. [Comienza aquí](CONTRIBUTING_ES.md)
+
+## Pruebas
+
+### Usando unittest
+Escriba lo siguiente para ejecutar todas las pruebas:
+
+    $ python3 -m unittest discover tests
+
+Para ejecutar pruebas en específico, puede hacerlo de la siguiente manera (Ej: sort):
+
+    $ python3 -m unittest tests.test_sort
+
+### Usando pytest
+Escriba lo siguiente para ejecutar todas las pruebas:
+
+    $ python3 -m pytest tests
+
+## Instalación
+Si desea utilizar el API algorithms en su código, es tan simple como:
+
+    $ pip3 install algorithms
+
+Puede probar creando un archivo python: (Ej: use `merge_sort` en `sort`)
+
+```python3
+from algorithms.sort import merge_sort
+
+if __name__ == "__main__":
+    my_list = [1, 8, 3, 5, 6]
+    my_list = merge_sort(my_list)
+    print(my_list)
+```
+
+## Desinstalación
+Si desea desinstalar algorithms, es tan simple como:
+
+    $ pip3 uninstall -y algorithms
+
+## Lista de immplementaciones
+
+- [arrays](algorithms/arrays)
+    - [delete_nth](algorithms/arrays/delete_nth.py)
+    - [flatten](algorithms/arrays/flatten.py)
+    - [garage](algorithms/arrays/garage.py)
+    - [josephus_problem](algorithms/arrays/josephus.py)
+    - [limit](algorithms/arrays/limit.py)
+    - [longest_non_repeat](algorithms/arrays/longest_non_repeat.py/)
+    - [max_ones_index](algorithms/arrays/max_ones_index.py)
+    - [merge_intervals](algorithms/arrays/merge_intervals.py)
+    - [missing_ranges](algorithms/arrays/missing_ranges.py)
+    - [plus_one](algorithms/arrays/plus_one.py)
+    - [rotate](algorithms/arrays/rotate.py)
+    - [summarize_ranges](algorithms/arrays/summarize_ranges.py)
+    - [three_sum](algorithms/arrays/three_sum.py)
+    - [trimmean](algorithms/arrays/trimmean.py)
+    - [top_1](algorithms/arrays/top_1.py)
+    - [two_sum](algorithms/arrays/two_sum.py)
+    - [move_zeros](algorithms/arrays/move_zeros.py)
+    - [n_sum](algorithms/arrays/n_sum.py)
+- [backtrack](algorithms/backtrack)
+    - [general_solution.md](algorithms/backtrack/)
+    - [add_operators](algorithms/backtrack/add_operators.py)
+    - [anagram](algorithms/backtrack/anagram.py)
+    - [array_sum_combinations](algorithms/backtrack/array_sum_combinations.py)
+    - [combination_sum](algorithms/backtrack/combination_sum.py)
+    - [factor_combinations](algorithms/backtrack/factor_combinations.py)
+    - [generate_abbreviations](algorithms/backtrack/generate_abbreviations.py)
+    - [generate_parenthesis](algorithms/backtrack/generate_parenthesis.py)
+    - [letter_combination](algorithms/backtrack/letter_combination.py)
+    - [palindrome_partitioning](algorithms/backtrack/palindrome_partitioning.py)
+    - [pattern_match](algorithms/backtrack/pattern_match.py)
+    - [permute](algorithms/backtrack/permute.py)
+    - [permute_unique](algorithms/backtrack/permute_unique.py)
+    - [subsets](algorithms/backtrack/subsets.py)
+    - [subsets_unique](algorithms/backtrack/subsets_unique.py)
+- [bfs](algorithms/bfs)
+    - [maze_search](algorithms/bfs/maze_search.py)
+    - [shortest_distance_from_all_buildings](algorithms/bfs/shortest_distance_from_all_buildings.py)
+    - [word_ladder](algorithms/bfs/word_ladder.py)
+- [bit](algorithms/bit)
+    - [add_bitwise_operator](algorithms/bit/add_bitwise_operator.py)
+    - [bit_operation](algorithms/bit/bit_operation.py)
+    - [bytes_int_conversion](algorithms/bit/bytes_int_conversion.py)
+    - [count_flips_to_convert](algorithms/bit/count_flips_to_convert.py)
+    - [count_ones](algorithms/bit/count_ones.py)
+    - [find_difference](algorithms/bit/find_difference.py)
+    - [find_missing_number](algorithms/bit/find_missing_number.py)
+    - [flip_bit_longest_sequence](algorithms/bit/flip_bit_longest_sequence.py)
+    - [power_of_two](algorithms/bit/power_of_two.py)
+    - [reverse_bits](algorithms/bit/reverse_bits.py)
+    - [single_number](algorithms/bit/single_number.py)
+    - [single_number2](algorithms/bit/single_number2.py)
+    - [single_number3](algorithms/bit/single_number3.py)
+    - [subsets](algorithms/bit/subsets.py)
+    - [swap_pair](algorithms/bit/swap_pair.py)
+    - [has_alternative_bit](algorithms/bit/has_alternative_bit.py)
+    - [insert_bit](algorithms/bit/insert_bit.py)
+    - [remove_bit](algorithms/bit/remove_bit.py)
+    - [binary_gap](algorithms/bit/binary_gap.py)
+- [calculator](algorithms/calculator)
+    - [math_parser](algorithms/calculator/math_parser.py)
+- [dfs](algorithms/dfs)
+    - [all_factors](algorithms/dfs/all_factors.py)
+    - [count_islands](algorithms/dfs/count_islands.py)
+    - [pacific_atlantic](algorithms/dfs/pacific_atlantic.py)
+    - [sudoku_solver](algorithms/dfs/sudoku_solver.py)
+    - [walls_and_gates](algorithms/dfs/walls_and_gates.py)
+- [dp](algorithms/dp)
+    - [buy_sell_stock](algorithms/dp/buy_sell_stock.py)
+    - [climbing_stairs](algorithms/dp/climbing_stairs.py)
+    - [coin_change](algorithms/dp/coin_change.py)
+    - [combination_sum](algorithms/dp/combination_sum.py)
+    - [egg_drop](algorithms/dp/egg_drop.py)
+    - [house_robber](algorithms/dp/house_robber.py)
+    - [job_scheduling](algorithms/dp/job_scheduling.py)
+    - [knapsack](algorithms/dp/knapsack.py)
+    - [longest_increasing](algorithms/dp/longest_increasing.py)
+    - [matrix_chain_order](algorithms/dp/matrix_chain_order.py)
+    - [max_product_subarray](algorithms/dp/max_product_subarray.py)
+    - [max_subarray](algorithms/dp/max_subarray.py)
+    - [min_cost_path](algorithms/dp/min_cost_path.py)
+    - [num_decodings](algorithms/dp/num_decodings.py)
+    - [regex_matching](algorithms/dp/regex_matching.py)
+    - [rod_cut](algorithms/dp/rod_cut.py)
+    - [word_break](algorithms/dp/word_break.py)
+    - [fibonacci](algorithms/dp/fib.py)
+- [graph](algorithms/graph)
+    - [check_bipartite](algorithms/graph/check_bipartite.py)
+    - [strongly_connected](algorithms/graph/check_digraph_strongly_connected.py)
+    - [clone_graph](algorithms/graph/clone_graph.py)
+    - [cycle_detection](algorithms/graph/cycle_detection.py)
+    - [find_all_cliques](algorithms/graph/find_all_cliques.py)
+    - [find_path](algorithms/graph/find_path.py)
+    - [graph](algorithms/graph/graph.py)
+    - [markov_chain](algorithms/graph/markov_chain.py)
+    - [minimum_spanning_tree](algorithms/graph/minimum_spanning_tree.py)
+    - [satisfiability](algorithms/graph/satisfiability.py)
+    - [tarjan](algorithms/graph/tarjan.py)
+    - [traversal](algorithms/graph/traversal.py)
+- [heap](algorithms/heap)
+    - [merge_sorted_k_lists](algorithms/heap/merge_sorted_k_lists.py)
+    - [skyline](algorithms/heap/skyline.py)
+    - [sliding_window_max](algorithms/heap/sliding_window_max.py)
+    - [binary_heap](algorithms/heap/binary_heap.py)
+- [linkedlist](algorithms/linkedlist)
+    - [add_two_numbers](algorithms/linkedlist/add_two_numbers.py)
+    - [copy_random_pointer](algorithms/linkedlist/copy_random_pointer.py)
+    - [delete_node](algorithms/linkedlist/delete_node.py)
+    - [first_cyclic_node](algorithms/linkedlist/first_cyclic_node.py)
+    - [is_cyclic](algorithms/linkedlist/is_cyclic.py)
+    - [is_palindrome](algorithms/linkedlist/is_palindrome.py)
+    - [kth_to_last](algorithms/linkedlist/kth_to_last.py)
+    - [linkedlist](algorithms/linkedlist/linkedlist.py)
+    - [remove_duplicates](algorithms/linkedlist/remove_duplicates.py)
+    - [reverse](algorithms/linkedlist/reverse.py)
+    - [rotate_list](algorithms/linkedlist/rotate_list.py)
+    - [swap_in_pairs](algorithms/linkedlist/swap_in_pairs.py)
+    - [is_sorted](algorithms/linkedlist/is_sorted.py)
+    - [remove_range](algorithms/linkedlist/remove_range.py)
+- [map](algorithms/map)
+    - [hashtable](algorithms/map/hashtable.py)
+    - [separate_chaining_hashtable](algorithms/map/separate_chaining_hashtable.py)
+    - [longest_common_subsequence](algorithms/map/longest_common_subsequence.py)
+    - [randomized_set](algorithms/map/randomized_set.py)
+    - [valid_sudoku](algorithms/map/valid_sudoku.py)
+    - [word_pattern](algorithms/map/word_pattern.py)
+    - [is_isomorphic](algorithms/map/is_isomorphic.py)
+    - [is_anagram](algorithms/map/is_anagram.py)    
+- [maths](algorithms/maths)
+    - [base_conversion](algorithms/maths/base_conversion.py)
+    - [combination](algorithms/maths/combination.py)
+    - [decimal_to_binary_ip](algorithms/maths/decimal_to_binary_ip.py)
+    - [euler_totient](algorithms/maths/euler_totient.py)
+    - [extended_gcd](algorithms/maths/extended_gcd.py)
+    - [factorial](algorithms/maths/factorial.py)    
+    - [gcd/lcm](algorithms/maths/gcd.py)
+    - [generate_strobogrammtic](algorithms/maths/generate_strobogrammtic.py)
+    - [is_strobogrammatic](algorithms/maths/is_strobogrammatic.py)
+    - [modular_exponential](algorithms/maths/modular_exponential.py)
+    - [next_bigger](algorithms/maths/next_bigger.py)
+    - [next_perfect_square](algorithms/maths/next_perfect_square.py)
+    - [nth_digit](algorithms/maths/nth_digit.py)
+    - [prime_check](algorithms/maths/prime_check.py)
+    - [primes_sieve_of_eratosthenes](algorithms/maths/primes_sieve_of_eratosthenes.py)
+    - [pythagoras](algorithms/maths/pythagoras.py)
+    - [rabin_miller](algorithms/maths/rabin_miller.py)
+    - [rsa](algorithms/maths/rsa.py)
+    - [sqrt_precision_factor](algorithms/maths/sqrt_precision_factor.py)
+    - [summing_digits](algorithms/maths/summing_digits.py)
+- [matrix](algorithms/matrix)
+    - [sudoku_validator](algorithms/matrix/sudoku_validator.py)
+    - [bomb_enemy](algorithms/matrix/bomb_enemy.py)
+    - [copy_transform](algorithms/matrix/copy_transform.py)
+    - [count_paths](algorithms/matrix/count_paths.py)
+    - [matrix_rotation.txt](algorithms/matrix/matrix_rotation.txt)
+    - [rotate_image](algorithms/matrix/rotate_image.py)
+    - [search_in_sorted_matrix](algorithms/matrix/search_in_sorted_matrix.py)
+    - [sparse_dot_vector](algorithms/matrix/sparse_dot_vector.py)
+    - [sparse_mul](algorithms/matrix/sparse_mul.py)
+    - [spiral_traversal](algorithms/matrix/spiral_traversal.py)
+- [queues](algorithms/queues)
+    - [max_sliding_window](algorithms/queues/max_sliding_window.py)
+    - [moving_average](algorithms/queues/moving_average.py)
+    - [queue](algorithms/queues/queue.py)
+    - [reconstruct_queue](algorithms/queues/reconstruct_queue.py)
+    - [zigzagiterator](algorithms/queues/zigzagiterator.py)
+- [search](algorithms/search)
+    - [binary_search](algorithms/search/binary_search.py)
+    - [first_occurrence](algorithms/search/first_occurrence.py)
+    - [last_occurrence](algorithms/search/last_occurrence.py)
+    - [linear_search](algorithms/search/linear_search.py)
+    - [search_insert](algorithms/search/search_insert.py)
+    - [two_sum](algorithms/search/two_sum.py)
+    - [search_range](algorithms/search/search_range.py)
+    - [find_min_rotate](algorithms/search/find_min_rotate.py)
+    - [search_rotate](algorithms/search/search_rotate.py)
+    - [jump_search](algorithms/search/jump_search.py)
+    - [next_greatest_letter](algorithms/search/next_greatest_letter.py)
+- [set](algorithms/set)
+    - [randomized_set](algorithms/set/randomized_set.py)
+    - [set_covering](algorithms/set/set_covering.py)
+    - [find_keyboard_row](algorithms/set/find_keyboard_row.py)
+- [sort](algorithms/sort)
+    - [bitonic_sort](algorithms/sort/bitonic_sort.py)
+    - [bogo_sort](algorithms/sort/bogo_sort.py)
+    - [bubble_sort](algorithms/sort/bubble_sort.py)
+    - [bucket_sort](algorithms/sort/bucket_sort.py)
+    - [cocktail_shaker_sort](algorithms/sort/cocktail_shaker_sort.py)
+    - [comb_sort](algorithms/sort/comb_sort.py)
+    - [counting_sort](algorithms/sort/counting_sort.py)
+    - [cycle_sort](algorithms/sort/cycle_sort.py)
+    - [gnome_sort](algorithms/sort/gnome_sort.py)
+    - [heap_sort](algorithms/sort/heap_sort.py)
+    - [insertion_sort](algorithms/sort/insertion_sort.py)
+    - [meeting_rooms](algorithms/sort/meeting_rooms.py)
+    - [merge_sort](algorithms/sort/merge_sort.py)
+    - [pancake_sort](algorithms/sort/pancake_sort.py)
+    - [quick_sort](algorithms/sort/quick_sort.py)
+    - [radix_sort](algorithms/sort/radix_sort.py)
+    - [selection_sort](algorithms/sort/selection_sort.py)
+    - [shell_sort](algorithms/sort/shell_sort.py)
+    - [sort_colors](algorithms/sort/sort_colors.py)
+    - [top_sort](algorithms/sort/top_sort.py)
+    - [wiggle_sort](algorithms/sort/wiggle_sort.py)
+- [stack](algorithms/stack)
+    - [longest_abs_path](algorithms/stack/longest_abs_path.py)
+    - [simplify_path](algorithms/stack/simplify_path.py)
+    - [stack](algorithms/stack/stack.py)
+    - [valid_parenthesis](algorithms/stack/valid_parenthesis.py)
+    - [stutter](algorithms/stack/stutter.py)
+    - [switch_pairs](algorithms/stack/switch_pairs.py)
+    - [is_consecutive](algorithms/stack/is_consecutive.py)
+    - [remove_min](algorithms/stack/remove_min.py)
+    - [is_sorted](algorithms/stack/is_sorted.py)
+- [strings](algorithms/strings)
+    - [fizzbuzz](algorithms/strings/fizzbuzz.py)
+    - [delete_reoccurring](algorithms/strings/delete_reoccurring.py)
+    - [strip_url_params](algorithms/strings/strip_url_params.py)
+    - [validate_coordinates](algorithms/strings/validate_coordinates.py)
+    - [domain_extractor](algorithms/strings/domain_extractor.py)
+    - [merge_string_checker](algorithms/strings/merge_string_checker.py)
+    - [add_binary](algorithms/strings/add_binary.py)
+    - [breaking_bad](algorithms/strings/breaking_bad.py)
+    - [decode_string](algorithms/strings/decode_string.py)
+    - [encode_decode](algorithms/strings/encode_decode.py)
+    - [group_anagrams](algorithms/strings/group_anagrams.py)
+    - [int_to_roman](algorithms/strings/int_to_roman.py)
+    - [is_palindrome](algorithms/strings/is_palindrome.py)
+    - [license_number](algorithms/strings/license_number.py)
+    - [make_sentence](algorithms/strings/make_sentence.py)
+    - [multiply_strings](algorithms/strings/multiply_strings.py)
+    - [one_edit_distance](algorithms/strings/one_edit_distance.py)
+    - [rabin_karp](algorithms/strings/rabin_karp.py)
+    - [reverse_string](algorithms/strings/reverse_string.py)
+    - [reverse_vowel](algorithms/strings/reverse_vowel.py)
+    - [reverse_words](algorithms/strings/reverse_words.py)
+    - [roman_to_int](algorithms/strings/roman_to_int.py)
+    - [word_squares](algorithms/strings/word_squares.py)
+    - [unique_morse](algorithms/strings/unique_morse.py)
+    - [judge_circle](algorithms/strings/judge_circle.py)
+    - [strong_password](algorithms/strings/strong_password.py)
+    - [caesar_cipher](algorithms/strings/caesar_cipher.py)
+    - [contain_string](algorithms/strings/contain_string.py)
+    - [count_binary_substring](algorithms/strings/count_binary_substring.py)
+    - [repeat_string](algorithms/strings/repeat_string.py)
+    - [min_distance](algorithms/strings/min_distance.py)
+    - [longest_common_prefix](algorithms/strings/longest_common_prefix.py)
+    - [rotate](algorithms/strings/rotate.py)
+    - [first_unique_char](algorithms/strings/first_unique_char.py)
+    - [repeat_substring](algorithms/strings/repeat_substring.py)     
+- [tree](algorithms/tree)
+    - [bst](algorithms/tree/bst)
+        - [array_to_bst](algorithms/tree/bst/array_to_bst.py)
+        - [bst_closest_value](algorithms/tree/bst/bst_closest_value.py)
+        - [BSTIterator](algorithms/tree/bst/BSTIterator.py)
+        - [delete_node](algorithms/tree/bst/delete_node.py)
+        - [is_bst](algorithms/tree/bst/is_bst.py)
+        - [kth_smallest](algorithms/tree/bst/kth_smallest.py)
+        - [lowest_common_ancestor](algorithms/tree/bst/lowest_common_ancestor.py)
+        - [predecessor](algorithms/tree/bst/predecessor.py)
+        - [serialize_deserialize](algorithms/tree/bst/serialize_deserialize.py)
+        - [successor](algorithms/tree/bst/successor.py)
+        - [unique_bst](algorithms/tree/bst/unique_bst.py)
+        - [depth_sum](algorithms/tree/bst/depth_sum.py)
+        - [count_left_node](algorithms/tree/bst/count_left_node.py)
+        - [num_empty](algorithms/tree/bst/num_empty.py)
+        - [height](algorithms/tree/bst/height.py)
+    - [red_black_tree](algorithms/tree/red_black_tree)
+        - [red_black_tree](algorithms/tree/red_black_tree/red_black_tree.py)
+    - [segment_tree](algorithms/tree/segment_tree)
+        - [segment_tree](algorithms/tree/segment_tree/segment_tree.py)
+    - [traversal](algorithms/tree/traversal)
+        - [inorder](algorithms/tree/traversal/inorder.py)
+        - [level_order](algorithms/tree/traversal/level_order.py)
+        - [postorder](algorithms/tree/traversal/postorder.py)
+        - [preorder](algorithms/tree/traversal/preorder.py)
+        - [zigzag](algorithms/tree/traversal/zigzag.py)
+    - [trie](algorithms/tree/trie)
+        - [add_and_search](algorithms/tree/trie/add_and_search.py)
+        - [trie](algorithms/tree/trie/trie.py)
+    - [binary_tree_paths](algorithms/tree/binary_tree_paths.py)
+    - [bin_tree_to_list](algorithms/tree/bin_tree_to_list.py)
+    - [deepest_left](algorithms/tree/deepest_left.py)
+    - [invert_tree](algorithms/tree/invert_tree.py)
+    - [is_balanced](algorithms/tree/is_balanced.py)
+    - [is_subtree](algorithms/tree/is_subtree.py)
+    - [is_symmetric](algorithms/tree/is_symmetric.py)
+    - [longest_consecutive](algorithms/tree/longest_consecutive.py)
+    - [lowest_common_ancestor](algorithms/tree/lowest_common_ancestor.py)
+    - [max_height](algorithms/tree/max_height.py)
+    - [max_path_sum](algorithms/tree/max_path_sum.py)
+    - [min_height](algorithms/tree/min_height.py)
+    - [path_sum](algorithms/tree/path_sum.py)
+    - [path_sum2](algorithms/tree/path_sum2.py)
+    - [pretty_print](algorithms/tree/pretty_print.py)
+    - [same_tree](algorithms/tree/same_tree.py)
+    - [tree](algorithms/tree/tree.py)
+- [unix](algorithms/unix)
+    - [path](algorithms/unix/path/)
+        - [join_with_slash](algorithms/unix/path/join_with_slash.py)
+        - [full_path](algorithms/unix/path/full_path.py)
+        - [split](algorithms/unix/path/split.py)
+        - [simplify_path](algorithms/unix/path/simplify_path.py)
+- [union-find](algorithms/union-find)
+    - [count_islands](algorithms/union-find/count_islands.py)
+- [machine-learning](algorithms/machine-learning)
+    - [nearest neighbor classification](algorithms/machine-learning/nearest_neighbor.py)
+
+## Colaboradores
+El repositorio es mantenido por
+
+* [Keon Kim](https://github.com/keon)
+* [Rahul Goswami](https://github.com/goswami-rahul)
+* [Christian Bender](https://github.com/christianbender)
+* [Ankit Agarwal](https://github.com/ankit167)
+* [Hai Hoang Dang](https://github.com/danghai)
+* [Saad](https://github.com/SaadBenn)
+
+Y gracias a [todos los colaboradores](https://github.com/keon/algorithms/graphs/contributors)
+que ayudaron en la construcción del repositorio.
diff --git a/README_FR.md b/README_FR.md
index bfe2f90..aecd40e 100644
--- a/README_FR.md
+++ b/README_FR.md
@@ -1,6 +1,6 @@
 <p align="center"><img src="https://raw.githubusercontent.com/keon/algorithms/master/docs/source/_static/logo/logotype1blue.png"></p>
 
-English | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md)
+[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | Français | [Español](README_ES.md)
 
 [![Version PyPI](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms)
 [![Contributeurs open source](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms)
diff --git a/README_GE.md b/README_GE.md
index 782c494..e88d5c3 100644
--- a/README_GE.md
+++ b/README_GE.md
@@ -1,6 +1,6 @@
 <p align="center"><img src="https://raw.githubusercontent.com/keon/algorithms/master/docs/source/_static/logo/logotype1blue.png"></p>
 
-[English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md)
+[English](README.md) | [简体中文](README_CN.md) | Deutsch | [日本語](README_JP.md) | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md)
 
 [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms)
 [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms)
diff --git a/README_JP.md b/README_JP.md
index b5fff7b..98d1eb5 100644
--- a/README_JP.md
+++ b/README_JP.md
@@ -1,6 +1,6 @@
 <p align="center"><img src="https://raw.githubusercontent.com/keon/algorithms/master/docs/source/_static/logo/logotype1blue.png"></p>
 
-[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md)
+[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | 日本語 | [한국어](README_KR.md) | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md)
 
 [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms)
 [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms)
diff --git a/README_KR.md b/README_KR.md
index cf09125..e3114f3 100644
--- a/README_KR.md
+++ b/README_KR.md
@@ -1,6 +1,6 @@
 <p align="center"><img src="https://raw.githubusercontent.com/keon/algorithms/master/docs/source/_static/logo/logotype1blue.png"></p>
 
-[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | 한국어 | [Português](README_PTBR.md) | [Français](README_FR.md)
+[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | 한국어 | [Português](README_PTBR.md) | [Français](README_FR.md) | [Español](README_ES.md)
 
 [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms)
 [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms)
diff --git a/README_PTBR.md b/README_PTBR.md
index efe3b1b..e0ca1a1 100644
--- a/README_PTBR.md
+++ b/README_PTBR.md
@@ -1,6 +1,6 @@
 <p align="center"><img src="https://raw.githubusercontent.com/keon/algorithms/master/docs/source/_static/logo/logotype1blue.png"></p>
 
-[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | Português | [Français](README_FR.md)
+[English](README.md) | [简体中文](README_CN.md) | [Deutsch](README_GE.md) | [日本語](README_JP.md) | [한국어](README_KR.md) | Português | [Français](README_FR.md) | [Español](README_ES.md)
 
 [![PyPI version](https://badge.fury.io/py/algorithms.svg)](https://badge.fury.io/py/algorithms)
 [![Open Source Helpers](https://www.codetriage.com/keon/algorithms/badges/users.svg)](https://www.codetriage.com/keon/algorithms)
diff --git a/algorithms/calculator/math_parser.py b/algorithms/calculator/math_parser.py
index a1d0e0b..3cbe1cb 100644
--- a/algorithms/calculator/math_parser.py
+++ b/algorithms/calculator/math_parser.py
@@ -93,7 +93,7 @@ def parse(expression):
                 result.append(i)
             else:
                 raise Exception("invalid syntax " + i)
-                
+
     if len(current) > 0:
         result.append(current)
     return result
@@ -133,15 +133,17 @@ def main():
         simple user-interface
     """
     print("\t\tCalculator\n\n")
-    user_input = input("expression or exit: ")
-    while user_input != "exit":
+    while True:
+        user_input = input("expression or exit: ")
+        if user_input == "exit":
+            break
         try:
             print("The result is {0}".format(evaluate(user_input)))
         except Exception:
             print("invalid syntax!")
             user_input = input("expression or exit: ")
     print("program end")
-        
+
 
 if __name__ == "__main__":
     main()
diff --git a/algorithms/graph/minimum_spanning_tree.py b/algorithms/graph/minimum_spanning_tree.py
index 2a877f9..dcc6898 100644
--- a/algorithms/graph/minimum_spanning_tree.py
+++ b/algorithms/graph/minimum_spanning_tree.py
@@ -28,8 +28,8 @@ class DisjointSet:
 
         # Get the set of nodes at position <a> and <b>
         # If <a> and <b> are the roots, this will be constant O(1)
-        a = self.findSet(a)
-        b = self.findSet(b)
+        a = self.find_set(a)
+        b = self.find_set(b)
 
         # Join the shortest node to the longest, minimizing tree size (faster find)
         if self.size[a] < self.size[b]:
@@ -73,8 +73,8 @@ def kruskal(n, edges, ds):
     mst = [] # List of edges taken, minimum spanning tree
 
     for edge in edges:
-        set_u = ds.findSet(edge.u) # Set of the node <u>
-        set_v = ds.findSet(edge.v) # Set of the node <v>
+        set_u = ds.find_set(edge.u) # Set of the node <u>
+        set_v = ds.find_set(edge.v) # Set of the node <v>
         if set_u != set_v:
             ds.merge_set(set_u, set_v)
             mst.append(edge)
@@ -127,4 +127,4 @@ if __name__ == "__main__":
             edges[i] = Edge(u, v, weight)
 
         # After finish input and graph creation, use Kruskal algorithm for MST:
-        print("MST weights sum:", kruskal(n, edges, ds))
\ No newline at end of file
+        print("MST weights sum:", kruskal(n, edges, ds))
diff --git a/algorithms/heap/__init__.py b/algorithms/heap/__init__.py
index 3731b0e..9ea682d 100644
--- a/algorithms/heap/__init__.py
+++ b/algorithms/heap/__init__.py
@@ -1,3 +1,5 @@
 from .binary_heap import *
 from .skyline import *
 from .sliding_window_max import *
+from .merge_sorted_k_lists import *
+from .k_closest_points import *
diff --git a/algorithms/heap/binary_heap.py b/algorithms/heap/binary_heap.py
index 5119a03..629be43 100644
--- a/algorithms/heap/binary_heap.py
+++ b/algorithms/heap/binary_heap.py
@@ -59,9 +59,7 @@ class BinaryHeap(AbstractHeap):
         while i // 2 > 0:
             if self.heap[i] < self.heap[i // 2]:
                 # Swap value of child with value of its parent
-                tmp = self.heap[i]
-                self.heap[i] = self.heap[i // 2]
-                self.heap[i // 2] = tmp
+                self.heap[i], self.heap[i//2] = self.heap[i//2], self.heap[i]
             i = i // 2
 
     """
@@ -95,9 +93,7 @@ class BinaryHeap(AbstractHeap):
             min_child = self.min_child(i)
             if self.heap[min_child] < self.heap[i]:
                 # Swap min child with parent
-                tmp = self.heap[min_child]
-                self.heap[min_child] = self.heap[i]
-                self.heap[i] = tmp
+                self.heap[min_child], self.heap[i] = self.heap[i], self.heap[min_child]
             i = min_child
     """
         Remove Min method removes the minimum element and swap it with the last
diff --git a/algorithms/heap/k_closest_points.py b/algorithms/heap/k_closest_points.py
new file mode 100644
index 0000000..8e38e05
--- /dev/null
+++ b/algorithms/heap/k_closest_points.py
@@ -0,0 +1,44 @@
+"""Given a list of points, find the k closest to the origin.
+
+Idea: Maintain a max heap of k elements.
+We can iterate through all points.
+If a point p has a smaller distance to the origin than the top element of a heap, we add point p to the heap and remove the top element.
+After iterating through all points, our heap contains the k closest points to the origin.
+"""
+
+
+from heapq import heapify, heappushpop
+
+
+def k_closest(points, k, origin=(0, 0)):
+    # Time: O(k+(n-k)logk)
+    # Space: O(k)
+    """Initialize max heap with first k points.
+    Python does not support a max heap; thus we can use the default min heap where the keys (distance) are negated.
+    """
+    heap = [(-distance(p, origin), p) for p in points[:k]]
+    heapify(heap)
+
+    """
+    For every point p in points[k:],
+    check if p is smaller than the root of the max heap;
+    if it is, add p to heap and remove root. Reheapify.
+    """
+    for p in points[k:]:
+        d = distance(p, origin)
+
+        heappushpop(heap, (-d, p))  # heappushpop does conditional check
+        """Same as:
+            if d < -heap[0][0]:
+                heappush(heap, (-d,p))
+                heappop(heap)
+
+        Note: heappushpop is more efficient than separate push and pop calls.
+        Each heappushpop call takes O(logk) time.
+        """
+
+    return [p for nd, p in heap]  # return points in heap
+
+
+def distance(point, origin=(0, 0)):
+    return (point[0] - origin[0])**2 + (point[1] - origin[1])**2
diff --git a/algorithms/maths/hailstone.py b/algorithms/maths/hailstone.py
new file mode 100644
index 0000000..2232123
--- /dev/null
+++ b/algorithms/maths/hailstone.py
@@ -0,0 +1,13 @@
+def hailstone(n):
+  """Return the 'hailstone sequence' from n to 1
+     n: The starting point of the hailstone sequence
+  """
+
+  sequence = [n]
+  while n > 1:
+    if n%2 != 0:
+      n = 3*n + 1
+    else: 
+      n = int(n/2)
+    sequence.append(n)
+  return sequence
\ No newline at end of file
diff --git a/algorithms/matrix/rotate_image.py b/algorithms/matrix/rotate_image.py
index 0a6fb50..21f1c74 100644
--- a/algorithms/matrix/rotate_image.py
+++ b/algorithms/matrix/rotate_image.py
@@ -14,7 +14,7 @@ Could you do this in-place?
 # 4 5 6  => 4 5 6  => 8 5 2
 # 7 8 9     1 2 3     9 6 3
 
-def rotate(mat:"List[List[int]]"):
+def rotate(mat): 
     if not mat:
         return mat
     mat.reverse()


Test patch:
diff --git a/tests/test_heap.py b/tests/test_heap.py
index 0925972..91e144d 100644
--- a/tests/test_heap.py
+++ b/tests/test_heap.py
@@ -1,15 +1,18 @@
 from algorithms.heap import (
     BinaryHeap,
     get_skyline,
-    max_sliding_window
+    max_sliding_window,
+    k_closest_points
 )
 
 import unittest
 
+
 class TestBinaryHeap(unittest.TestCase):
     """
         Test suite for the binary_heap data structures
     """
+
     def setUp(self):
         self.min_heap = BinaryHeap()
         self.min_heap.insert(4)
@@ -24,7 +27,7 @@ class TestBinaryHeap(unittest.TestCase):
         # After insert:  [0, 2, 50, 4, 55, 90, 87, 7]
         self.min_heap.insert(2)
         self.assertEqual([0, 2, 50, 4, 55, 90, 87, 7],
-                          self.min_heap.heap)
+                         self.min_heap.heap)
         self.assertEqual(7, self.min_heap.currentSize)
 
     def test_remove_min(self):
@@ -32,23 +35,33 @@ class TestBinaryHeap(unittest.TestCase):
         # Before remove_min : [0, 4, 50, 7, 55, 90, 87]
         # After remove_min: [7, 50, 87, 55, 90]
         # Test return value
-        self.assertEqual(4,ret)
+        self.assertEqual(4, ret)
         self.assertEqual([0, 7, 50, 87, 55, 90],
-                          self.min_heap.heap)
+                         self.min_heap.heap)
         self.assertEqual(5, self.min_heap.currentSize)
 
+
 class TestSuite(unittest.TestCase):
     def test_get_skyline(self):
-        buildings = [ [2, 9, 10], [3, 7, 15], [5, 12, 12], \
-                      [15, 20, 10], [19, 24, 8] ]
+        buildings = [[2, 9, 10], [3, 7, 15], [5, 12, 12],
+                     [15, 20, 10], [19, 24, 8]]
         # Expect output
-        output = [ [2, 10], [3, 15], [7, 12], [12, 0], [15, 10], \
-                   [20, 8], [24, 0] ]
+        output = [[2, 10], [3, 15], [7, 12], [12, 0], [15, 10],
+                  [20, 8], [24, 0]]
         self.assertEqual(output, get_skyline(buildings))
 
     def test_max_sliding_window(self):
         nums = [1, 3, -1, -3, 5, 3, 6, 7]
         self.assertEqual([3, 3, 5, 5, 6, 7], max_sliding_window(nums, 3))
 
+    def test_k_closest_points(self):
+        points = [(1, 0), (2, 3), (5, 2), (1, 1), (2, 8), (10, 2), (-1, 0), (-2, -2)]
+        self.assertEqual([(-1, 0), (1, 0)], k_closest(points, 2))
+        self.assertEqual([(1, 1), (-1, 0), (1, 0)], k_closest(points, 3))
+        self.assertEqual([(-2, -2), (1, 1), (1, 0), (-1, 0)], k_closest(points, 4))
+        self.assertEqual([(10, 2), (2, 8), (5, 2), (-2, -2), (2, 3),
+                          (1, 0), (-1, 0), (1, 1)], k_closest(points, 8))
+
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/tests/test_maths.py b/tests/test_maths.py
index 0777f9a..dd1d0e1 100644
--- a/tests/test_maths.py
+++ b/tests/test_maths.py
@@ -14,7 +14,8 @@ from algorithms.maths import (
     pythagoras,
     is_prime,
     encrypt, decrypt,
-    combination, combination_memo
+    combination, combination_memo,
+    hailstone,
 )
 
 import unittest
@@ -288,5 +289,17 @@ class TestFactorial(unittest.TestCase):
         self.assertRaises(ValueError, factorial_recur, 42, -1)
 
 
+class TestHailstone(unittest.TestCase):
+    """[summary]
+    Test for the file hailstone.py
+
+    Arguments:
+        unittest {[type]} -- [description]
+    """
+    def test_hailstone(self):
+        self.assertEqual([8, 4, 2, 1], hailstone.hailstone(8))
+        self.assertEqual([10, 5, 16, 8, 4, 2, 1], hailstone.hailstone(10))
+
+
 if __name__ == "__main__":
     unittest.main()