📜  迭代方法来打印数组的所有排列

📅  最后修改于: 2021-04-21 23:47:37             🧑  作者: Mango

给定大小为N的数组arr [] ,任务是生成并打印给定数组的所有排列。

例子:

方法:这里和这里讨论解决上述问题的递归方法。在这篇文章中,将讨论一种输出给定数组的所有排列的迭代方法。
迭代方法充当状态机。调用机器时,它将输出排列并移至下一个排列。

首先,我们需要一个整数数组Indexes来存储输入数组的所有索引,并且将数组Indexes中的值初始化为0n – 1 。我们需要做的是置换Indexes数组。

在迭代过程中,我们在Indexes数组中找到最小的index增量,使得Indexes [Increase] ,这是第一个“值增加”。然后,我们有了Indexes [0]> Indexes [1]> Indexes [2]>…> Indexes [Increase] ,这是从index [0]开始递减的值。下一步将是:

  1. 找到索引mid ,以使Indexes [mid]最大,并且约束条件为0≤mid≤增加,并且Indexs [mid] ;由于数组索引0到反向递增排序,因此此步骤可以使用二进制搜索。
  2. 交换索引[Increase + 1]索引[mid]
  3. 索引[0]反向索引[Increase]

索引中的值变为n – 10时,就没有“值增加”,并且算法终止。

为了输出组合,我们遍历索引数组,而整数数组的值就是输入数组的索引。

下图说明了算法中的迭代。

下面是上述方法的实现:

C++
// C++ implementation of the approach
#include 
using namespace std;
  
template 
class AllPermutation {
private:
    // The input array for permutation
    const T* Arr;
  
    // Length of the input array
    const int Length;
  
    // Index array to store indexes of input array
    int* Indexes;
  
    // The index of the first "increase"
    // in the Index array which is the smallest
    // i such that Indexes[i] < Indexes[i + 1]
    int Increase;
  
public:
    // Constructor
    AllPermutation(T* arr, int length)
        : Arr(arr), Length(length)
    {
        this->Indexes = nullptr;
        this->Increase = -1;
    }
  
    // Destructor
    ~AllPermutation()
    {
        if (this->Indexes != nullptr) {
            delete[] this->Indexes;
        }
    }
  
    // Initialize and output
    // the first permutation
    void GetFirst()
    {
  
        // Allocate memory for Indexes array
        this->Indexes = new int[this->Length];
  
        // Initialize the values in Index array
        // from 0 to n - 1
        for (int i = 0; i < this->Length; ++i) {
            this->Indexes[i] = i;
        }
  
        // Set the Increase to 0
        // since Indexes[0] = 0 < Indexes[1] = 1
        this->Increase = 0;
  
        // Output the first permutation
        this->Output();
    }
  
    // Function that returns true if it is
    // possible to generate the next permutation
    bool HasNext()
    {
  
        // When Increase is in the end of the array,
        // it is not possible to have next one
        return this->Increase != (this->Length - 1);
    }
  
    // Output the next permutation
    void GetNext()
    {
  
        // Increase is at the very beginning
        if (this->Increase == 0) {
  
            // Swap Index[0] and Index[1]
            this->Swap(this->Increase, this->Increase + 1);
  
            // Update Increase
            this->Increase += 1;
            while (this->Increase < this->Length - 1
                   && this->Indexes[this->Increase]
                          > this->Indexes[this->Increase + 1]) {
                ++this->Increase;
            }
        }
        else {
  
            // Value at Indexes[Increase + 1] is greater than Indexes[0]
            // no need for binary search,
            // just swap Indexes[Increase + 1] and Indexes[0]
            if (this->Indexes[this->Increase + 1] > this->Indexes[0]) {
                this->Swap(this->Increase + 1, 0);
            }
            else {
  
                // Binary search to find the greatest value
                // which is less than Indexes[Increase + 1]
                int start = 0;
                int end = this->Increase;
                int mid = (start + end) / 2;
                int tVal = this->Indexes[this->Increase + 1];
                while (!(this->Indexes[mid] < tVal
                         && this->Indexes[mid - 1] > tVal)) {
                    if (this->Indexes[mid] < tVal) {
                        end = mid - 1;
                    }
                    else {
                        start = mid + 1;
                    }
                    mid = (start + end) / 2;
                }
  
                // Swap
                this->Swap(this->Increase + 1, mid);
            }
  
            // Invert 0 to Increase
            for (int i = 0; i <= this->Increase / 2; ++i) {
                this->Swap(i, this->Increase - i);
            }
  
            // Reset Increase
            this->Increase = 0;
        }
        this->Output();
    }
  
private:
    // Function to output the input array
    void Output()
    {
        for (int i = 0; i < this->Length; ++i) {
  
            // Indexes of the input array
            // are at the Indexes array
            cout << (this->Arr[this->Indexes[i]]) << " ";
        }
        cout << endl;
    }
  
