1

我的电线在某处交叉(或者我睡眠不足)。我需要一个双向循环,而我当前的代码简直丑陋。

问题:我正在使用索引沿着线性数据结构运行。我有一个起始索引,比如说 120。我想在两个方向交替运行。

示例:120,121,119,122,118,123,117,...

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

示例:在向后 116 和向前 130 处停止执行:120,121,119,122,118,123,117,124,116,(break),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 做某事”放入一个单独的函数中。虽然这对于提出我的问题的方式来说是一个完美的想法,但我更喜欢将迭代代码放在其他地方,并将生产代码留在那里。我有一个很长的算法,想在完成后将其拆分,以最大程度地减少重新排列工作。

4

4 回答 4

2

这个怎么样?

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++;
        }
    }
}
于 2010-09-10T21:19:22.187 回答
1

碰巧我今天几乎编写了这个问题。我使用了一个 C# 迭代器函数来做到这一点。但我认为你想要一个更通用的解决方案。

如果您使用一种可以构建自己的迭代器的语言(C++、Java、C#),那就很容易了。您只需创建一个自定义迭代器,该迭代器最初会从中心开始吐出数字。然后你给迭代器一个额外的函数来告诉它停止在当前方向上运行。

如果你在 C 中做这样的事情(它在我看来是 C),你可以用一个包含迭代器状态的结构来模仿它,以及你调用的函数来向前或停止它。

于 2010-09-10T21:02:10.827 回答
1

首先通过破解这个(假设 C - 其他语言需要适应,但这些概念基本上是语言中立的):

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++;
}

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

于 2010-09-10T21:07:09.403 回答
0

这就是我在 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;
    }
}
于 2010-09-10T21:25:36.610 回答