生成整数数组排列的最快方法

时间:2015-09-07 13:09:06

标签: java permutation

我想生成整数数组的所有不同排列。该数组可能包含重复项。但我想生成所有不同的排列。我尝试过下一个排列和递归方法,这些方法往往很慢。请建议。

1 个答案:

答案 0 :(得分:0)

有n! n个元素的不同排列。生成单个置换的成本是n(严格地),因此任何置换生成算法的最小成本都是O(n * n!)

Steinhaus-Johnson-Trotter算法就是其中一种算法。有像Shimon Even这样的改进以及像Heap这样的其他算法,但没有一个在O(n * n!)下得到它们

谷歌搜索"排列算法"获得了几种可以实现的不同算法,尽管大多数使用递归,这意味着另一个堆栈步骤。 Steinhaus-Johnson-Trotter被定义为迭代,因此不应该得到这个问题。

这是一个Java实现

import java.util.Arrays;
import java.util.Iterator;

/**
 * this implementation is based in Steinhaus–Johnson–Trotter algorithm and
 * Shimon Even's improvement;
 * 
 * @see https 
 *      ://en.wikipedia.org/wiki/Steinhaus%E2%80%93Johnson%E2%80%93Trotter_algorithm
 *
 */
public class Permutations implements Iterator<int[]> {
    /**
     * direction[i] = -1 if the element i has to move to the left, +1 to the
     * right, 0 if it does not need to move
     */
    private int[] direction;
    /**
     * inversePermutation[i] is the position of element i in permutation; It's
     * called inverse permutation because if p2 is the inverse permutation of
     * p1, then p1 is the inverse permutation of p2
     */
    private int[] inversePermutation;
    /**
     * current permutation
     */
    private int[] permutation;

    /**
     * @param numElements
     *            >= 1
     */
    public Permutations(int numElements) {
        // initial permutation
        permutation = new int[numElements];
        for (int i = 0; i < numElements; i++) {
            permutation[i] = i;
        }
        // the support elements
        inversePermutation = Arrays.copyOf(permutation, numElements);
        direction = new int[numElements];
        Arrays.fill(direction, -1);
        direction[0] = 0;
    }

    /**
     * Swaps the elements in array at positions i1 and i2
     * 
     * @param array
     * @param i1
     * @param i2
     */
    private static void swap(int[] array, int i1, int i2) {
        int temp = array[i1];
        array[i1] = array[i2];
        array[i2] = temp;
    }

    /**
     * prepares permutation to be the next one to return
     */
    private void buildNextPermutation() {
        // find the largest element with a nonzero direction, and swaps it in
        // the indicated direction
        int index = -1;
        for (int i = 0; i < direction.length; i++) {
            if (direction[permutation[i]] != 0
                    && (index < 0 || permutation[index] < permutation[i])) {
                index = i;
            }
        }
        if (index < 0) {
            // there are no more permutations
            permutation = null;
        } else {
            // element we're moving
            int chosenElement = permutation[index];
            // direction we're moving
            int dir = direction[chosenElement];
            // index2 is the new position of chosenElement
            int index2 = index + dir;

            // we'll swap positions elements permutation[index] and
            // permutation[index2] in permutation, to keep inversePermutation we
            // have to swap inversePermutation's elements at index
            // permutation[index] and permutation[index2]
            swap(inversePermutation, permutation[index], permutation[index2]);
            swap(permutation, index, index2);

            // update directions
            if (index2 == 0 || index2 == permutation.length - 1
                    || permutation[index2 + dir] > permutation[index2]) {
                // direction of chosen element
                direction[chosenElement] = 0;
            }

            // all elements greater that chosenElement set its direction to +1
            // if they're before index-1 or -1 if they're after
            for (int i = chosenElement + 1; i < direction.length; i++) {
                if (inversePermutation[i] > index2) {
                    direction[i] = -1;
                } else {
                    direction[i] = 1;
                }
            }
        }
    }

    @Override
    public boolean hasNext() {
        return permutation != null;
    }

    @Override
    public int[] next() {
        int[] result = Arrays.copyOf(permutation, permutation.length);
        buildNextPermutation();
        return result;
    }
}