简化/确定这个双向循环?

问题描述:

我把电线穿过某处(或者我没有足够的睡眠)。我需要一个双向循环,而我目前的代码只是简单的丑陋。简化/确定这个双向循环?

问题:我沿着一个使用索引的线性数据结构运行。我有一个开始索引,可以说120.我想在两个方向交替运行。

实施例: 120,121,119,122,118,123,117,...

我有需要分别满足每个方向停止标准。如果它满足一个方向,我只想跑向另一个方向,如果两个都满足,我需要退出循环。此外,如果下一个索引无效(数据结构结束,比如小于0或大于200),我需要停止。

示例:在116向后和130向前停止执行: 120,121,119,122,118,123,117,124,116,(中断),125,126,127,128,129,130​​。

先走向一个方向,然后另一个不幸的是不是一个选项。

我现在的代码很难看。这是很多行不包含任何“生产力”的代码。只有迭代逻辑:

int start_idx = 120; 
    int forward_idx = start_idx; 
    int backward_idx = start_idx; 

    bool next_step_forward = true; //should next step be forward or backward? 

    int cur_idx; 
    while(backward_idx >= 0 || forward_idx >= 0) 
    { 
    if(next_step_forward //if we should step forward 
     && forward_idx >= 0) //and we still can step forward 
    { 
     cur_idx = ++forward_idx; 

     if(forward_idx >= 200) //200 is fictive "max index" 
     { 
     next_step_forward = false; 
     forward_idx = -1; //end of data reached, no more stepping forward 
     continue; 
     } 

     if(backward_idx >= 0) 
     { 
     next_step_forward = false; 
     } 
    } 
    else if(!next_step_forward 
      && backward_idx >= 0) 
    { 
     cur_idx = --backward_idx; 
     if(backward_idx < 0) //beginning of data reached, no more stepping backward 
     { 
     next_step_forward = true; 
     continue; 
     } 

     if(forward_idx >= 0) 
     { 
     next_step_forward = true; 
     } 
    } 
    else 
    { 
     next_step_forward = !next_step_forward; //ever hit?, just security case 
     continue; 
    } 

    //loop body 
    //do something with cur_idx here 

    if(stoppingCriterionMet()) 
    { 

     if(cur_idx > start_idx) 
     { //this was a forward step, stop forward stepping 
     forward_idx = -1; 
     } 
     else 
     { //this was backward step, stop backward stepping 
     backward_idx = -1; 
     } 
    } 
    } 

我错过了什么吗?任何提示赞赏。谢谢。

编辑1:有很多非常好的答案,它们把“用cur_idx做某事”放到一个单独的函数中。虽然这对于我的问题被问到的方式来说是一个完美的想法,但我更喜欢将迭代代码放在其他地方,并将生产代码留在那里。我有一个很长的算法,并希望在完成后将其拆分,以尽量减少重新排列工作。

+0

你应该简化你的问题。而不是“线性数据结构”只是说数组。而不是“停止标准”,只是停留。如果你清理你的问题,你可能会看到一个更清洁的解决方案。 – 2010-09-10 20:57:08

+0

如果这是作业,你应该添加标签 – 2010-09-10 20:57:40

+0

对不起,我会去睡觉来解决这个问题。这不是功课。哪位疯子想纠正学生提出的解决方案? – B3ret 2010-09-10 21:15:45

恰巧我今天编写了这个问题。我使用C#迭代器函数来完成它。但我认为你想要一个更通用的解决方案。

