如何改写多重循环 (只用2个循环替代N个循环)

假设有类似下面的多重循环:

for(i=0; i<3; i++)
    for (j=2; j<6; j++)
       for (k=5; k<16; k++)
            for (l=3; l<5; l++)
              {
                 //do something with i,j,k,l
              }

像上面一共有4重循环,有时候可能更多,如何将任意多重循环用2重循环来改写呢?

 

方法1:
 

int main()
{
    vector<int> upper = {3,6,16,5};
    vector<int> lower = {0,2,5,3};
    vector<int> index = lower;
    int level;

    do{
        level =upper.size() - 1;
          
       //do something with index[]
       for (auto i : index) cout<<i<<" ";
        cout<<endl;
          
        while(level >= 0 && (++index[level] >= upper[level])) {
            index[level] = lower[level];
            level--;
        }
    } while (level >= 0);

    return 0;
}

输出结果为:
0 2 5 3
0 2 5 4
0 2 6 3
...

2 5 15 3                                                                                                              
2 5 15 4    

上面的两层循环中,外层的do循环每次都从level=3开始,经过内层循环后检测level是不是还>=0。内层循环会做如下工作:
1) ++index[level]
2) 判断当前的level是不是已经到边界(upper[level]),
 如果已到边界,将index[level]重新置为起始值,并将level减1,也就是到了上面一层;
 否则跳过内层循环。
3) 什么时候终止外层循环呢? 当level < 0时。而level<0只有可能内部的while循环总共执行了4次已经,即index[0], index[1], index[2], index[3]分别和lower[0], lower[1], lower[2], lower[3]相等后,level再--,此时level = -1。

如果还想不明白,在//do something的地方打印出index[0],index[1], index[2], index[3]即可,它们分别对应前面的i,j,k,l。也可以用下面的方法,原理差不多:

方法2:

注意do while循环只有当level = -1才终止。此时对应所以的组合都打印完毕,即从0,2, 6, 5打印到2,5,15,4,最后当index[]={2,5,15,4}时,对应for循环内部level--已经执行了4次,然后level再--,此时level = -1。注意没有打印到最后时,for循环内部level--都没有执行过4次,因为都break出来了。

int main()
{
    const vector<int> upper = {3, 6, 16, 5};
    const vector<int> lower = {0, 2, 5, 3};
    vector<int> index = lower;
    int level;

    do{
        for (auto i : index) cout<<i<<" ";
        cout<<endl;
          
        for (level = upper.size() - 1; level >= 0; level--) {
            index[level]++;
            if (index[level] >= upper[level]) 
                index[level] = lower[level];
            else 
                break;
            
        }
    } while (level >= 0);

    return 0;
}

方法3:

说起循环我们就应该想到递归,所以我们也可以用递归来改写这个多重循环,原理跟上面的方法差不多,只是外层循环用递归代替了。代码如下:

const vector<int> upper = {3, 6, 16, 5};
const vector<int> lower = {0, 2, 5, 3};

void dfs(vector<int> & nums, int level) {

    //do something with arr[], such as print
    for (auto n : nums) cout<<n<<" ";
    cout<<endl;
    
    bool endCondition = true;
    for (int i = 0; i <= level; ++i) {
        if (nums[i] < upper[i] - 1) {
            endCondition = false;
            break;
        }
    }
    
    if (endCondition) return;
    
    for (int i = nums.size() - 1; i >= 0; i--) {
        nums[i]++;
        if (nums[i] >= upper[i])
            nums[i] = lower[i];
        else
            break;
    }
    
    dfs(nums, level);
}

int main()
{
    vector<int> nums = lower;
    dfs(nums, 4);

    return 0;
}

调用的时候用dfs(index, 3)即可。


 

 

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值