2011-08-26 22 views
9

我有一個元素列表(1,2,3),我需要獲取該列表的超集(powerset)(不包括重複元素)。所以基本上我需要創建列表的列表,看起來像:打印列表的所有可能的子集

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

什麼是最好的(在這種情況下,簡單>效率,名單不會是巨大的)的方式來實現這一點?最好在Java中,但任何語言的解決方案都是有用的。

+1

你想要一個列表的所有子集。我建議遞歸。然而,如果你處理的是30-40多個元素,那麼你將無法處理你擁有的巨大數據(超過1TB數據)。這用於什麼? –

+2

您正在查找的數據結構稱爲Powerset(不同之處在於它也包含一個空集)。它已經在SO上進行了討論。 –

+0

感謝Zenzen指引我在正確的方向......我發現http://stackoverflow.com/questions/1670862/obtaining-powerset-of-a-set-in-java。 – Steve

回答

31

使用位掩碼:

int allMasks = (1 << N); 
for (int i = 1; i < allMasks; i++) 
{ 
    for (int j = 0; j < N; j++) 
     if ((i & (1 << j)) > 0) //The j-th element is used 
      System.out.print((j + 1) + " "); 

    System.out.println(); 
} 

這裏是所有位掩碼:

1 = 001 = {1} 
2 = 010 = {2} 
3 = 011 = {1, 2} 
4 = 100 = {3} 
5 = 101 = {1, 3} 
6 = 110 = {2, 3} 
7 = 111 = {1, 2, 3} 

你知道,在二進制的第一位是最右邊。

+0

這是非常有趣的...你顯然比我更聰明 - 給我一些時間來包圍我的想法....是N原始列表中的元素的數量?我是否將列表中的對象映射爲整數? – Steve

+0

@Steve - 是的,'N'是元素的數量 - 在你的例子中'N = 3'上面。以二進制形式考慮 - 如果元素未使用,則該位爲0,如果使用該元素,則該位爲1。例如5 = 101二進制。這意味着使用'1'和'3'。 '= {1,3}' –

+0

@Steve - 看看我的編輯。 –

1
import java.io.*; 
import java.util.*; 
class subsets 
{ 
    static String list[]; 
    public static void process(int n) 
    { 
     int i,j,k; 
     String s=""; 
     displaySubset(s); 
     for(i=0;i<n;i++) 
     { 
      for(j=0;j<n-i;j++) 
      { 
       k=j+i; 
       for(int m=j;m<=k;m++) 
       { 
        s=s+m; 
       } 
       displaySubset(s); 
       s=""; 
      } 
     } 
    } 
    public static void displaySubset(String s) 
    { 
     String set=""; 
     for(int i=0;i<s.length();i++) 
     { 
      String m=""+s.charAt(i); 
      int num=Integer.parseInt(m); 
      if(i==s.length()-1) 
       set=set+list[num]; 
      else 
       set=set+list[num]+","; 
     } 
     set="{"+set+"}"; 
     System.out.println(set); 
    } 
    public static void main() 
    { 
     Scanner sc=new Scanner(System.in); 
     System.out.println("Input ur list"); 
     String slist=sc.nextLine(); 
     int len=slist.length(); 
     slist=slist.substring(1,len-1); 
     StringTokenizer st=new StringTokenizer(slist,","); 
     int n=st.countTokens(); 
     list=new String[n]; 
     for(int i=0;i<n;i++) 
     { 
      list[i]=st.nextToken(); 
     } 
     process(n); 
    } 
} 
+0

該程序很簡單。首先,我們嘗試獲取所有可能的1-n數字組合,直到1,2,3的每個列表的最後一位數字.... n位數字是n。然後用每個組合提取其每個字符(即數字)並顯示存儲在由該字符(數字)表示的單元索引中的子集的元素。 –

+0

在答案本身中添加代碼的描述比在評論中更好。一般情況下,僅使用代碼回答並不是社區的良好回答,即使代碼正確回答了問題。 –

0

根據斯托Minchev溶液中的Java解決方案 -

public static List<List<Integer>> getAllSubsets(List<Integer> input) { 
    int allMasks = 1 << input.size(); 
    List<List<Integer>> output = new ArrayList<List<Integer>>(); 
    for(int i=0;i<allMasks;i++) { 
     List<Integer> sub = new ArrayList<Integer>(); 
     for(int j=0;j<input.size();j++) { 
      if((i & (1 << j)) > 0) { 
       sub.add(input.get(j)); 
      } 
     } 
     output.add(sub); 
    } 

    return output; 
} 
0

我注意到,答案集中的字符串列表上。因此,我決定分享更通用的答案。 希望它會有幫助。 (Soultion基於另一種解決方案,我發現,我把它合併到一個通用的算法用於)

/** 
* metod returns all the sublists of a given list 
* the method assumes all object are different 
* no matter the type of the list (generics) 
* @param list the list to return all the sublist of 
* @param <T> 
* @return list of the different sublists that can be made from the list object 
*/ 
public static <T> List<List<T>>getAllSubLists(List<T>list) 
{ 
    List<T>subList; 
    List<List<T>>res = new ArrayList<>(); 
    List<List<Integer>> indexes = allSubListIndexes(list.size()); 
    for(List<Integer> subListIndexes:indexes) 
    { 
     subList=new ArrayList<>(); 
     for(int index:subListIndexes) 
      subList.add(list.get(index)); 
     res.add(subList); 
    } 
    return res; 
} 
/** 
* method returns list of list of integers representing the indexes of all the sublists in a N size list 
* @param n the size of the list 
* @return list of list of integers of indexes of the sublist 
*/ 
public static List<List<Integer>> allSubListIndexes(int n) { 
    List<List<Integer>> res = new ArrayList<>(); 
    int allMasks = (1 << n); 
    for (int i = 1; i < allMasks; i++) 
    { 
     res.add(new ArrayList<>()); 
     for (int j = 0; j < n; j++) 
      if ((i & (1 << j)) > 0) 
       res.get(i-1).add(j); 

    } 
    return res; 
}