Talk:Heap's algorithm

Latest comment: 2 months ago by Yuvalif in topic Incorrect algorithm

Code could be reduced

edit

the algorithm presented on this page can be refactored to the following

let swap = (a, l, r) => {
	let t = a[l];
	a[l] = a[r];
	a[r] = t;
}

let generate = (A, k) => {
	while(k-- > 1){
		for(let i = 0; i < k; i++){
			generate(A, k);
			swap(A, k%2*i, k);
		}
	}

	output(a);
}

I believe this to be an improvement as it reduces the amount of control flow and reduces repetition. — Preceding unsigned comment added by 134.161.212.93 (talk) 15:46, 13 October 2023 (UTC)Reply

Fix needed

edit

This article needs to be enhanced. It looks like this algorithm is a good solution to the problem. It is quite nice that it is short and works, and in 1963 it was most important to reduce complexity and memory consumption. But if you look what it does (the picture is very helpful with that) it is quite weird and does lots of unnecessary swaps. So, the pro and contra, and other algorithms like Steinhaus–Johnson–Trotter algorithm should be mentioned. 5.146.194.61 (talk) 14:53, 8 October 2014 (UTC)Reply

Please fix it! Feel free to add at least a "see also" section that links to the other algorithm, and if you have source that compares algorithms, be sure to cite it. QVVERTYVS (hm?) 09:34, 9 October 2014 (UTC)Reply

An Implementation in Javascript

edit

I implemented this algorithm in Javascript based on the pseudocode from this article, as closely as possible. I had found the algorithm a little difficult to understand without a working implementation, & hope this can help others. I didn't add this link to the Article itself, to avoid violating WP:NOR. http://dsernst.com/2014/12/14/heaps-permutation-algorithm-in-javascript/ Thanks! --dsernst (talk) 09:52, 4 January 2015 (UTC)Reply

Thanks @dsernst, this was very useful to me. I tried to follow in your footsteps and implement the non-recursive algo in Javascript. Here is the link to the implementation: https://github.com/user883311/heap-s-permutations/blob/master/non-recursive.js -- B.

Incorrect algorithm

edit

The extra swaps stem from swapping in the last iteration of the for loop, are not a part of Heap's algorithm. I compared with Sedgewick (1977). I will correct the article, but this means that the nice illustration is out of date, and will be removed. sverdrup (talk) 11:48, 29 June 2015 (UTC)Reply

