Repository: keon/algorithms
Pull request #426 (2018-10-09 16:31:23)

Add spanish README and  CONTRIBUTING
(Put an `X` inside the `[ ]` to denote check mark `[X]`.)


- [ ] **If creating a new file :**
  - [X] added links to it in the README files ?
  - [ ] included tests with it ?
  - [ ] 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..1510077 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)
@@ -203,6 +203,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/arrays/plus_one.py b/algorithms/arrays/plus_one.py
index f63aafa..473b6c7 100644
--- a/algorithms/arrays/plus_one.py
+++ b/algorithms/arrays/plus_one.py
@@ -42,7 +42,7 @@ def plus_one_v2(digits):
 def plus_one_v3(num_arr):
 
     for idx in reversed(list(enumerate(num_arr))):
-        num_arr[idx] = (num_arr[idx] + 1) % 10
-        if num_arr[idx]:
+        num_arr[idx[0]] = (num_arr[idx[0]] + 1) % 10
+        if num_arr[idx[0]]:
             return num_arr
     return [1] + num_arr
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/dp/__init__.py b/algorithms/dp/__init__.py
new file mode 100644
index 0000000..174f524
--- /dev/null
+++ b/algorithms/dp/__init__.py
@@ -0,0 +1,1 @@
+from .edit_distance import *
diff --git a/algorithms/dp/edit_distance.py b/algorithms/dp/edit_distance.py
new file mode 100644
index 0000000..ecf6beb
--- /dev/null
+++ b/algorithms/dp/edit_distance.py
@@ -0,0 +1,54 @@
+"""The edit distance between two words is the minimum number of letter insertions,
+letter deletions, and letter substitutions required to transform one word into another.
+
+For example, the edit distance between FOOD and MONEY is at most four:
+
+FOOD -> MOOD -> MOND -> MONED -> MONEY
+
+Given two words A and B, find the minimum number of operations required to transform one string into the other.
+In other words, find the edit distance between A and B.
+
+Thought process:
+
+Let edit(i, j) denote the edit distance between the prefixes A[1..i] and B[1..j].
+
+Then, the function satifies the following recurrence:
+
+edit(i, j) = i if j = 0
+             j if i = 0
+             min(edit(i-1, j) + 1, 
+                 edit(i, j-1), + 1,
+                 edit(i-1, j-1) + cost) otherwise
+
+There are two base cases, both of which occur when one string is empty and the other is not.
+1. To convert an empty string A into a string B of length n, perform n insertions.
+2. To convert a string A of length m into an empty string B, perform m deletions.
+
+Here, the cost is 1 if a substitution is required,
+or 0 if both chars in words A and B are the same at indexes i and j, respectively.
+
+To find the edit distance between two words A and B,
+we need to find edit(m, n), where m is the length of A and n is the length of B.
+"""
+
+
+def edit_distance(A, B):
+    # Time: O(m*n)
+    # Space: O(m*n)
+
+    m, n = len(A) + 1, len(B) + 1
+
+    edit = [[0 for _ in range(n)] for _ in range(m)]
+
+    for i in range(1, m):
+        edit[i][0] = i
+
+    for j in range(1, n):
+        edit[0][j] = j
+
+    for i in range(1, m):
+        for j in range(1, n):
+            cost = 0 if A[i - 1] == B[j - 1] else 1
+            edit[i][j] = min(edit[i - 1][j] + 1, edit[i][j - 1] + 1, edit[i - 1][j - 1] + cost)
+
+    return edit[-1][-1]  # this is the same as edit[m][n]
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/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/linkedlist/__init__.py b/algorithms/linkedlist/__init__.py
index 21263bf..1c9c3b9 100644
--- a/algorithms/linkedlist/__init__.py
+++ b/algorithms/linkedlist/__init__.py
@@ -6,3 +6,4 @@ from .rotate_list import *
 from .is_cyclic import *
 from .merge_two_list import *
 from .is_palindrome import *
