public class Algorithms {    public Algorithms() {
    }
    
    private  static <T> void subCombination(List<List<T>> out,List<T> in,
     List<T> temp,int index,int nloop,int nth){
     if (index == nth){ //get the result
     out.add(temp);
     System.out.println(temp);
     }
     else{
     for (int loop = nloop;loop < in.size();++loop){
     temp.set(index,in.get(loop));
     subCombination(out,in,temp,index+1,loop+1,nth); //backtracking
     }
     }
    }
    
    public static <T> void combination(List<List<T>> out,List<T> in,int nth){
     if (nth >= in.size())
     return;
     List<T> temp = new ArrayList<T>(nth);
     for (int i = 0;i < nth;++i)
     temp.add(null);
     subCombination(out,in,temp,0,0,nth);
    }
    
    public static void main (String[] args) {
     List<String> ls = new ArrayList<String>();
     ls.addAll(Arrays.asList("a","b","c","d","e","f","g","h"));
     List<List<String>> comb = new ArrayList<List<String>>();
     combination(comb,ls,7);
     System.out.println(comb);
}
}
输出:[a, b, c, d, e, f, g]
[a, b, c, d, e, f, h]
[a, b, c, d, e, g, h]
[a, b, c, d, f, g, h]
[a, b, c, e, f, g, h]
[a, b, d, e, f, g, h]
[a, c, d, e, f, g, h]
[b, c, d, e, f, g, h]
[[h, h, h, h, h, h, h], [h, h, h, h, h, h, h], [h, h, h, h, h, h, h], [h, h, h, h, h, h, h], [h, h, h, h, h, h, h], [h, h, h, h, h, h, h], [h, h, h, h, h, h, h], [h, h, h, h, h, h, h]]
输出的两部分,其中前面正确的结果是因为在算法中检测输出结果,而后面错误的输出是实际提取出来的组合结果。问题1:
我知道错误的原因是因为“浅拷贝”的问题,在out.add(temp);一句中,out中的结果和temp做了个映射,而temp是不断改变的。
我想知道在此处用“深拷贝”该如何实现?进一步,java中对象“深拷贝”的实现。注:不仅是那里,因为浅拷贝的原因,使得方法返回的结果和输入建立映射,改变其一,会引起另一不期望的改变。问题2:
总所周知,java的泛型不允许创建泛型数组,即T[] temp = new T[nth];所以我把temp实现为List<T>,并且因为要使用set来改变位置元素,所以很别扭的采用一个for循环再赋值null的方法。其实很不想这样做,有没有什么更好的方法实现temp这个变量?
………………………………………………………………………………………………………………………………………………
这是个使用递归回溯的计算组合的算法,闲来没事用java实现下,准备放进我的库里。这个算法用c++我是实现过的,也是用的泛型。
大家帮下忙,我没接触过java中的数据结构和算法,代码里的不合理的地方希望指导一下。

