2010-09-10 111 views
1

我把電線穿過某處(或者我沒有足夠的睡眠)。我需要一個雙向循環,而我目前的代碼只是簡單的醜陋。簡化/確定這個雙向循環?

問題:我沿着一個使用索引的線性數據結構運行。我有一個開始索引,可以說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

回答

1

恰巧我今天編寫了這個問題。我使用C#迭代器函數來完成它。但我認爲你想要一個更通用的解決方案。

如果您使用可以構建自己的迭代器(C++,Java,C#)的語言,那很容易。您只需製作一個自定義迭代器,最初從中心開始掃出數字。然後你給迭代器一個額外的函數來告訴它停止以當前方向運行。如果你在C中做這樣的事情(它看起來像C),你可以用一個包含迭代器狀態的結構和你調用的函數來模仿它,使它向前移動或停止它。

+0

低水平幾何處理編程的日子似乎搶走了我的面向對象技能。 Gamma等人的設計模式正在從書架上嘲笑我,說「迭代器模式你是白癡,應該自己提出來」。謝謝你的提示。 – B3ret 2010-09-10 21:17:42

1

第一遍在黑客(假設ç - 需要對其他語言的適應,但其概念基本上是中性語言):

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

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