The last edit to the algorithm itself (where the range of iteration has been changed from [0,n-1] to [0,n-2]) did not work, so I changed it back to [0,n-1].
I have no access to the Sedgewick 1977 paper, but according to the other 'paper'(more like presentation) the genuine range is [0,n-1]. — Preceding unsigned comment added by 5.43.65.114 (talk) 22:41, 18 August 2015 (UTC)Reply
There have been some edits to the given algorithm, and it seems we've been through these edits before.
This edit, which deleted the second call to generate did not do enough permutations. I reverted. A similar edit was reverted previously.[1]
This edit, which added another iteration to the for loop, does too many permutations. It would do the right number of permutations if the second call to generate were removed (and produces Sedgewick's variation below). However, that brings us back to Sverdrup's comment that the algorithm performs extra swaps. (If n is even, it's a null swap, but if odd, it's a real swap.) The characteristic that Heap's paper desired was exactly one swap between successive permutations: "Methods for obtaining all possible permutations of a number of objects, in which each permutation differs from its predecessor only by the interchange of two of the objects, are discussed."
At stage n, it takes only n−1 swaps to place all n objects at the last position. The routine should only do n−1 iterations.
Sedgewick's talk (which uses 1-based arrays), article reference 3, ignores that issue, so his version is a variation of Heap's algorithm.
Glrx (talk) 17:57, 7 February 2016 (UTC)Reply

It is nice to have a page with this algorithm and try to follow the source fully, but it is also important to provide a nicely written and well-formed pseudo code, which can then be easily integrated into larger projects. Therefore, if you insist on avoiding an extra swap it is much better to use something like "if i<n-1" to avoid it instead of adding another "generate" call. When you use such code in your programs it is often of a big importance to have only one place where you call a function, not to bump on them here and there. The same goes for non recursive version, it is very bad to have two places for "output". The whole idea of having a non recursive version is to be easy to integrate it with some additional processing at the very place of generating the next permutation. By having more than one place for output, you practically defeated much of the convenience a non recursive version should provide. I see you try to defend your ideas to the last breath, so I will not edit this page anymore, but I had to say my opinion, and you can go as you wish. dr 24.135.83.70 (talk) 00:35, 6 August 2016 (UTC)Reply

For the sake of completeness, here is the recursive version I would suggest as better (only one call to generate): dr 24.135.83.70 (talk) 11:08, 6 August 2016 (UTC)Reply
why not use the version below in the article? Yuvalif (talk) 16:03, 15 September 2024 (UTC)Reply
procedure generate(n : integer, A : array of any):
    if n = 1 then
          output(A)
    else
        for i := 0; i < n; i += 1 do
            generate(n - 1, A)
            if i < n-1 then
                if n is even then
                    swap(A[i], A[n-1])
                else
                    swap(A[0], A[n-1])
                end if
            end if
        end for
    end if

The current implementation in the `Proof` appears to be 100% identical to the implementation in the `Frequent mis-implementations`, presumably because someone replaced it with the very mis-implementation discussed. Was it this edit? I don't understand the math quite well enough to be immediately able to tell if this edit is incorrect or not. MooingDuck (talk) 17:10, 20 November 2023 (UTC)Reply

Still confusing

edit

In the article, the text just above the recursive algorithm says the swap index is i when k is even, and is 0 when k is odd. But the pseudocode algorithm says the opposite. The pseudocode algorithm immediately above here on the talk page (as of 26-Jan-2021 04:28 UTC) seems to be correct. I implemented both and I found the pseudocode in the article to be incorrect. Can someone else confirm this? (This is my first ever Wikipedia talk, so please forgive any breaches of etiquette.) PlaidFlannel (talk) 04:36, 26 January 2021 (UTC)Reply

Still too many swaps

edit

As of 24-Aug-2017, the recursive pseudocode still does too many swaps -- for n == 4, it generates the 24 permutations, but takes 40 swaps to do it. Adding the "if i < n-1" statement to avoid the swaps at the end of the loop avoids swaps, but repeats some permutations, and fails to provide all permutations. WhackTheWiki (talk) 04:07, 25 August 2017 (UTC)Reply

Messy loop control logic

edit

The recursive Python algorithm has a really messy set of loop control logic (in the variable c). I put a much cleaner Java implementation on the main page for comparison purposes. I suggest the Python version be cleaned up to match the Java version.

Correct non recursive Algorithm

edit

The non recursive implementation of Heap's algorithm proposed in the link number 3 (Sedgewick's pdf) can't work. It seems plagued by, really, a lot of errors or typos. Meanwhile, using the ideas of the link one can get a working implementation. Unfortunately the one I get is much less stylish, not even mentioning time efficiency.

// doit() is whatever shall be done with a new permutation of the N elements of table t
void exchange(int *t,int n, int i,int j){
  int b;
  b = t[i]; t[i] = t[j]; t[j] = b;
}
void permutate(int*t, int N){
  int n,i,j;
  int c[N],tt[N];
  for(i=0; i<N; i++){
    c[i] = 0; tt[i] = t[i];}
  for(j=0;j<N;j++) {exchange(t,N,j,c[j]);}
  //doit();
  for(i=1;i<N;){
    if(c[i] < i){
      c[i]++; i=1; 
      for(j=0;j<N;j++) {t[j] = tt[j];}
      for(j=0;j<N;j++) {exchange(t,N,j,c[j]);}
      //doit();
    } else {
      c[i++] = 0;
    }
  }
}

— Preceding unsigned comment added by 192.93.101.133 (talkcontribs) 11:44 6 January 2016

The Sedgewick's non recursive algorithm has some typos in one line only. They could be easily spotted if you understand the idea. The line "exch(N % 2 ? 1 : c, N)" should read "exch(n % 2 ? 1 : c[n], n)". The second problem is that whoever converted this algorithm to this pseudo code and decided that loops go from 0, forgot that this change also inverts the condition "n%2", so the swaps should be swapped in "if i is even then". So, the corrected (and working!) version of the presented code is as follows: dr 24.135.83.70 (talk) 11:01, 6 August 2016 (UTC)Reply
procedure generate(n : integer, A : array of any):
    c : array of int

    for i := 0; i < n; i += 1 do
        c[i] := 0
    end for

    output(A)
    for i := 0; i < n; do
        if  c[i] < i then
            if i is even then
                swap(A[0], A[i])
            else
                swap(A[c[i]], A[i])
            end if
            output(A)
            c[i] += 1
            i := 0
        else
            c[i] := 0
            i += 1
        end if
    end for
