我的电线在某处交叉(或者我的睡眠不足)。我需要一个双向循环,而我当前的代码很简单。
问题:我使用索引运行线性数据结构。我有一个起始指数,比方说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 :(得分: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++;
}
}
}
答案 1 :(得分:1)
碰巧我今天几乎把这个问题编码了。我使用了C#迭代器函数来完成它。但我认为你想要一个更通用的解决方案。
如果您使用的语言可以构建自己的迭代器(C ++,Java,C#),那么很容易。你只需要创建一个自定义迭代器,它最初从中心开始吐出数字。然后你给迭代器一个额外的函数来告诉它停止在当前方向上运行。
如果你在C中做这样的事情(它看起来对我而言),你可以用包含迭代器状态的结构和你调用的函数来模仿它,以便将它向前推进或停止它。
答案 2 :(得分: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++;
}
}
如果起始位置与停止标准匹配,则不清楚会发生什么。搜索应该完全停止,还是应该继续向上,向下或两种方式。我选择了“完全停止”,但可以为列出的任何选项提供案例。在'both'的情况下,你甚至都不愿意进行停止标准检查。
我也选择在向上方向前做下部;它显然是平凡的逆转。最后两个循环的顺序无关紧要,因为如果两个方向都在同一次迭代中终止,则不执行尾随循环;如果只有一个方向被终止,则相应的循环根本不会执行 - 只有另一个方向将执行。
由于那里仍然有重复的代码:
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++;
}
可见性控件(静态函数)等被遗漏为实现语言的细节。
答案 3 :(得分: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;
}
}