web-dev-qa-db-fra.com

Obtention de la puissance d'un ensemble en Java

Le pouvoir de {1, 2, 3} est:

{{}, {2}, {3}, {2, 3}, {1, 2}, {1, 3}, {1, 2, 3}, {1}}

Disons que j'ai une Set en Java:

Set<Integer> mySet = new HashSet<Integer>();
mySet.add(1);
mySet.add(2);
mySet.add(3);
Set<Set<Integer>> powerSet = getPowerset(mySet);

Comment puis-je écrire la fonction getPowerset, avec le meilleur ordre possible de complexité?

84
Manuel Aráoz

Oui, il s'agit bien de O(2^n), car vous devez générer, bien, 2^n des combinaisons possibles. Voici une implémentation qui fonctionne, utilisant des génériques et des ensembles:

public static <T> Set<Set<T>> powerSet(Set<T> originalSet) {
    Set<Set<T>> sets = new HashSet<Set<T>>();
    if (originalSet.isEmpty()) {
        sets.add(new HashSet<T>());
        return sets;
    }
    List<T> list = new ArrayList<T>(originalSet);
    T head = list.get(0);
    Set<T> rest = new HashSet<T>(list.subList(1, list.size())); 
    for (Set<T> set : powerSet(rest)) {
        Set<T> newSet = new HashSet<T>();
        newSet.add(head);
        newSet.addAll(set);
        sets.add(newSet);
        sets.add(set);
    }       
    return sets;
}  

Et un test, à partir de votre exemple d'entrée:

 Set<Integer> mySet = new HashSet<Integer>();
 mySet.add(1);
 mySet.add(2);
 mySet.add(3);
 for (Set<Integer> s : SetUtils.powerSet(mySet)) {
     System.out.println(s);
 }
95
João Silva

En fait, j'ai écrit un code qui fait ce que vous demandez dans O (1). La question est de savoir ce que vous prévoyez de faire {faire avec le prochain set. Si vous appelez simplement size() dessus, c’est O (1), mais si vous voulez le répéter, il est évident que O(2^n).

contains() serait O(n), etc.

Avez-vous vraiment besoin de ça?

MODIFIER:

Ce code est maintenant disponible dans Guava , exposé via la méthode Sets.powerSet(set) .

29

Voici une solution où j'utilise un générateur, l'avantage étant que tout le jeu de puissance n'est jamais stocké à la fois ... Vous pouvez donc le parcourir un par un sans avoir besoin de le stocker en mémoire. J'aimerais penser que c'est une meilleure option ... Notez que la complexité est la même, O (2 ^ n), mais que la mémoire requise est réduite (en supposant que le ramasse-miettes se comporte bien!;))

/**
 *
 */
package org.mechaevil.util.Algorithms;

import Java.util.BitSet;
import Java.util.Iterator;
import Java.util.Set;
import Java.util.TreeSet;

/**
 * @author st0le
 *
 */
public class PowerSet<E> implements Iterator<Set<E>>,Iterable<Set<E>>{
    private E[] arr = null;
    private BitSet bset = null;

    @SuppressWarnings("unchecked")
    public PowerSet(Set<E> set)
    {
        arr = (E[])set.toArray();
        bset = new BitSet(arr.length + 1);
    }

    @Override
    public boolean hasNext() {
        return !bset.get(arr.length);
    }

    @Override
    public Set<E> next() {
        Set<E> returnSet = new TreeSet<E>();
        for(int i = 0; i < arr.length; i++)
        {
            if(bset.get(i))
                returnSet.add(arr[i]);
        }
        //increment bset
        for(int i = 0; i < bset.size(); i++)
        {
            if(!bset.get(i))
            {
                bset.set(i);
                break;
            }else
                bset.clear(i);
        }

        return returnSet;
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException("Not Supported!");
    }

    @Override
    public Iterator<Set<E>> iterator() {
        return this;
    }

}