解决方案 »

  1.   

    什么叫深拷贝,是不是override clone method就行了。
      

  2.   

    1、修改subCombination
    private  static <T> void subCombination(List<List<T>> out,List<T> in,
            List<T> temp,int index,int nloop,int nth){
            if (index == nth){        //get the result
                out.add(temp);
                System.out.println(temp);
            }
            else{
                for (int loop = nloop;loop < in.size();++loop){
                 List<T> temp1=new ArrayList<T>(temp);//。
                    temp1.set(index,in.get(loop));
                    subCombination(out,in,temp1,index+1,loop+1,nth);        //backtracking
                }
            }
        }
      

  3.   

    2、没想到好方法  不过变通一下也可以实现
    private  static <T> void subCombination(List<List<T>> out,List<T> in,
            List<T> temp,int index,int nloop,int nth){
            if (index == nth){        //get the result
                out.add(temp);
                System.out.println(temp);
            }
            else{
                for (int loop = nloop;loop < in.size();++loop){
                 List<T> temp1=new ArrayList<T>(temp);
                
                            //这里改了
                            if(index>temp1.size()){
                 temp1.set(index,in.get(loop));
                 }else{
                 temp1.add(in.get(loop));
                 }
                   
                    subCombination(out,in,temp1,index+1,loop+1,nth);        //backtracking
                }
            }
        }
        
        public static <T> void combination(List<List<T>> out,List<T> in,int nth){
            if (nth >= in.size())
                return;
            List<T> temp = new ArrayList<T>(nth);         subCombination(out,in,temp,0,0,nth);
        }
      

  4.   

    第一个问题:深拷贝比较复杂,涉及到递归,用clone实现吧。
    把out.add(temp)改成下面就可以了。
    out.add((List<T>)((ArrayList)temp).clone());
    第二个问题:虽然T[] temp = new T[nth]不行,但可以这样;
    Ojbect[] os = new Object[nth];
    T[] temp = (T[])os;
    完整程序import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.List;public class Algorithms
    {    public Algorithms()
        {
        }    private static <T> void subCombination(List<List<T>> out, List<T> in,
                        T[] temp, int index, int nloop, int nth)
        {
            if (index == nth)
            { // get the result
                out.add(Arrays.asList(temp.clone()));
                System.out.print("[");
                for(int i=0;i<temp.length-1;i++)
                    System.out.print(temp[i]+", ");
                System.out.print(temp[temp.length-1]+"]");
                System.out.println();
            }
            else
            {
                for (int loop = nloop; loop < in.size(); ++loop)
                {
                    //temp.set(index, in.get(loop));
                    temp[index] = in.get(loop);
                    subCombination(out, in, temp, index + 1, loop + 1, nth); // backtracking
                }
            }
        }    public static <T> void combination(List<List<T>> out, List<T> in, int nth)
        {
            if (nth >= in.size())
            {
                return;
            }
            //List<T> temp = new ArrayList<T>(nth);
            Object[] os = new Object[nth];
            T[] temp = (T[])os;
    //        for (int i = 0; i < nth; ++i)
    //            temp.add(null);
            subCombination(out, in, temp, 0, 0, nth);
        }    public static void main(String[] args)
        {
            List<String> ls = new ArrayList<String>();
            ls.addAll(Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h"));
            List<List<String>> comb = new ArrayList<List<String>>();
            combination(comb, ls, 7);
            System.out.println(comb);
        }
    }
      

  5.   


            private  static <T> void subCombination(List<List<T>> out,List<T> in,
                List<T> temp,int index,int nloop,int nth){
                if (index == nth){        //get the result
                    out.add(temp);
                    System.out.println(temp);
                }
                else{
                    for (int loop = nloop;loop < in.size();++loop){
                        List<T> temp1=new ArrayList<T>(temp);                    //我晕上面subCombination()的不对
                           //因为index等于temp1.size() 
                        //搞得自己没看懂程序                    temp1.add(in.get(loop));
                           
                        subCombination(out,in,temp1,index+1,loop+1,nth);        //backtracking
                    }
                }
            }
      

  6.   


    谢谢你的解答,你的解决可以很好的完成。但是还有点疑问。
    用clone我也想过,但是这里我是用的String去实例化运行这个程序,要是是一个自定义类型,该类型又包含非基本类型的域,如果该类没有去实现Cloneable接口,又或者实现了,但是其包含的域没有实现Cloneable接口,一样会有“浅拷贝”存在。
    也许是我太钻牛角尖了,但是我想即使采用clone来实现,有可以保护这种情况,也就是说在不能进行深拷贝的对象,我在方法中抛出个异常,这样不知道能否实现。
    对于第2个问题,我确实不知道,因为我理解的泛型类型参数会被擦除,所以在转型时不能使用,但是居然可以,只是有个unchecked的警告,用@SuppressWarninis可以禁止。
      

  7.   

    嗯,对于一个List要实现完全的深拷贝确实比较麻烦,因为你根本不知道List里面放的到底是什么类型数据,要根据具体情况采用不同的方法。用抛出异常应该也是一个解决方法,我觉得应该是可行的。你可以试试看。不过,你捕获到这个异常后怎么处理呢?