+from .copy_random_pointer import *
diff --git a/algorithms/linkedlist/copy_random_pointer.py b/algorithms/linkedlist/copy_random_pointer.py
index 7653d49..b3ef462 100644
--- a/algorithms/linkedlist/copy_random_pointer.py
+++ b/algorithms/linkedlist/copy_random_pointer.py
@@ -4,35 +4,45 @@ pointer which could point to any node in the list or null.
 
 Return a deep copy of the list.
 """
-# from collections import defaultdict
+from collections import defaultdict
 
-# TODO: This requires to be rewritten -- commenting it out for now
-# class Solution0:
-  # @param head, a RandomListNode
-  # @return a RandomListNode
-  # def copyRandomList(self, head):
-  #   dic = dict()
-  #   m = n = head
-  #   while m:
-  #       dic[m] = RandomListNode(m.label)
-  #       m = m.next
-  #   while n:
-  #       dic[n].next = dic.get(n.next)
-  #       dic[n].random = dic.get(n.random)
-  #       n = n.next
-  #   return dic.get(head)
-#
-#
-# class Solution1:  # O(n)
-#   @param head, a RandomListNode
-#   @return a RandomListNode
-  # def copyRandomList(self, head):
-  #   copy = defaultdict(lambda: RandomListNode(0))
-  #   copy[None] = None
-  #   node = head
-  #   while node:
-  #       copy[node].label = node.label
-  #       copy[node].next = copy[node.next]
-  #       copy[node].random = copy[node.random]
-  #       node = node.next
-  #   return copy[head]
+
+class RandomListNode(object):
+    def __init__(self, label):
+        self.label = label
+        self.next = None
+        self.random = None
+
+
+def copy_random_pointer_v1(head):
+    """
+    :type head: RandomListNode
+    :rtype: RandomListNode
+    """
+    dic = dict()
+    m = n = head
+    while m:
+        dic[m] = RandomListNode(m.label)
+        m = m.next
+    while n:
+        dic[n].next = dic.get(n.next)
+        dic[n].random = dic.get(n.random)
+        n = n.next
+    return dic.get(head)
+
+
+# O(n)
+def copy_random_pointer_v2(head):
+    """
+    :type head: RandomListNode
+    :rtype: RandomListNode
+    """
+    copy = defaultdict(lambda: RandomListNode(0))
+    copy[None] = None
+    node = head
+    while node:
+        copy[node].label = node.label
+        copy[node].next = copy[node.next]
+        copy[node].random = copy[node.random]
+        node = node.next
+    return copy[head]
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_dp.py b/tests/test_dp.py
new file mode 100644
index 0000000..bbec085
--- /dev/null
+++ b/tests/test_dp.py
@@ -0,0 +1,16 @@
+from algorithms.dp import (
+    edit_distance
+)
+
+
+import unittest
+
+
+class TestEditDistance(unittest.TestCase):
+    def test_edit_distance(self):
+        self.assertEqual(edit_distance('food', 'money'), 4)
+        self.assertEqual(edit_distance('horse', 'ros'), 3)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/test_linkedlist.py b/tests/test_linkedlist.py
index 435ac72..6b7f1f4 100644
--- a/tests/test_linkedlist.py
+++ b/tests/test_linkedlist.py
@@ -1,3 +1,5 @@
+import unittest
+
 from algorithms.linkedlist import (
     reverse_list, reverse_list_recursive,
     is_sorted,
@@ -6,16 +8,17 @@ from algorithms.linkedlist import (
     rotate_right,
     is_cyclic,
     merge_two_list, merge_two_list_recur,
-    is_palindrome, is_palindrome_stack, is_palindrome_dict
+    is_palindrome, is_palindrome_stack, is_palindrome_dict,
+    RandomListNode, copy_random_pointer_v1, copy_random_pointer_v2
 )
 
-import unittest
 
 class Node(object):
     def __init__(self, x):
         self.val = x
         self.next = None
 
+
 # Convert from linked list Node to list for testing
 def convert(head):
     ret = []
@@ -26,6 +29,7 @@ def convert(head):
             current = current.next
     return ret
 
+
 class TestSuite(unittest.TestCase):
     def setUp(self):
         # list test for palindrome
@@ -69,7 +73,6 @@ class TestSuite(unittest.TestCase):
         self.assertFalse(is_sorted(head))
 
     def test_remove_range(self):
-
         # Test case: middle case.
         head = Node(0)
         head.next = Node(1)
@@ -163,12 +166,50 @@ class TestSuite(unittest.TestCase):
     def test_is_palindrome(self):
         self.assertTrue(is_palindrome(self.l))
         self.assertFalse(is_palindrome(self.l1))
+
     def test_is_palindrome_stack(self):
         self.assertTrue(is_palindrome_stack(self.l))
         self.assertFalse(is_palindrome_stack(self.l1))
+
     def test_is_palindrome_dict(self):
         self.assertTrue(is_palindrome_dict(self.l))
         self.assertFalse(is_palindrome_dict(self.l1))
 
+    def test_solution_0(self):
+        self._init_random_list_nodes()
+        result = copy_random_pointer_v1(self.random_list_node1)
+        self._assert_is_a_copy(result)
+
+    def test_solution_1(self):
+        self._init_random_list_nodes()
+        result = copy_random_pointer_v2(self.random_list_node1)
+        self._assert_is_a_copy(result)
+
+    def _assert_is_a_copy(self, result):
+        self.assertEqual(5, result.next.next.next.next.label)
+        self.assertEqual(4, result.next.next.next.label)
+        self.assertEqual(3, result.next.next.label)
+        self.assertEqual(2, result.next.label)
+        self.assertEqual(1, result.label)
+        self.assertEqual(3, result.next.next.next.next.random.label)
+        self.assertIsNone(result.next.next.next.random)
+        self.assertEqual(2, result.next.next.random.label)
+        self.assertEqual(5, result.next.random.label)
+        self.assertEqual(4, result.random.label)
+
+    def _init_random_list_nodes(self):
+        self.random_list_node1 = RandomListNode(1)
+        random_list_node2 = RandomListNode(2)
+        random_list_node3 = RandomListNode(3)
+        random_list_node4 = RandomListNode(4)
+        random_list_node5 = RandomListNode(5)
+
+        self.random_list_node1.next, self.random_list_node1.random = random_list_node2, random_list_node4
+        random_list_node2.next, random_list_node2.random = random_list_node3, random_list_node5
+        random_list_node3.next, random_list_node3.random = random_list_node4, random_list_node2
+        random_list_node4.next = random_list_node5
+        random_list_node5.random = random_list_node3
+
+
 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()