Iterative approach to print all combinations of an Array

Given an array arr[] of size N, the task is to generate and print all possible combinations of R elements in array.

Examples:

Input: arr[] = {0, 1, 2, 3}, R = 3
Output:
0 1 2
0 1 3
0 2 3
1 2 3

Input: arr[] = {1, 3, 4, 5, 6, 7}, R = 5
Output:
1 3 4 5 6
1 3 4 5 7
1 3 4 6 7
1 3 5 6 7
1 4 5 6 7
3 4 5 6 7

Approach: Recursive methods are discussed here. In this post, an iterative method to output all combinations for a given array will be discussed.
The iterative method acts as a state machine. When the machine is called, it outputs a combination and move to the next one.
For a combination of r elements from an array of size n, a given element may be included or excluded from the combination.
Let’s have a Boolean array of size n to label whether the corresponding element in data array is included. If the ith element in the data array is included, then the ith element in the boolean array is true or false otherwise.
Then, r booleans in the boolean array will be labelled as true. We can initialize the boolean array to have r trues from index 0 to index r – 1. During the iteration, we scan the boolean array from left to right and find the first element which is true and whose previous one is false and the first element which is true and whose next one is false.
Then, we have the first continuous tract of trues in the Boolean array. Assume there are m trues in this tract, starting from index Start and ending at index End. The next iteration would be

  1. Set index End + 1 of the boolean array to true.
  2. Set index Start to index End – 1 of the boolean array to false.
  3. Set index 0 to index k – 2 to true.

For example,
If the current boolean array is {0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0}, then k = 4, Start = 2, and End = 5. The next Boolean array would be {1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0}. In case Start == End where there is only one true in the tract, we simply set index End to false and index End + 1 to true.
We also need to record the current Start and End and update Start and End during each iteration. When the last r booleans are set to true, we cannot move to the next combination and we stop.

The following image illustrates how the boolean array changes from one iteration to another.

To output the combination, we just scan the boolean array. If its ith index is true, we print out the ith element of the data array.

Below is the implementation of the above approach:

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ implementation of the approach
#include <iostream>
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;
}

chevron_right


C#

filter_none

edit
close

play_arrow

link
brightness_4
code

// 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();
    }
}
  
// Drive 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();
        }
    }
}
}

chevron_right


Output:

0 1 2 
0 1 3 
0 2 3 
1 2 3


My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.