    // Swap two values in the Indexes array
    void Swap(int p, int q)
    {
        int tmp = this->Indexes[p];
        this->Indexes[p] = this->Indexes[q];
        this->Indexes[q] = tmp;
    }
};
  
// Driver code
int main()
{
    int arr[] = { 0, 1, 2 };
    AllPermutation perm(arr, sizeof(arr) / sizeof(int));
    perm.GetFirst();
    while (perm.HasNext()) {
        perm.GetNext();
    }
  
    return 0;
}


Java
// Java implementation of the approach
class AllPermutation 
{
  
    // The input array for permutation
    private final int Arr[];
  
    // Index array to store indexes of input array
    private int Indexes[];
  
    // The index of the first "increase"
    // in the Index array which is the smallest
    // i such that Indexes[i] < Indexes[i + 1]
    private int Increase;
  
    // Constructor
    public AllPermutation(int arr[])
    {
        this.Arr = arr;
        this.Increase = -1;
        this.Indexes = new int[this.Arr.length];
    }
  
    // Initialize and output
    // the first permutation
    public void GetFirst()
    {
  
        // Allocate memory for Indexes array
        this.Indexes = new int[this.Arr.length];
  
        // Initialize the values in Index array
        // from 0 to n - 1
        for (int i = 0; i < Indexes.length; ++i) 
        {
            this.Indexes[i] = i;
        }
  
        // Set the Increase to 0
        // since Indexes[0] = 0 < Indexes[1] = 1
        this.Increase = 0;
  
        // Output the first permutation
        this.Output();
    }
  
    // Function that returns true if it is
    // possible to generate the next permutation
    public boolean HasNext()
    {
  
        // When Increase is in the end of the array,
        // it is not possible to have next one
        return this.Increase != (this.Indexes.length - 1);
    }
  
    // Output the next permutation
    public void GetNext()
    {
  
        // Increase is at the very beginning
        if (this.Increase == 0) 
        {
  
            // Swap Index[0] and Index[1]
            this.Swap(this.Increase, this.Increase + 1);
  
            // Update Increase
            this.Increase += 1;
            while (this.Increase < this.Indexes.length - 1
                && this.Indexes[this.Increase]
                        > this.Indexes[this.Increase + 1]) 
            {
                ++this.Increase;
            }
        }
        else
        {
  
            // Value at Indexes[Increase + 1] is greater than Indexes[0]
            // no need for binary search,
            // just swap Indexes[Increase + 1] and Indexes[0]
            if (this.Indexes[this.Increase + 1] > this.Indexes[0]) 
            {
                this.Swap(this.Increase + 1, 0);
            }
            else
            {
  
                // Binary search to find the greatest value
                // which is less than Indexes[Increase + 1]
                int start = 0;
                int end = this.Increase;
                int mid = (start + end) / 2;
                int tVal = this.Indexes[this.Increase + 1];
                while (!(this.Indexes[mid] tVal)) 
                {
                    if (this.Indexes[mid] < tVal)
                    {
                        end = mid - 1;
                    }
                    else 
                    {
                        start = mid + 1;
                    }
                    mid = (start + end) / 2;
                }
  
                // Swap
                this.Swap(this.Increase + 1, mid);
            }
  
            // Invert 0 to Increase
            for (int i = 0; i <= this.Increase / 2; ++i)
            {
                this.Swap(i, this.Increase - i);
            }
  
            // Reset Increase
            this.Increase = 0;
        }
        this.Output();
    }
  
    // Function to output the input array
    private void Output()
    {
        for (int i = 0; i < this.Indexes.length; ++i) 
        {
  
            // Indexes of the input array
            // are at the Indexes array
            System.out.print(this.Arr[this.Indexes[i]]);
            System.out.print(" ");
        }
        System.out.println();
    }
  