Pour l'appeler, utilisez ce modèle:

        Set<Character> set = new TreeSet<Character> ();
        for(int i = 0; i < 5; i++)
            set.add((char) (i + 'A'));

        PowerSet<Character> pset = new PowerSet<Character>(set);
        for(Set<Character> s:pset)
        {
            System.out.println(s);
        }

C'est de ma bibliothèque Project Euler ... :)

11
st0le

Si n <63, ce qui est une hypothèse raisonnable car vous manqueriez de mémoire (à moins d'utiliser une implémentation d'itérateur) en essayant de construire le jeu de pouvoir de toute façon, c'est une façon plus concise de le faire. Les opérations binaires sont bien plus rapides que Math.pow() et les tableaux de masques, mais les utilisateurs de Java en ont peur ...

List<T> list = new ArrayList<T>(originalSet);
int n = list.size();

Set<Set<T>> powerSet = new HashSet<Set<T>>();

for( long i = 0; i < (1 << n); i++) {
    Set<T> element = new HashSet<T>();
    for( int j = 0; j < n; j++ )
        if( (i >> j) % 2 == 1 ) element.add(list.get(j));
    powerSet.add(element); 
}

return powerSet;
10
Andrew Mao

Ici est un tutoriel décrivant exactement ce que vous voulez, y compris le code. Vous avez raison de dire que la complexité est O (2 ^ n).

9
Adamski

J'ai proposé une autre solution basée sur les idées de @Harry He's. Probablement pas le plus élégant, mais voici ce que je comprends:

Prenons l'exemple simple classique PowerSet of S P(S) = {{1}, {2}, {3}} . Nous savons que la formule pour obtenir le nombre de sous-ensembles est 2 ^ n ( 7 + ensemble vide). Pour cet exemple, 2 ^ 3 = 8 sous-ensembles.

Afin de trouver chaque sous-ensemble, nous devons convertir 0-7 décimal en représentation binaire comme indiqué dans le tableau de conversion ci-dessous:

ConversionTable

Si nous parcourons la table ligne par ligne, chaque ligne donnera un sous-ensemble et les valeurs de chaque sous-ensemble proviendront des bits activés. 

Chaque colonne de la section Valeur du bac correspond à la position d'index dans l'ensemble d'entrée d'origine. 

Voici mon code:

public class PowerSet {

/**
 * @param args
 */
public static void main(String[] args) {
    PowerSet ps = new PowerSet();
    Set<Integer> set = new HashSet<Integer>();
    set.add(1);
    set.add(2);
    set.add(3);
    for (Set<Integer> s : ps.powerSet(set)) {
        System.out.println(s);
    }
}

public Set<Set<Integer>> powerSet(Set<Integer> originalSet) {
    // Original set size e.g. 3
    int size = originalSet.size();
    // Number of subsets 2^n, e.g 2^3 = 8
    int numberOfSubSets = (int) Math.pow(2, size);
    Set<Set<Integer>> sets = new HashSet<Set<Integer>>();
    ArrayList<Integer> originalList = new ArrayList<Integer>(originalSet);
    for (int i = 0; i < numberOfSubSets; i++) {
        // Get binary representation of this index e.g. 010 = 2 for n = 3
        String bin = getPaddedBinString(i, size);
        //Get sub-set
        Set<Integer> set = getSet(bin, originalList));
        sets.add(set);
    }
    return sets;
}

//Gets a sub-set based on the binary representation. E.g. for 010 where n = 3 it will bring a new Set with value 2
private Set<Integer> getSet(String bin, List<Integer> origValues){
    Set<Integer> result = new HashSet<Integer>();
    for(int i = bin.length()-1; i >= 0; i--){
        //Only get sub-sets where bool flag is on
        if(bin.charAt(i) == '1'){
            int val = origValues.get(i);
            result.add(val);
        }
    }
    return result;
}

//Converts an int to Bin and adds left padding to zero's based on size
private String getPaddedBinString(int i, int size) {
    String bin = Integer.toBinaryString(i);
    bin = String.format("%0" + size + "d", Integer.parseInt(bin));
    return bin;
}

}
7
Adolfo Perez

