📜  迭代方法打印数组的所有组合

📅  最后修改于: 2021-04-28 14:14:24             🧑  作者: Mango

给定大小为N的数组arr [] ,任务是生成并打印数组中R元素的所有可能组合。

例子:

方法:这里讨论递归方法。在这篇文章中,将讨论一种输出给定数组的所有组合的迭代方法。
迭代方法充当状态机。调用机器时,它输出一个组合并移至下一个组合。
对于大小为n的数组中r个元素的组合,给定元素可以包括在组合中,也可以从该组合中排除。
让我们有一个大小为n的布尔数组,以标记是否包含数据数组中的相应元素。如果数据阵列中的第i个元素被包括,则布尔阵列中的第i个元素是真还是假,否则。
然后,布尔数组中的r布尔值将被标记为true。我们可以将布尔数组初始化为从索引0到索引r – 1的r trues。在迭代过程中,我们从左到右扫描布尔数组,找到第一个为true且一个为false的元素和第一个为true且一个为false的元素。
然后,我们在布尔数组中具有第一个连续的true。假设从索引Start开始到索引End结束,该段中有m个true。下一个迭代将是

  1. 将布尔数组的索引End + 1设置为true。
  2. 将index Start设置为index End –布尔数组的1为false。
  3. 将索引0设置为索引k – 2设置为true。

例如
如果当前布尔数组为{ 0,0,1,1,1,1,0,0,0,1,0,0 } ,则k = 4Start = 2End = 5 。下一个布尔数组将为{1、1、1、0、0、0、1、0、0、1、0、0} 。如果Start == End的区域中只有一个真值,我们只需将index End设置为false并将index End + 1设置为true。
我们还需要记录当前的“开始”和“结束” ,并在每次迭代过程中更新“开始”和“结束” 。当最后的R布尔值设置为true,我们不能移动到下一个组合,我们停下来。

下图说明了布尔数组如何从一个迭代变为另一个迭代。

要输出组合,我们只需扫描布尔数组。如果其第i个索引为true,则打印出数据数组的第i个元素。

下面是上述方法的实现:

C++
// C++ implementation of the approach
#include 
using namespace std;
  
class Combination {
private:
    // Data array for combination
    int* Indices;
  
    // Length of the data array
    int N;
  
    // Number of elements in the combination
    int R;
  
    // The boolean array
    bool* Flags;
  
    // Starting index of the 1st tract of trues
    int Start;
  
    // Ending index of the 1st tract of trues
    int End;
  
public:
    // Constructor
    Combination(int* arr, int n, int r)
    {
        this->Indices = arr;
        this->N = n;
        this->R = r;
        this->Flags = nullptr;
    }
    ~Combination()
    {
        if (this->Flags != nullptr) {
            delete[] this->Flags;
        }
    }
  
    // Set the 1st r Booleans to true,
    // initialize Start and End
    void GetFirst()
    {
        this->Flags = new bool[N];
  
        // Generate the very first combination
        for (int i = 0; i < this->N; ++i) {
            if (i < this->R) {
                Flags[i] = true;
            }
            else {
                Flags[i] = false;
            }
        }
  
        // Update the starting ending indices
        // of trues in the boolean array
        this->Start = 0;
        this->End = this->R - 1;
        this->Output();
    }
  
    // Function that returns true if another
    // combination can still be generated
    bool HasNext()
    {
        return End < (this->N - 1);
    }
  
    // Function to generate the next combination
    void Next()
    {
  
        // Only one true in the tract
        if (this->Start == this->End) {
            this->Flags[this->End] = false;
            this->Flags[this->End + 1] = true;
            this->Start += 1;
            this->End += 1;
            while (this->End + 1 < this->N
                   && this->Flags[this->End + 1]) {
                ++this->End;
            }
        }
        else {
  
            // Move the End and reset the End
            if (this->Start == 0) {
                Flags[this->End] = false;
                Flags[this->End + 1] = true;
                this->End -= 1;
            }
            else {
                Flags[this->End + 1] = true;
  
                // Set all the values to false starting from
                // index Start and ending at index End
                // in the boolean array
                for (int i = this->Start; i <= this->End; ++i) {
                    Flags[i] = false;
                }
  
                // Set the beginning elements to true
                for (int i = 0; i < this->End - this->Start; ++i) {
                    Flags[i] = true;
                }
  
                // Reset the End
                this->End = this->End - this->Start - 1;
                this->Start = 0;
            }
        }
        this->Output();
    }
  
private:
    // Function to print the combination generated previouslt
    void Output()
    {
        for (int i = 0, count = 0; i < this->N
                                   && count < this->R;
             ++i) {
  
            // If current index is set to true in the boolean array
            // then element at current index in the original array
            // is part of the combination generated previously
            if (Flags[i]) {
                cout << Indices[i] << " ";
                ++count;
            }
        }
        cout << endl;
    }
};
  
// Driver code
int main()
{
    int arr[] = { 0, 1, 2, 3 };
    int n = sizeof(arr) / sizeof(int);
    int r = 3;
    Combination com(arr, n, r);
    com.GetFirst();
    while (com.HasNext()) {
        com.Next();
    }
    return 0;
}


Java
// Java implementation of the approach
class Combination 
{
  
    // Data array for combination
    private int[] Indices;
  
    // Number of elements in the combination
    private int R;
  
    // The boolean array
    private boolean[] Flags;
  
    // Starting index of the 1st tract of trues
    private int Start;
  
    // Ending index of the 1st tract of trues
    private int End;
  
