سؤال

لقد عبرت أسلاكي في مكان ما (أو لم يكن لدي نوم كافي). أحتاج إلى حلقة ثنائية الاتجاه ، والرمز الحالي الخاص بي هو مجرد قبيح.

المشكلة: أنا أقوم بتشغيل دانستستروستري خطي باستخدام فهرس. لدي فهرس بدء ، دعنا نقول 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" في وظيفة منفصلة. على الرغم من أن هذه فكرة مثالية للطريقة التي تم طرح سؤالي بها ، إلا أنني أفضل وضع الرمز المتردد في مكان آخر وترك الرمز الإنتاجي هناك. لدي خوارزمية طويلة وأريد تقسيمها بعد الانتهاء من ذلك لتقليل أعمال التخلف.

هل كانت مفيدة؟

المحلول

لقد حدث ذلك لدرجة أنني قمت بترميز هذه المشكلة تقريبًا اليوم. واستخدمت وظيفة C# ITerator للقيام بذلك. لكني أعتقد أنك تريد حلًا أكثر عامة.

إذا كنت تستخدم لغة يمكنك من خلالها إنشاء تكراراتك الخاصة (C ++ ، Java ، C#) ، فهذا أمر سهل. أنت فقط تصنع جهازًا مخصصًا مخصصًا يبصق في البداية الأرقام بدءًا من المركز. ثم تعطي التكرار وظيفة إضافية لإخبارها بالتوقف عن التشغيل في الاتجاه الحالي.

إذا كنت تفعل شيئًا كهذا في C (يبدو أنه C بالنسبة لي) ، فيمكنك محاكاة ذلك بهيكل يحتوي على حالة التكرار ، والوظائف التي تدعوها لتوجيهها للأمام أو إيقافها.

نصائح أخرى

وماذا عن هذا؟

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 - التعديلات اللازمة للغات الأخرى ، ولكن المفاهيم هي أساسًا لغة محايدة):

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

ضوابط الرؤية (وظائف ثابتة) وما إلى ذلك تم تركها كتفاصيل لغة التنفيذ.

هذه هي الطريقة التي سأقترب بها في 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;
    }
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top