简体   繁体   中英

What loop is more efficient?

I want to know which code is more efficient, and I have two options. Which would you say it is more efficient and why? Thank you.

Option A

array1 size is 1000
array2 size is 2000

for(int i = 0; i < array1.size(); i++)
{
    for(int j = 0; j < array2.size(); j++) {
        if(array1[i].method() == array2[j].method()) // CHECKS IF THERE'S AN EQUAL IN BOTH ARRAYS
        {
            doSomething();
            break;
        }
        if(j == array2.size()-1) // CHECKS IF ARRAY1 DID NOT FIND A MATCH
        {
            doSomething();
            break;
        }
        for(k = 0; k < array1.size(); k++)
        {
            if(array1[k].method() == array2[j].method()) // CHECKS IF THERE'S AN EQUAL IN BOTH ARRAYS
            {
                // BUT DOES NOTHING BECAUSE IT WAS DONE ALREADY UPSIDE
                break;
            }
            if(k == array1.size()-1) // CHECKS IF ARRAY2 DID NOT FIND A MATCH
            {
                doSomething();
                break;
            }
        }
    }
}

Option B

array1 size is 1000
array2 size is 2000


    for(int i = 0; i < array1.size(); i++)
    {
        for(int j = 0; j < array2.size(); j++) {
            if(array1[i].method() == array2[j].method()) // CHECKS IF THERE'S AN EQUAL IN BOTH ARRAYS
            {
                doSomething();
                break;
            }
            if(j == array2.size-1)  // CHECKS IF ARRAY1 HAS NO ARRAY2 MATCH
            {
                doSomething();
                break;
            }
        }
    }

    for(int j = 0; j < array2.size(); j++)
    {
        for(int i = 0; i < array1.size(); i++) {
            if(array2[j].method() == array1[i].method()) // CHECKS IF THERE'S AN EQUAL IN BOTH ARRAYS
            {
                // BUT DOES NOTHING BECAUSE IT WAS DONE ALREADY UPSIDE
                break;
            }
            if(i == array1.size-1) // CHECKS IF ARRAY2 HAS NO ARRAY1 MATCH
            {
                doSomething();
                break;
            }
        }
    }

I currently have OPTION B implemented and I am wondering if I should move to OPTION A, because although Options A may take more time, I don't know if it will take more time doing both loops or one doing all the iterations. Or maybe are the same, I don't really know about it.

Option A is O(x^2*y) Option B is O(x*y) in your case option A will take up to 2,000,000,000 iterations while B will take up to 4,000,000 iterations. This doesn't include breaks or continues of course. I would probably stick with B.

As said by @Sploder12 but you will also gain a lot taking out the function calls in the loop eg

int n= array.size()
for(int i=0; i<n; i++)

rather than

 for(int i=0; i<array.size(); i++)

Unless you are modifying array size within loop the repeated function calls are a waste.

Regarding the comment of @Turing85 I did wonder whether or not there might be some compiler mechanism which could spot the fact that the return value of size() in the loop initialisations may be constant and therefore could be replaced with a constant "effecively final". I therefore ran the following two loops, the first without the manual constant optimisation:

int n1=a1.size();
for(int i=0; i<a1.size(); i++) {
    int n2=a2.size();
    for(int j=0; j<a2.size(); j++) {
        int n3=a3.size();
        for(int k=0; k<a3.size(); k++) {
            int candidate=a1.get(i)*a2.get(j)*a3.get(k);
            candidate+=n1*n2*n3;
            func(candidate);
        }//k
    }//j
}//i

The second with a manual constant optimisation:

int n1=a1.size();
for(int i=0; i<n1; i++) {
    int n2=a2.size();
    for(int j=0; j<n2; j++) {
        int n3=a3.size();
        for(int k=0; k<n3; k++) {
            int candidate=a1.get(i)*a2.get(j)*a3.get(k);
            candidate+=n1*n2*n3;
            func(candidate);
        }//k
    }//j
}//i

I then ran these loops 10 times with a1.size()=100, a2.size()=200, and a3.size()=300 to get a time and calculated the mean and standard error of 100 times for each variation of the loop with the order of the 200 runs randomised.

This whole process was repeated 10 times within a single job (ie a single invocation of the JVM) to obtain 10 paired means and standard errors (one member of the pair from the optimised runs and the other from the unoptimised runs). In all 10 cases the optimised mean times were considerably faster than the unoptimised mean times. In every case the difference between the means was more than 6.9 times the standard error and in 7 out of the 10 cases the difference between the means was more than 15 standard errors. The data are given below. The byte code generated for the loops was different and although I don't claim to speak bytecode there were additional invokevirtual calls to a*.size() which I assume are responsible for differences in the performance of the two loop versions.

So, taking into account the comment from @Turing85 I wonder about the conditions under which optimisations "on this level" can be ignored?

openjdk version "11" 2018-09-25 OpenJDK Runtime Environment 18.9 (build 11+28) OpenJDK 64-Bit Server VM 18.9 (build 11+28, mixed mode)

====== Data ======

100 runs of optimised loop took on average 6.412s each, standard error 0.013; 100 runs of unoptimised loop took on average 6.502s each, standard error 0.013

100 runs of optimised loop took on average 5.143s each, standard error 0.004; 100 runs of unoptimised loop took on average 5.232s each, standard error 0.005

100 runs of optimised loop took on average 6.090s each, standard error 0.006; 100 runs of unoptimised loop took on average 6.175s each, standard error 0.006

100 runs of optimised loop took on average 5.739s each, standard error 0.005; 100 runs of unoptimised loop took on average 5.827s each, standard error 0.005

100 runs of optimised loop took on average 5.613s each, standard error 0.005; 100 runs of unoptimised loop took on average 5.697s each, standard error 0.004

100 runs of optimised loop took on average 6.045s each, standard error 0.004; 100 runs of unoptimised loop took on average 6.121s each, standard error 0.004

100 runs of optimised loop took on average 5.333s each, standard error 0.003; 100 runs of unoptimised loop took on average 5.415s each, standard error 0.003

100 runs of optimised loop took on average 5.903s each, standard error 0.009; 100 runs of unoptimised loop took on average 5.972s each, standard error 0.007

100 runs of optimised loop took on average 5.770s each, standard error 0.005; 100 runs of unoptimised loop took on average 5.851s each, standard error 0.005

100 runs of optimised loop took on average 4.975s each, standard error 0.004; 100 runs of unoptimised loop took on average 5.052s each, standard error 0.004

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM