Skip to content

Heaps algorithm #2475

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Sep 29, 2020
Merged
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions divide_and_conquer/heaps_algorithm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""
Heap's algorithm returns the list of all permutations possible from a list.
It minimizes movement by generating each permutation from the previous one
by swapping only two elements.
More information:
https://en.wikipedia.org/wiki/Heap%27s_algorithm.
"""


def heaps(arr: list) -> list:
"""
Pure python implementation of the Heap's algorithm,
returning all permutations of a list.
>>> heaps([])
[[]]
>>> heaps([0])
[[0]]
>>> heaps([-1, 1])
[[-1, 1], [1, -1]]
>>> heaps([1, 2, 3])
[[1, 2, 3], [2, 1, 3], [3, 1, 2], [1, 3, 2], [2, 3, 1], [3, 2, 1]]
Copy link
Member

@cclauss cclauss Sep 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of (or in addition to) manual doctest results, please test this against https://docs.python.org/3/library/itertools.html#itertools.permutations to ensure they both deliver identical results.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Added one comparison between my algo and itertools permutations. Also outputed my permutations as list of tuples instead of list of lists to match itertools.

Copy link
Member

@cclauss cclauss Sep 24, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I use set() since i have to compare the result of a generator (itertools) vs mine (list of tuple), as well as the order of tuples might also be different from one version to the other but can still be correct. Maybe you see another "cleaner" way of doing this ?
I don't think comparing with combinations is a good idea, the Heap's algorithm outputs permutations (order of elements matters).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tuple(permutations(data)) and if that does not work sorted(permutations(data))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Used sorted() but had to used it on both permutations() and heaps().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated with your comment relative to the iterative version.

"""

if len(arr) <= 1:
return [arr]

res = []

def generate(k: int, arr: list):
if k == 1:
res.append(arr[:])
return

generate(k - 1, arr)

for i in range(k - 1):
if k % 2 == 0: # k is even
arr[i], arr[k - 1] = arr[k - 1], arr[i]
else: # k is odd
arr[0], arr[k - 1] = arr[k - 1], arr[0]
generate(k - 1, arr)

generate(len(arr), arr)
return res


if __name__ == "__main__":
user_input = input("Enter numbers separated by a comma:\n").strip()
arr = [int(item) for item in user_input.split(",")]
print(heaps(arr))