嵌套循环的效率优化

日常开发中,我们经常会遇到类似这样的嵌套循环:

for (int i = 0; i < outterLoopCount; i++)
     for (int j = 0; j < innerLoopCount; j++)
	 doSomething();

 

一般的说法是把循环次数少的循环放在外面,如jdk里java.util.Collections.disjoint(Collection<?> c1, Collection<?> c2)的实现.

public static boolean disjoint(Collection<?> c1, Collection<?> c2) {
        /*
         * We're going to iterate through c1 and test for inclusion in c2.
         * If c1 is a Set and c2 isn't, swap the collections.  Otherwise,
         * place the shorter collection in c1. Hopefully this heuristic
         * will minimize the cost of the operation.
         */
        if ((c1 instanceof Set) && !(c2 instanceof Set) ||
            (c1.size() > c2.size())) {
            Collection<?> tmp = c1;
            c1 = c2;
            c2 = tmp;
        }

        for (Object e : c1)
            if (c2.contains(e))
                return false;
        return true;
    }

 

这种方法是出于减少循环次数的目的,能减少  (大循环长度 - 小循环长度)次循环,但这样能保证效率总是最优吗?

static void loop() {
		int[][] arr = new int[1000000][10];

		// 第一个循环,大循环放在里面
		long start = System.currentTimeMillis();
		for (int i = 0; i < 10; i++)
			for (int j = 0; j < 1000000; j++)
				arr[j][i] = i + j;
		long loop1End = System.currentTimeMillis();

		// 第二个循环,大循环放在外面
		for (int i = 0; i < 1000000; i++)
			for (int j = 0; j < 10; j++)
				arr[i][j] = i + j;
		long loop2End = System.currentTimeMillis();

		System.out.println(loop1End - start);
		System.out.println(loop2End - loop1End);
	}

 

在我的机器上运行,第二个循环总是比第一个循环快。
所以将循环次数少的循环放在外面只考虑到了循环次数,并没有考虑到单次循环花费的时间,并不总是正确的优化方法。
那么怎样才对正确的优化循环呢?我首先想到的是对其建立模型求解。

有两个循环loop1, loop2,次数为分别为 x,y ,单次循环时间分别为 a,b;
设x > y >= 0;
a >= 0;
b >= 0;
解:
设 n = x - y, 则 n >0 且为常数,  y = x - n;

两种组合花费的时间分别为:

loop1 在外,loop2 在内:  x(a + b * y)    #1式
loop1 在内,loop2 在外:y(b + a * x)    #2式

时间差t为:

t =  #1 - #2
t  =  (b - a) x^2 + (n + 1)(a - b)x + bn

(1) 当a==b时,t是常量bn;

(2) 当a<>b时,是一个二次函数,根据我们设置的条件,不能得到惟一的函数图形。

其顶点为: ((n + 1) / 2 , (a -b)(n + 1) ^ 2 / 4);

落在t轴上的坐标为: (0, bn);

落在x轴上的坐标为: 1/2的 (n + 1) ^ 2 + 4bn / (a - b) 平方根 - (n + 1);

说到最后,依然无法得出指导性的优化原则,当然了一般编程时并不需要去考虑这种问题,对代码效率影响太小了,并没有什么太多的实际意义。

你可能感兴趣的:(优化,循环)