    // Swap two values in the Indexes array
    private void Swap(int p, int q)
    {
        int tmp = this.Indexes[p];
        this.Indexes[p] = this.Indexes[q];
        this.Indexes[q] = tmp;
    }
}
  
// Driver code
class AppDriver 
{
    public static void main(String args[])
    {
        int[] arr = { 0, 1, 2 };
          
        AllPermutation perm = new AllPermutation(arr);
        perm.GetFirst();
        while (perm.HasNext())
        {
            perm.GetNext();
        }
    }
}
  
// This code is contributed by ghanshyampandey


C#
// C# implementation of the approach
using System;
namespace Permutation {
  
class AllPermutation {
  
    // The input array for permutation
    private readonly T[] Arr;
  
    // Index array to store indexes of input array
    private int[] Indexes;
  
    // The index of the first "increase"
    // in the Index array which is the smallest
    // i such that Indexes[i] < Indexes[i + 1]
    private int Increase;
  
    // Constructor
    public AllPermutation(T[] arr)
    {
        this.Arr = arr;
        this.Increase = -1;
    }
  
    // Initialize and output
    // the first permutation
    public void GetFirst()
    {
  
        // Allocate memory for Indexes array
        this.Indexes = new int[this.Arr.Length];
  
        // Initialize the values in Index array
        // from 0 to n - 1
        for (int i = 0; i < Indexes.Length; ++i) {
            this.Indexes[i] = i;
        }
  
        // Set the Increase to 0
        // since Indexes[0] = 0 < Indexes[1] = 1
        this.Increase = 0;
  
        // Output the first permutation
        this.Output();
    }
  
    // Function that returns true if it is
    // possible to generate the next permutation
    public bool HasNext()
    {
  
        // When Increase is in the end of the array,
        // it is not possible to have next one
        return this.Increase != (this.Indexes.Length - 1);
    }
  
    // Output the next permutation
    public void GetNext()
    {
  
        // Increase is at the very beginning
        if (this.Increase == 0) {
  
            // Swap Index[0] and Index[1]
            this.Swap(this.Increase, this.Increase + 1);
  
            // Update Increase
            this.Increase += 1;
            while (this.Increase < this.Indexes.Length - 1
                   && this.Indexes[this.Increase]
                          > this.Indexes[this.Increase + 1]) {
                ++this.Increase;
            }
        }
        else {
  
            // Value at Indexes[Increase + 1] is greater than Indexes[0]
            // no need for binary search,
            // just swap Indexes[Increase + 1] and Indexes[0]
            if (this.Indexes[this.Increase + 1] > this.Indexes[0]) {
                this.Swap(this.Increase + 1, 0);
            }
            else {
  
                // Binary search to find the greatest value
                // which is less than Indexes[Increase + 1]
                int start = 0;
                int end = this.Increase;
                int mid = (start + end) / 2;
                int tVal = this.Indexes[this.Increase + 1];
                while (!(this.Indexes[mid] tVal)) {
                    if (this.Indexes[mid] < tVal) {
                        end = mid - 1;
                    }
                    else {
                        start = mid + 1;
                    }
                    mid = (start + end) / 2;
                }
  
                // Swap
                this.Swap(this.Increase + 1, mid);
            }
  
            // Invert 0 to Increase
            for (int i = 0; i <= this.Increase / 2; ++i) {
                this.Swap(i, this.Increase - i);
            }
  
            // Reset Increase
            this.Increase = 0;
        }
        this.Output();
    }
  
    // Function to output the input array
    private void Output()
    {
        for (int i = 0; i < this.Indexes.Length; ++i) {
  
            // Indexes of the input array
            // are at the Indexes array
            Console.Write(this.Arr[this.Indexes[i]]);
            Console.Write(" ");
        }
        Console.WriteLine();
    }
  
    // Swap two values in the Indexes array
    private void Swap(int p, int q)
    {
        int tmp = this.Indexes[p];
        this.Indexes[p] = this.Indexes[q];
        this.Indexes[q] = tmp;
    }
}
  
// Driver code
class AppDriver {
    static void Main()
    {
        int[] arr = { 0, 1, 2 };
        AllPermutation perm = new AllPermutation(arr);
        perm.GetFirst();
        while (perm.HasNext()) {
            perm.GetNext();
        }
    }
}
}


输出:
0 1 2 
1 0 2 
0 2 1 
2 0 1 
1 2 0 
2 1 0