    // Constructor
    public Combination(int[] arr, int r)
    {
        this.Indices = arr;
        this.R = r;
    }
  
    // Set the 1st r Booleans to true,
    // initialize Start and End
    public void GetFirst()
    {
        Flags = new boolean[this.Indices.length];
  
        // Generate the very first combination
        for (int i = 0; i < this.R; ++i) 
        {
            Flags[i] = true;
        }
  
        // Update the starting ending indices
        // of trues in the boolean array
        this.Start = 0;
        this.End = this.R - 1;
        this.Output();
    }
  
    // Function that returns true if another
    // combination can still be generated
    public boolean HasNext()
    {
        return End < (this.Indices.length - 1);
    }
  
    // Function to generate the next combination
    public void Next()
    {
  
        // Only one true in the tract
        if (this.Start == this.End)
        {
            this.Flags[this.End] = false;
            this.Flags[this.End + 1] = true;
            this.Start += 1;
            this.End += 1;
            while (this.End + 1 < this.Indices.length
                && this.Flags[this.End + 1]) 
            {
                ++this.End;
            }
        }
        else 
        {
  
            // Move the End and reset the End
            if (this.Start == 0)
            {
                Flags[this.End] = false;
                Flags[this.End + 1] = true;
                this.End -= 1;
            }
            else 
            {
                Flags[this.End + 1] = true;
  
                // Set all the values to false starting from
                // index Start and ending at index End
                // in the boolean array
                for (int i = this.Start; i <= this.End; ++i)
                {
                    Flags[i] = false;
                }
  
                // Set the beginning elements to true
                for (int i = 0; i < this.End - this.Start; ++i) 
                {
                    Flags[i] = true;
                }
  
                // Reset the End
                this.End = this.End - this.Start - 1;
                this.Start = 0;
            }
        }
        this.Output();
    }
  
    // Function to print the combination generated previouslt
    private void Output()
    {
        for (int i = 0, count = 0; i < Indices.length
                                && count < this.R; ++i)
        {
  
            // If current index is set to true in the boolean array
            // then element at current index in the original array
            // is part of the combination generated previously
            if (Flags[i]) 
            {
                System.out.print(Indices[i]);
                System.out.print(" ");
                ++count;
            }
        }
        System.out.println();
    }
}
  
// Driver code
class GFG 
{
    public static void main(String[] args)
    {
        int[] arr = { 0, 1, 2, 3 };
        int r = 3;
        Combination com = new Combination(arr, r);
        com.GetFirst();
        while (com.HasNext())
        {
            com.Next();
        }
    }
}
  
// This code is contributed by Rajput-Ji


C#
// C# implementation of the approach
using System;
namespace IterativeCombination {
class Combination {
  
    // Data array for combination
    private int[] Indices;
  
    // Number of elements in the combination
    private int R;
  
    // The boolean array
    private bool[] Flags;
  
    // Starting index of the 1st tract of trues
    private int Start;
  
    // Ending index of the 1st tract of trues
    private int End;
  
    // Constructor
    public Combination(int[] arr, int r)
    {
        this.Indices = arr;
        this.R = r;
    }
  
    // Set the 1st r Booleans to true,
    // initialize Start and End
    public void GetFirst()
    {
        Flags = new bool[this.Indices.Length];
  
        // Generate the very first combination
        for (int i = 0; i < this.R; ++i) {
            Flags[i] = true;
        }
  
        // Update the starting ending indices
        // of trues in the boolean array
        this.Start = 0;
        this.End = this.R - 1;
        this.Output();
    }
  
    // Function that returns true if another
    // combination can still be generated
    public bool HasNext()
    {
        return End < (this.Indices.Length - 1);
    }
  
    // Function to generate the next combination
    public void Next()
    {
  
        // Only one true in the tract
        if (this.Start == this.End) {
            this.Flags[this.End] = false;
            this.Flags[this.End + 1] = true;
            this.Start += 1;
            this.End += 1;
            while (this.End + 1 < this.Indices.Length
                   && this.Flags[this.End + 1]) {
                ++this.End;
            }
        }
        else {
  
            // Move the End and reset the End
            if (this.Start == 0) {
                Flags[this.End] = false;
                Flags[this.End + 1] = true;
                this.End -= 1;
            }
            else {
                Flags[this.End + 1] = true;
  
                // Set all the values to false starting from
                // index Start and ending at index End
                // in the boolean array
                for (int i = this.Start; i <= this.End; ++i) {
                    Flags[i] = false;
                }
  
                // Set the beginning elements to true
                for (int i = 0; i < this.End - this.Start; ++i) {
                    Flags[i] = true;
                }
  
                // Reset the End
                this.End = this.End - this.Start - 1;
                this.Start = 0;
            }
        }
        this.Output();
    }
  
    // Function to print the combination generated previouslt
    private void Output()
    {
        for (int i = 0, count = 0; i < Indices.Length
                                   && count < this.R;
             ++i) {
  
            // If current index is set to true in the boolean array
            // then element at current index in the original array
            // is part of the combination generated previously
            if (Flags[i]) {
                Console.Write(Indices[i]);
                Console.Write(" ");
                ++count;
            }
        }
        Console.WriteLine();
    }
}
  
// Driver code
class AppDriver {
    static void Main()
    {
        int[] arr = { 0, 1, 2, 3 };
        int r = 3;
        Combination com = new Combination(arr, r);
        com.GetFirst();
        while (com.HasNext()) {
            com.Next();
        }
    }
}
}


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