The current non recursive implementation has a problem that might defeat all the benefits of its non-recursiveness, it calls "output" at two places, preventing processing without a callback function. Here is how to avoid that problem: dr 24.135.83.70 (talk) 09:51, 7 August 2016 (UTC)Reply
procedure generate(n : integer, A : array of any):
    c : array of int

    for i := 0; i < n; i += 1 do
        c[i] := 0
    end for

    for i := 0; i < n; do
        if i == 0 then
            output(A)
        end if
        if  c[i] < i then
            if i is even then
                swap(A[0], A[i])
            else
                swap(A[c[i]], A[i])
            end if
            c[i] += 1
            i := 0
        else
            c[i] := 0
            i += 1
        end if
    end for

Python generator based on pseudo code

edit
def heaps(n, a):
    if n == 1:
        yield a
    else:
        for i in range(0,n-1):
            yield from heaps(n-1, a)
            if n & 1 == 0:
                a[i], a[n-1] = a[n-1], a[i]
            else:
                a[0], a[n-1] = a[n-1], a[0]
        yield from heaps(n-1, a)

# test the heaps generator
test = list('ABCD')
heaps_generator = heaps(len(test), test)
try:
    while True:
        print(next(heaps_generator))
except:
    pass

Dmilham (talk) 18:29, 22 July 2016 (UTC)Reply

B. R. Heap

edit

I'd like to read about B. R. Heap. Is the concept of HeapSpace related to him / her? — Preceding unsigned comment added by 171.4.233.123 (talk) 07:12, 16 October 2018 (UTC)Reply

Does anybody, ANYBODY, know who B. R. Heap is? What is his name?
Is he still alive? Where did he study and with who? (We don't even know if its a man or woman!)
Here's a list of publications all authored with a colleague M.S.Lynn. The list includes the following:
  • 1964: The index of primitivity of a non-negative matrix
  • 1964: A graph-theoretic algorithm for the solution of a linear diophantine problem of frobenius
  • 1965: On a linear diophantine problem of Frobenius: an improved algorithm.
  • 1966 The Structure of Powers of Nonnegative Matrices I. The Index of Convergence.
  • 1966 The Structure of Powers of Nonnegative Matrices II. The Index of Maximum Density.
Who are these two and where are they from? פשוט pashute ♫ (talk) 07:18, 7 July 2022 (UTC)Reply

Heap data structure?

edit
In continuation with the question about B. R. Heap:
This algorithm (the Heap algorithm) has to do with A HEAP - a digital construct, studied in computer science, and called so because it somewhat resembles a mound when it is drawn as a balanced upside-down tree-shaped data-structure, as opposed to the STACK, which is depicted as vertical standing rectangle, meant to resemble a gun magazine with bullets.
So does he have anything to do with the "Heapsort" algorithm? Or to the name of the Heap data structure? פשוט pashute ♫ (talk) 07:38, 7 July 2022 (UTC)Reply

Edit request

edit

After being informed by MrOllie about a potential conflict of interest, I am now formally requesting to make the following additions to the page. The Combinatorial Object Server is a collection of open source software tools I frequently use to create this kind of illustrations illustrations, and to which I am a frequent contributor.

Add the following diagram to the page:


 
Wheel diagram of all permutations of length   generated by Heap's algorithm, where each permutation is color-coded (1=blue, 2=green, 3=yellow, 4=red).[1]

Torsten Mütze (talk) 16:27, 29 May 2019 (UTC)Reply

References

  1. ^ Mütze, Torsten; Sawada, Joe; Williams, Aaron. "Generate permutations". Combinatorial Object Server. Retrieved May 28, 2019.{{cite web}}: CS1 maint: multiple names: authors list (link)

Per David Eppstein's input at Talk:Steinhaus–Johnson–Trotter algorithm#Edit_request I think the only problem was including the reference, which in this case has been left out, since the author information resides in the image file's page.  Spintendo  00:49, 30 May 2019 (UTC) Ok. Will do as suggested. Torsten Mütze (talk) 14:46, 30 May 2019 (UTC)Reply