如果您使用可以构建自己的迭代器(C++,Java,C#)的语言,那很容易。您只需制作一个自定义迭代器,最初从中心开始扫出数字。然后你给迭代器一个额外的函数来告诉它停止以当前方向运行。如果你在C中做这样的事情(它看起来像C),你可以用一个包含迭代器状态的结构和你调用的函数来模仿它,使它向前移动或停止它。

+0

低水平几何处理编程的日子似乎抢走了我的面向对象技能。 Gamma等人的设计模式正在从书架上嘲笑我,说“迭代器模式你是白痴,应该自己提出来”。谢谢你的提示。 – B3ret 2010-09-10 21:17:42

第一遍在黑客(假设ç - 需要对其他语言的适应,但其概念基本上是中性语言):

void pass1(int start_x, int lo_limit, int hi_limit) 
{ 
    assert(start_x >= lo_limit && start_x <= hi_limit); 
    int lo_x = start_x - 1; 
    int hi_x = start_x + 1; 

    Process(start_x); 
    if (StopCriterion(start_x)) 
     return; // Is that correct? 

    while (lo_x >= lo_limit && hi_x <= hi_limit) 
    { 
     Process(lo_x); 
     if (StopCriterion(lo_x)) 
      lo_x = lo_limit - 1; 
     else 
      lo_x--; 
     Process(hi_x); 
     if (StopCriterion(hi_x)) 
      hi_x = hi_limit + 1; 
     else 
      hi_x++; 
    } 
    while (lo_x >= lo_limit) 
    { 
     Process(lo_x); 
     if (StopCriterion(lo_x)) 
      lo_x = lo_limit - 1; 
     else 
      lo_x--; 
    } 
    while (hi_x <= hi_limit) 
    { 
     Process(hi_x); 
     if (StopCriterion(hi_x)) 
      hi_x = hi_limit + 1; 
     else 
      hi_x++; 
    } 
} 

目前尚不清楚如果起始位置停止准则相匹配应该发生什么。搜索应该完全停止,还是应该继续向上,向下或两种方式。我选择了“完全停止”,但可以为列出的任何选项制定案例。在“两者”的情况下,您甚至不会执行停止标准检查。

我也选择在上方向前做下方;它显然被微妙地颠倒过来。最后两个循环的顺序并不重要,因为如果两个方向在相同的迭代中终止,则不执行尾循环;如果只有一个方向终止,则相应的循环根本不会执行 - 只有另一个会执行。

,因为在那里仍有反复代码:

void pass2(int start_x, int lo_limit, int hi_limit) 
{ 
    assert(start_x >= lo_limit && start_x <= hi_limit); 
    int lo_x = start_x - 1; 
    int hi_x = start_x + 1; 

    Process(start_x); 
    if (StopCriterion(start_x)) 
     return; // Is that correct? 

    while (lo_x >= lo_limit && hi_x <= hi_limit) 
    { 
     Process_lo(&lo_x, lo_limit); 
     Process_hi(&hi_x, hi_limit); 
    } 
    while (lo_x >= lo_limit) 
     Process_lo(&lo_x, lo_limit); 
    while (hi_x <= hi_limit) 
     Process_hi(&hi_x, hi_limit); 
} 

void Process_lo(int *lo_x, int lo_limit) 
{ 
    Process(*lo_x); 
    if (StopCriterion(*lo_x)) 
     *lo_x = lo_limit - 1; 
    else 
     *lo_x--; 
} 

void Process_hi(int *hi_x, int hi_limit) 
{ 
    Process(*hi_x); 
    if (StopCriterion(*hi_x)) 
     *hi_x = hi_limit + 1; 
    else 
     *hi_x++; 
} 

可见性控制(静态函数)等离开了作为实现语言的细节。

+0

Upvote for nice three-loop-idea。不幸的是,我有很多数据需要传递给并从“process”或全球化(想想:10个不重要的数据结构)中获取。 – B3ret 2010-09-10 21:13:12

+0

@ B3ret:认为有10个成员的非平凡数据结构,通过引用传递。 – 2010-09-10 21:21:01

+0

当然通过引用/指针,但仍然不是很好看。但是,如果我想保持“低水平”绝对要走的路! – B3ret 2010-09-10 21:22:44

这个怎么样?

void do_loop(SomeType *arr, int start, int low, int high, int arr_max) 
{ 
    int downwardIndex, upwardIndex; 
    downwardIndex = upwardIndex = start; 
    while (downwardIndex > 0 && upwardIndex < arr_max) { 
     if (downwardIndex < low && upwardIndex > high) { 
      break; 
     } 
     if (downwardIndex > low) { 
      processElement(arr[downwardIndex]); 
      downwardIndex--; 
     } 
     if (upwardIndex < high) { 
      processElement(arr[upwardIndex]); 
      upwardIndex++; 
     } 
    } 
} 

这是我想接近它在C#:

const int UPPER_BOUND = 200; 
const int LOWER_BOUND = 0; 
const int START = 120; 
bool foundlower = false, foundupper = false; 
int upper, lower; 
upper = lower = START; 

while (!foundlower || !foundupper) { 
    if (!foundlower) { 
     if (--lower <= LOWER_BOUND) foundlower = true; 
     if (stoppingCriterionMet(lower)) foundlower = true; 
    } 

    if (!foundupper) { 
     if (++upper >= UPPER_BOUND) foundupper = true; 
     if (stoppingCriterionMet(upper)) foundupper = true; 
    } 
}