Si vous utilisez Collections Eclipse (anciennement GS Collections ), vous pouvez utiliser la méthode powerSet() sur tous les SetIterables.

MutableSet<Integer> set = UnifiedSet.newSetWith(1, 2, 3);
System.out.println("powerSet = " + set.powerSet());
// prints: powerSet = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]

Note: Je suis un partisan des collections Eclipse.

5
Craig P. Motlin

Je cherchais une solution qui ne soit pas aussi énorme que celles affichées ici. Ceci cible Java 7, il faudra donc une poignée de pâtes pour les versions 5 et 6.

Set<Set<Object>> powerSetofNodes(Set<Object> orig) {
    Set<Set<Object>> powerSet = new HashSet<>(),
        runSet = new HashSet<>(),
        thisSet = new HashSet<>();

    while (powerSet.size() < (Math.pow(2, orig.size())-1)) {
        if (powerSet.isEmpty()) {
            for (Object o : orig) {
                Set<Object> s = new TreeSet<>();
                s.add(o);
                runSet.add(s);
                powerSet.add(s);
            }
            continue;
        }
        for (Object o : orig) {
            for (Set<Object> s : runSet) {
                Set<Object> s2 = new TreeSet<>();
                s2.addAll(s);
                s2.add(o);
                powerSet.add(s2);
                thisSet.add(s2);
            }
        }
        runSet.clear();
        runSet.addAll(thisSet);
        thisSet.clear();
    }
    powerSet.add(new TreeSet());
    return powerSet;

Voici un exemple de code à tester:

Set<Object> hs = new HashSet<>();
hs.add(1);
hs.add(2);
hs.add(3);
hs.add(4);
for(Set<Object> s : powerSetofNodes(hs)) {
    System.out.println(Arrays.toString(s.toArray()));
}
4
Ben

La solution suivante est empruntée à mon livre " Coding Interviews: Questions, Analysis & Solutions ":

Certains entiers dans un tableau sont sélectionnés et composent une combinaison. Un ensemble de bits est utilisé, chaque bit représentant un entier dans le tableau. Si le i-ème caractère est sélectionné pour une combinaison, le bit i-ème est à 1; sinon, il est 0. Par exemple, trois bits sont utilisés pour les combinaisons du tableau [1, 2, 3]. Si les deux premiers nombres entiers 1 et 2 sont sélectionnés pour composer une combinaison [1, 2], les bits correspondants sont {1, 1, 0}. De même, les bits correspondant à une autre combinaison [1, 3] sont {1, 0, 1}. Nous pouvons obtenir toutes les combinaisons d'un tableau de longueur n si nous pouvons obtenir toutes les combinaisons possibles de n bits.

Un nombre est composé d'un ensemble de bits. Toutes les combinaisons possibles de n bits correspondent à des nombres .__ de 1 à 2 ^ n -1. Par conséquent, chaque nombre compris entre 1 et 2 ^ n -1 correspond à la combinaison d'un tableau de longueur n. Par exemple, le nombre 6 est composé des bits {1, 1, 0}, de sorte que les premier et deuxième caractères sont sélectionnés dans le tableau [1, 2, 3] pour générer la combinaison [1, 2]. De même, le nombre 5 avec les bits {1, 0, 1} correspond à la combinaison [1, 3].

Le code Java pour implémenter cette solution se présente comme suit:

public static ArrayList<ArrayList<Integer>> powerSet(int[] numbers) {
    ArrayList<ArrayList<Integer>> combinations = new ArrayList<ArrayList<Integer>>(); 
    BitSet bits = new BitSet(numbers.length);
    do{
        combinations.add(getCombination(numbers, bits));
    }while(increment(bits, numbers.length));

    return combinations;
}

private static boolean increment(BitSet bits, int length) {
    int index = length - 1;

    while(index >= 0 && bits.get(index)) {
        bits.clear(index);
        --index;
    }

    if(index < 0)
        return false;

    bits.set(index);
    return true;
}

private static ArrayList<Integer> getCombination(int[] numbers, BitSet bits){
    ArrayList<Integer> combination = new ArrayList<Integer>();
    for(int i = 0; i < numbers.length; ++i) {
        if(bits.get(i))
            combination.add(numbers[i]);
    }

    return combination;
}

L'incrément de méthode augmente un nombre représenté dans un ensemble de bits. L'algorithme efface 1 bit Du bit le plus à droite jusqu'à ce qu'un bit 0 soit trouvé. Il règle ensuite le bit 0 le plus à droite sur 1. Par exemple, pour augmenter le nombre 5 avec les bits {1, 0, 1}, il efface 1 bits du côté droit et définit le bit 0 le plus à droite sur 1. Les bits deviennent {1, 1, 0} pour le nombre 6, résultat de l'augmentation de 5 par 1.

3
Harry He

Voici une solution itérative facile O (2 ^ n):

public static Set<Set<Integer>> powerSet(List<Integer> intList){

    Set<Set<Integer>> result = new HashSet();
    result.add(new HashSet());

    for (Integer i : intList){

        Set<Set<Integer>> temp = new HashSet();

        for(Set<Integer> intSet : result){

            intSet = new HashSet(intSet);
            intSet.add(i);                
            temp.add(intSet);
        }
        result.addAll(temp);
    }
    return result;
}
2
jump3r
import Java.util.Set;
import com.google.common.collect.*;

Set<Set<Integer>> sets = Sets.powerSet(ImmutableSet.of(1, 2, 3));
2
Bax

Un sous-ensemble de t est tout ensemble qui peut être créé en supprimant zéro ou plusieurs éléments de t. Le sous-ensemble withoutFirst ajoute les sous-ensembles de t qui manquent au premier élément et la boucle for traitera l'ajout de sous-ensembles avec le premier élément. Par exemple, si t contenait les éléments ["1", "2", "3"], missingFirst ajoutera [[""], ["2"], ["3"], ["2" , "3"]] et la boucle for collent le "1" devant ces éléments et l'ajoutent au newSet. Nous allons donc nous retrouver avec [[""], ["1"], ["2"], ["3"], ["1", "2"], ["1", "3"] , ["2", "3"], ["1", "2", "3"]].

public static Set<Set<String>> allSubsets(Set<String> t) {
        Set<Set<String>> powerSet = new TreeSet<>();
        if(t.isEmpty()) {
            powerSet.add(new TreeSet<>());
            return powerSet;
        }
        String first = t.get(0);
        Set<Set<String>> withoutFirst = allSubsets(t.subSet(1, t.size()));
        for (List<String> 1st : withoutFirst) {
            Set<String> newSet = new TreeSet<>();
            newSet.add(first);
            newSet.addAll(lst);
            powerSet.add(newSet);
        }
        powerSet.addAll(withoutFirst);
        return powerSet;
    }
2
Hassan Alhujhoj

Certaines des solutions ci-dessus souffrent lorsque la taille de l'ensemble est grande, car elles créent beaucoup de déchets d'objets à collecter et nécessitent la copie de données. Comment pouvons-nous éviter cela? Nous pouvons tirer parti du fait que nous savons quelle sera la taille du jeu de résultats (2 ^ n), préallouer un tableau de cette taille et ajouter à la fin de celui-ci, sans jamais rien copier.

L'accélération augmente rapidement avec n. Je l'ai comparé à la solution de João Silva ci-dessus. Sur ma machine (toutes les mesures approximatives), n = 13 est 5x plus rapide, n = 14 est 7x, n = 15 est 12x, n = 16 est 25x, n = 17 est 75x, n = 18 est 140x. Ainsi, la création/collecte et la copie de déchets sont dominantes dans ce qui semble être des solutions similaires similaires.

La préallocation de la matrice au début semble être une victoire par rapport à une croissance dynamique. Avec n = 18, la croissance dynamique prend globalement deux fois plus de temps.

public static <T> List<List<T>> powerSet(List<T> originalSet) {
    // result size will be 2^n, where n=size(originalset)
    // good to initialize the array size to avoid dynamic growing
    int resultSize = (int) Math.pow(2, originalSet.size());
    // resultPowerSet is what we will return
    List<List<T>> resultPowerSet = new ArrayList<List<T>>(resultSize);

    // Initialize result with the empty set, which powersets contain by definition
    resultPowerSet.add(new ArrayList<T>(0)); 

    // for every item in the original list
    for (T itemFromOriginalSet : originalSet) {

        // iterate through the existing powerset result
        // loop through subset and append to the resultPowerset as we go
        // must remember size at the beginning, before we append new elements
        int startingResultSize = resultPowerSet.size();
        for (int i=0; i<startingResultSize; i++) {
            // start with an existing element of the powerset
            List<T> oldSubset = resultPowerSet.get(i);

            // create a new element by adding a new item from the original list
            List<T> newSubset = new ArrayList<T>(oldSubset);
            newSubset.add(itemFromOriginalSet);

            // add this element to the result powerset (past startingResultSize)
            resultPowerSet.add(newSubset);
        }
    }
    return resultPowerSet;
}
2
George Fairbanks

C'est mon approche avec les lambdas.

public static <T> Set<Set<T>> powerSet(T[] set) {
      return IntStream
            .range(0, (int) Math.pow(2, set.length))
            .parallel() //performance improvement
            .mapToObj(e -> IntStream.range(0, set.length).filter(i -> (e & (0b1 << i)) != 0).mapToObj(i -> set[i]).collect(Collectors.toSet()))
            .map(Function.identity())
            .collect(Collectors.toSet());
        }

Ou en parallèle (voir le commentaire parallel ()): 

Taille du jeu d'entrées: 18

Processeurs logiques: 8 à 3,4 GHz

Amélioration de la performance: 30%

1
Werner

Ceci est ma solution récursive qui peut obtenir le pouvoir de n'importe quel jeu en utilisant Java Generics. Son idée principale est de combiner la tête du tableau d’entrée avec toutes les solutions possibles du reste du tableau comme suit.

import Java.util.LinkedHashSet;
import Java.util.Set;

public class SetUtil {
    private static<T>  Set<Set<T>> combine(T head, Set<Set<T>> set) {
        Set<Set<T>> all = new LinkedHashSet<>();

        for (Set<T> currentSet : set) {
            Set<T> outputSet = new LinkedHashSet<>();

            outputSet.add(head);
            outputSet.addAll(currentSet);

            all.add(outputSet);
        }

        all.addAll(set);        

        return all;
    }

    //Assuming that T[] is an array with no repeated elements ...
    public static<T> Set<Set<T>> powerSet(T[] input) {
        if (input.length == 0) {
            Set <Set<T>>emptySet = new LinkedHashSet<>();

            emptySet.add(new LinkedHashSet<T>());

            return emptySet;
        }

        T head = input[0];
        T[] newInputSet = (T[]) new Object[input.length - 1];

        for (int i = 1; i < input.length; ++i) {
            newInputSet[i - 1] = input[i];
        }

        Set<Set<T>> all = combine(head, powerSet(newInputSet));

        return all;
    }

    public static void main(String[] args) {            
        Set<Set<Integer>> set = SetUtil.powerSet(new Integer[] {1, 2, 3, 4, 5, 6});

        System.out.println(set);
    }
}

Cela produira:

[[1, 2, 3, 4, 5, 6], [1, 2, 3, 4, 5], [1, 2, 3, 4, 6], [1, 2, 3, 4], [1, 2, 3, 5, 6], [1, 2, 3, 5], [1, 2, 3, 6], [1, 2, 3], [1, 2, 4, 5, 6], [1, 2, 4, 5], [1, 2, 4, 6], [1, 2, 4], [1, 2, 5, 6], [1, 2, 5], [1, 2, 6], [1, 2], [1, 3, 4, 5, 6], [1, 3, 4, 5], [1, 3, 4, 6], [1, 3, 4], [1, 3, 5, 6], [1, 3, 5], [1, 3, 6], [1, 3], [1, 4, 5, 6], [1, 4, 5], [1, 4, 6], [1, 4], [1, 5, 6], [1, 5], [1, 6], [1], [2, 3, 4, 5, 6], [2, 3, 4, 5], [2, 3, 4, 6], [2, 3, 4], [2, 3, 5, 6], [2, 3, 5], [2, 3, 6], [2, 3], [2, 4, 5, 6], [2, 4, 5], [2, 4, 6], [2, 4], [2, 5, 6], [2, 5], [2, 6], [2], [3, 4, 5, 6], [3, 4, 5], [3, 4, 6], [3, 4], [3, 5, 6], [3, 5], [3, 6], [3], [4, 5, 6], [4, 5], [4, 6], [4], [5, 6], [5], [6], []]
1
Hazem Saleh

Si S est un ensemble fini à N éléments, alors l'ensemble de puissance de S contient 2 ^ N éléments. Le temps nécessaire pour énumérer simplement les éléments du sous-système est de 2 ^ N, donc O(2^N) est une limite inférieure de la complexité temporelle de la construction (rapide) du sous-ensemble.

En termes simples, tout calcul impliquant la création d'ensembles de puissance n'échelle pas pour les grandes valeurs de N. Aucun algorithme intelligent ne vous aidera ... à part éviter la nécessité de créer les ensembles de pouvoirs!

1
Stephen C

Une façon de faire sans récursivité est la suivante: Utilisez un masque binaire et faites toutes les combinaisons possibles.

public HashSet<HashSet> createPowerSet(Object[] array)
{
    HashSet<HashSet> powerSet=new HashSet();
    boolean[] mask= new boolean[array.length];

    for(int i=0;i<Math.pow(2, array.length);i++)
    {
        HashSet set=new HashSet();
        for(int j=0;j<mask.length;j++)
        {
            if(mask[i])
                set.add(array[j]);
        }
        powerSet.add(set);      

        increaseMask(mask);
    }

    return powerSet;
}

public void increaseMask(boolean[] mask)
{
    boolean carry=false;

    if(mask[0])
        {
            mask[0]=false;
            carry=true;
        }
    else
        mask[0]=true;

    for(int i=1;i<mask.length;i++)
    {
        if(mask[i]==true && carry==true)
        mask[i]=false;
        else if (mask[i]==false && carry==true)
        {
            mask[i]=true;
            carry=false;
        }
        else 
            break;

    }

}
1
Orestis

Algorithme:

Entrée: Définissez [], set_size 1. Obtenez la taille du jeu de puissance powet_set_size = pow (2, set_size) 2 Boucle pour le compteur de 0 à pow_set_size (a) Boucle pour i = 0 à set_size (i) Si le bit dans le compteur est activé Imprimer cet élément de l'ensemble pour ce sous-ensemble (b) Séparateur d’impression pour les sous-ensembles, c’est-à-dire, nouvelle ligne

#include <stdio.h>
#include <math.h>
 
void printPowerSet(char *set, int set_size)
{
    /*set_size of power set of a set with set_size
      n is (2**n -1)*/
    unsigned int pow_set_size = pow(2, set_size);
    int counter, j;
 
    /*Run from counter 000..0 to 111..1*/
    for(counter = 0; counter < pow_set_size; counter++)
    {
      for(j = 0; j < set_size; j++)
       {
          /* Check if jth bit in the counter is set
             If set then pront jth element from set */
          if(counter & (1<<j))
            printf("%c", set[j]);
       }
       printf("\n");
    }
}
 
/*Driver program to test printPowerSet*/
int main()
{
    char set[] = {'a','b','c'};
    printPowerSet(set, 3);
 
    getchar();
    return 0;
}

1
gaurav

Un autre exemple d'implémentation: 

 public static void main(String args[])
    {
        int[] arr = new int[]{1,2,3,4};
        // Assuming that number of sets are in integer range
        int totalSets = (int)Math.pow(2,arr.length);
        for(int i=0;i<totalSets;i++)
        {
            String binaryRep = Integer.toBinaryString(i);      
            for(int j=0;j<binaryRep.length();j++)
            {
                int index=binaryRep.length()-1-j;
                if(binaryRep.charAt(index)=='1')
                System.out.print(arr[j] +" ");       
            }
            System.out.println();
        }
    }
1
Sandeep

J'ai récemment eu à utiliser quelque chose comme ça, mais j'avais besoin des plus petites sous-listes (avec 1 élément, puis 2 éléments, ...) en premier. Je ne voulais pas inclure la liste vide ni la liste complète ..__ De plus, je n'avais pas besoin d'une liste de toutes les sous-listes renvoyées, je devais juste faire quelques choses avec chacune d'elles. 

Je voulais faire cela sans récursion, et voici ce qui a été dit (avec le "travail" résumé dans une interface fonctionnelle):

@FunctionalInterface interface ListHandler<T> {
    void handle(List<T> list);
}


public static <T> void forAllSubLists(final List<T> list, ListHandler handler) {
    int     ll = list.size();   // Length of original list
    int     ci[] = new int[ll]; // Array for list indices
    List<T> sub = new ArrayList<>(ll);  // The sublist
    List<T> uml = Collections.unmodifiableList(sub);    // For passing to handler

    for (int gl = 1, gm; gl <= ll; gl++) {  // Subgroup length 1 .. n-1
        gm = 0; ci[0] = -1; sub.add(null);  // Some inits, and ensure sublist is at least gl items long

        do {
                ci[gm]++;                       // Get the next item for this member

                if (ci[gm] > ll - gl + gm) {    // Exhausted all possibilities for this position
                        gm--; continue;         // Continue with the next value for the previous member
                }

                sub.set(gm, list.get(ci[gm]));  // Set the corresponding member in the sublist

                if (gm == gl - 1) {             // Ok, a sublist with length gl
                        handler.handle(uml);    // Handle it
                } else {
                        ci[gm + 1] = ci[gm];    // Starting value for next member is this 
                        gm++;                   // Continue with the next member
                }
        } while (gm >= 0);  // Finished cycling through all possibilities
    }   // Next subgroup length
}

De cette façon, il est également facile de le limiter à des sous-listes de longueurs spécifiques.

0
tijmen
public class PowerSet {
    public static List<HashSet<Integer>> powerset(int[] a) {
        LinkedList<HashSet<Integer>> sets = new LinkedList<HashSet<Integer>>();
        int n = a.length;
        for (int i = 0; i < 1 << n; i++) {
            HashSet<Integer> set = new HashSet<Integer>();
            for (int j = 0; j < n; j++) {
                if ((1 << j & i) > 0)
                    set.add(a[j]);
            }
            sets.add(set);
        }
        return sets;
    }

    public static void main(String[] args) {
        List<HashSet<Integer>> sets = PowerSet.powerset(new int[]{ 1, 2, 3 });
        for (HashSet<Integer> set : sets) {
            for (int i : set)
                System.out.print(i);
            System.out.println();
        } 
    }
}
0
Selim Ekizoglu

Encore une autre solution - avec Java8 + api streamingIl est paresseux et ordonné afin de retourner les sous-ensembles corrects quand il est utilisé avec "limit ()". 

 public long bitRangeMin(int size, int bitCount){
    BitSet bs = new BitSet(size);
    bs.set(0, bitCount);
    return bs.toLongArray()[0];
}

public long bitRangeMax(int size, int bitCount){
    BitSet bs = BitSet.valueOf(new long[]{0});
    bs.set(size - bitCount, size);
    return bs.toLongArray()[0];
}

public <T> Stream<List<T>> powerSet(Collection<T> data)
{
    List<T> list = new LinkedHashSet<>(data).stream().collect(Collectors.toList());
    Stream<BitSet> head = LongStream.of(0).mapToObj( i -> BitSet.valueOf(new long[]{i}));
    Stream<BitSet> tail = IntStream.rangeClosed(1, list.size())
            .boxed()
            .flatMap( v1 -> LongStream.rangeClosed( bitRangeMin(list.size(), v1), bitRangeMax(list.size(), v1))
                    .mapToObj(v2 -> BitSet.valueOf(new long[]{v2}))
                    .filter( bs -> bs.cardinality() == v1));

    return Stream.concat(head, tail)
            .map( bs -> bs
                    .stream()
                    .mapToObj(list::get)
                    .collect(Collectors.toList()));
}

Et le code client est 

@Test
public void testPowerSetOfGivenCollection(){
    List<Character> data = new LinkedList<>();
    for(char i = 'a'; i < 'a'+5; i++ ){
        data.add(i);
    }
    powerSet(data)
            .limit(9)
            .forEach(System.out::print);

}

/ * Imprime: [] [a] [b] [c] [d] [e] [a, b] [a, c] [b, c] * /

0
ekobir

Nous pourrions écrire le jeu de puissances avec ou sans utilisation de la récursivité. Voici une tentative sans récursion:

public List<List<Integer>> getPowerSet(List<Integer> set) {
    List<List<Integer>> powerSet = new ArrayList<List<Integer>>();
    int max = 1 << set.size();
    for(int i=0; i < max; i++) {
        List<Integer> subSet = getSubSet(i, set);
        powerSet.add(subSet);
    }
    return powerSet;
}

private List<Integer> getSubSet(int p, List<Integer> set) {
    List<Integer> subSet = new ArrayList<Integer>();
    int position = 0;
    for(int i=p; i > 0; i >>= 1) {
        if((i & 1) == 1) {
            subSet.add(set.get(position));
        }
        position++;
    }
    return subSet;
}
0
YuVi
// input: S
// output: P
// S = [1,2]
// P = [], [1], [2], [1,2]

public static void main(String[] args) {
    String input = args[0];
    String[] S = input.split(",");
    String[] P = getPowerSet(S);
    if (P.length == Math.pow(2, S.length)) {
        for (String s : P) {
            System.out.print("[" + s + "],");
        }
    } else {
        System.out.println("Results are incorrect");
    }
}

private static String[] getPowerSet(String[] s) {
    if (s.length == 1) {
        return new String[] { "", s[0] };
    } else {
        String[] subP1 = getPowerSet(Arrays.copyOfRange(s, 1, s.length));
        String[] subP2 = new String[subP1.length];
        for (int i = 0; i < subP1.length; i++) {
            subP2[i] = s[0] + subP1[i];
        }
        String[] P = new String[subP1.length + subP2.length];
        System.arraycopy(subP1, 0, P, 0, subP1.length);
        System.arraycopy(subP2, 0, P, subP1.length, subP2.length);
        return P;
    }

}

Voici pour générer un ensemble de puissance. L'idée est première = S[0] et les plus petits ensembles sont S[1,...n]

Calculez tous les sous-ensembles de smallerSet et mettez-les dans tous les sous-ensembles.

Pour chaque sous-ensemble de tous les sous-ensembles, clonez-le et ajoutez-le d'abord au sous-ensemble.

ArrayList<ArrayList<Integer>> getSubsets(ArrayList<Integer> set, int index){
    ArrayList<ArrayList<Integer>> allsubsets;
    if(set.size() == index){
        allsubsets = new ArrayList<ArrayList<Integer>>();
        allsubsets.add(new ArrayList<Integer>()); // the empty set 
    }else{
        allsubsets = getSubsets(set, index+1);
        int item = set.get(index);

        ArrayList<ArrayList<Integer>> moresubsets = new ArrayList<ArrayList<Integer>>();

        for(ArrayList<Integer> subset: allsubsets){
            ArrayList<Integer> newsubset = new ArrayList<Integer>();

            newsubset.addAll(subset);
            newsubset.add(item);
            moresubsets.add(newsubset);

        }

        moresubsets.addAll(moresubsets);

    }

    return allsubsets;
}
0
None