Jump to content

Talk:Heap's algorithm

Page contents not supported in other languages.
From Wikipedia, the free encyclopedia
This is an old revision of this page, as edited by 24.135.83.70 (talk) at 20:47, 6 August 2016 (A clarification added.). The present address (URL) is a permanent link to this revision, which may differ significantly from the current revision.

Fix needed

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

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]

Incorrect algorithm

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]
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

Correct non recursive Algorithm

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

Python generator based on pseudo code

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]