【问题描述】(专业领域问题,保密起见此处省略……)
【模型】
data[][]={
{0, 100, 200, 300},
{0, 50, 100},
{0, 150, 300},
{0, 100, 200, 300, 400,}
}
//2维数组data,M行,每一行代表一组数据,每组数据内有序
//要求:从每一组数据中,取出且仅仅取出一个数,然后使这些数据的和满足[MIN, MAX]范围。
这是最近同学遇到的一个问题,开始先用非递归方法实现的,后来为了比较递归和非递归的区别,又用递归方法实现了。
先说说非递归方法,我的思路是:肯定要遍历各组数据之间的所有组合,即任意Xi属于组Si(i=0,1,2,....,M-1),{X1,X2,...,X(M-1)}的所有组合。当然,因为各组数据之内有序,可以在遍历过程中增加判断,如果当前的和已经大于M,则可以结束当前循环,以及后面的判断。采用数组INDEX[0---M-1]来记录每一行当前循环的index,如果后面的i行的index已经达到该行的最大index,则i-1行加一。及类似数字进位原理。(后来听同学说,这样也可以解决多层循环的问题)。
1
package swing;
2![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
3
import java.util.ArrayList;
4![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
5![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
6![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
public class HHH
{
7
private final int[] INDEX; //记录当前各层下一步的Index
8
private final int[] LENGTH; //记录各层的长度
9
private double[][] data; //原始数组
10
private double[][] result; //记录组合
11
private final double MIN; //要组合的数的和的下限
12
private final double MAX; //要组合的数的和的上限
13
private final int DD; //二维数组的行数
14![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public HHH(double[][] data, double min, double max)
{
15
this.data = data;
16
this.MIN = min;
17
this.MAX = max;
18![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
19![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (this.data == null)
{
20
DD = 0;
21
}
22![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
else
{
23
DD = data.length;
24
}
25
INDEX = new int[DD];
26
LENGTH = new int[DD];
27![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (int i = 0; i < DD; i++)
{
28![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (data[i] != null)
{
29
LENGTH[i] = data[i].length;
30
}
31![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
else
{
32
LENGTH[i] = 0;
33
}
34
}
35
//filter first
36![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (int i = 0; i < DD; i++)
{
37![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (int j = 0; j < LENGTH[i]; j++)
{
38![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (data[i][j] > MAX)
{
39
LENGTH[i] = j;
40
}
41
break;
42
}
43
}
44![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
45
//greatly filter
46
ArrayList a = new ArrayList();
47
double[] temp = new double[DD];
48
double sum = 0;
49
boolean over = false;
50![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
while (true)
{
51
sum = 0;
52![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (int i = 0; i < DD; i++)
{
53
temp[i] = data[i][INDEX[i]];
54
sum += temp[i];
55![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (sum > MAX)
{ //此处判断,可大量提高速度
56![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (int j = i + 1; j < DD; j++)
{
57
INDEX[j] = LENGTH[j] - 1;
58
break;
59
}
60
}
61
}
62![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (sum >= MIN && sum <= MAX)
{
63
a.add(temp);
64
temp = new double[DD];
65
}
66
INDEX[DD - 1]++;
67
int div = INDEX[DD - 1] / LENGTH[DD - 1];
68
INDEX[DD - 1] %= LENGTH[DD - 1];
69![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (int i = DD - 2; i >= 0; i--)
{
70
int ttt = INDEX[i] + div;
71![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (ttt == LENGTH[0])
{
72
over = true;
73
break;
74
}
75
INDEX[i] = ttt % LENGTH[i];
76
div = (ttt) / LENGTH[i];
77
}
78![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (over)
{
79
break;
80
}
81
}
82
//format
83
int size = a.size();
84
result = new double[size][];
85![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (int i = 0; i < size; i++)
{
86
result[i] = (double[]) a.get(i);
87
}
88
}
89![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
90![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public double[][] getResult()
{
91
return result;
92
}
93![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
94![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public void printResult()
{
95![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (result != null)
{
96![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (int i = 0; i < result.length; i++)
{
97![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (int j = 0; j < result[i].length; j++)
{
98
System.out.print(result[i][j] + " ");
99
}
100
System.out.println();
101
}
102
}
103
}
104![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
105![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public static void main(String[] args)
{
106![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
double[][] capacity =
{
107![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
108
0, 200, 300, 400, 500, 600, 700, 800, 1000, 5500, 5510, 5515, 5520,
109
5560, 6000}
110![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
111
0, 300, 600, 900, 1200, 1500, 1800, 2000, 2211, 2222, 2233}
112![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
113
0, 300, 600, 900, 1200}
114![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
115
0, 300, 600}
116![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
117
0, 135, 150, 230, 460}
118![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
119
0, 300, 600, 4000}
120![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
121
0, 600, 1200, 1800, 2400}
122![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
123
0, 300, 600}
124![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
125
0, 300, 600, 1000}
126
};
127
long begin = System.currentTimeMillis();
128
HHH h = new HHH(capacity, 7000, 8000);
129
begin = System.currentTimeMillis() - begin;
130
System.out.println("time used: " + (begin / 1000.0) + "s");
131
System.out.println("" + h.getResult().length);
132
//输出太多,省略
133
//h.printResult();
134
}
135![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
136
}
后来又用递归实现了,发现用递归实现反而思路更加简单,而且也好理解。就是从第一行到最后一行,每行取一个数,直到最后一行取了或者前面之和已经大于MAX为止。但是回退时要注意减掉上一次加的那个数。
1
package swing;
2![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
3
import java.util.ArrayList;
4![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
5![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
6![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
7![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
public class HHH1
{
8
private double[][] data;
9
private final int DD;
10
private final double MAX;
11
private final double MIN;
12
private double[][] result;
13
private ArrayList res = new ArrayList();
14
private double[] tmp;
15
private double sum = 0;
16![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public HHH1(double[][] data, double min, double max)
{
17
this.data = data;
18![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (data != null)
{
19
DD = data.length;
20
}
21![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
else
{
22
DD = 0;
23
}
24
MAX = max;
25
MIN = min;
26
tmp = new double[DD];
27
}
28![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
29![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public void process(int n, int index)
{
30![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (n == index)
{
31![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (sum >= MIN && sum <= MAX)
{
32
res.add(tmp.clone());
33
}
34
}
35![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
else
{
36
int i;
37![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (i = 0; i < data[index].length; i++)
{
38
tmp[index] = data[index][i];
39
sum += tmp[index];
40![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (i > 0)
{
41
sum -= data[index][i - 1];
42
}
43![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (sum > MAX)
{
44
sum -= tmp[index];
45
break;
46
}
47
process(n, index + 1);
48
}
49![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (i == data[index].length)
{
50
sum -= data[index][i - 1];
51
}
52
}
53
}
54![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
55![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
private void format()
{
56
int size = res.size();
57
result = new double[size][];
58![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
for (int i = 0; i < size; i++)
{
59
result[i] = (double[]) res.get(i);
60
}
61
}
62![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
63![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public double[][] getResult()
{
64![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
if (result == null)
{
65
format();
66
}
67
return result;
68
}
69![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
70![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
public static void main(String[] args)
{
71![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
double[][] capacity =
{
72![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
73
0, 200, 300, 400, 500, 600, 700, 800, 1000, 5500, 5510, 5515, 5520,
74
5560, 6000}
75![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
76
0, 300, 600, 900, 1200, 1500, 1800, 2000, 2211, 2222, 2233}
77![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
78
0, 300, 600, 900, 1200}
79![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
80
0, 300, 600}
81![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
82
0, 135, 150, 230, 460}
83![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
84
0, 300, 600, 4000}
85![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
86
0, 600, 1200, 1800, 2400}
87![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
88
0, 300, 600}
89![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
,
{
90
0, 300, 600, 1000}
91
};
92
long begin = System.currentTimeMillis();
93
HHH1 h = new HHH1(capacity, 7000, 8000);
94
h.process(capacity.length, 0);
95
double[][] res = h.getResult();
96
begin = System.currentTimeMillis() - begin;
97
System.out.println("time used: " + (begin / 1000.0) + "s");
98
System.out.println(res.length);
99
// for(int i=0;i<h.res.size();i++){
100
// double[] d=(double[])h.res.get(i);
101
// for(int j=0;j<d.length;j++){
102
// System.out.print(""+d[j]+" ");
103
// }
104
// System.out.println();
105
// }
106
}
107
}
经过用两种方法对相同的数据进行测试,发现递归的程序明显比非递归的程序快。原因初步分析如下:虽说递归涉及到多次的函数调用,即进栈出栈的操作,但是因为函数调用使用栈,而非在堆中,因此速度比在非递归时使用的在堆中分配的数据要快。当然,这也许和我写的非递归算法有关。
关于递归与非递归的使用以及转换和效率问题,最近抽空研究下。
====================================================================================================
added on 2009-11-17
经测试,非递归算法之所以这么慢,是因为我在程序中处理“进位”时,使用了除法和取余操作,而这两种操作相对加法和比较来说,是比较费时的。经改进算法,程序已经达到和递归差不多的速度。看来以后写程序得注意了,如果能有替代方案,尽量少用乘除操作。虽然计算少的时候效果看不出来,
最近对递归和非递归看了下,感觉递归思想确实易理解,而且程序简练,但是也存在许多问题,比如多次函数调用导致耗资源,不便于控制处理过程等。所以以后还是能不用递归就不用了吧。