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