কোনও লুপকে (যখন / জন্য) পুনরাবৃত্তি করতে বা পুনরাবৃত্তি থেকে একটি লুপে রূপান্তর করার সাধারণ উপায়?


23

এই সমস্যাটি মূলত অ্যালগরিদমে ফোকাস করছে, সম্ভবত কিছু বিমূর্ত এবং আরও শিক্ষামূলক academic

উদাহরণটি একটি চিন্তার প্রস্তাব দিচ্ছে, আমি জেনেরিক উপায় চাই, সুতরাং উদাহরণটি কেবলমাত্র আপনার চিন্তাভাবনা সম্পর্কে আমাদের আরও স্পষ্ট করে তুলতে ব্যবহৃত হয়।

সাধারণভাবে বলতে গেলে, একটি লুপকে পুনরাবৃত্তিতে রূপান্তর করা যায়।

উদাহরণ:

for(int i=1;i<=100;++i){sum+=i;}

এবং এটি সম্পর্কিত পুনরাবৃত্ত হয়:

int GetTotal(int number)
{
   if (number==1) return 1;   //The end number
   return number+GetTotal(number-1); //The inner recursive
}

এবং অবশেষে এটি সহজ করার জন্য, একটি লেজ পুনরুক্তি প্রয়োজন:

int GetTotal (int number, int sum)
{
    if(number==1) return sum;
    return GetTotal(number-1,sum+number);
}

তবে বেশিরভাগ ক্ষেত্রে উত্তর দেওয়া এবং বিশ্লেষণ করা এত সহজ নয়। আমি যা জানতে চাই তা হ'ল:

1) আমরা কি একটি লুপকে (কখন / কখন ……) পুনরাবৃত্তিতে রূপান্তর করতে একটি "সাধারণ সাধারণ উপায়" পেতে পারি? এবং রূপান্তর করার সময় আমাদের কী ধরণের বিষয়গুলিতে মনোযোগ দেওয়া উচিত? রূপান্তর প্রক্রিয়াটির সাথে সাথে কয়েকটি নমুনা এবং আপনার পার্সুডো তত্ত্বের সাথে বিস্তারিত তথ্য লেখাই ভাল।

2) "রিকার্সিভ" এর দুটি রূপ রয়েছে: লাইনলি রিকার্সিভ এবং টেইল-রিকার্সিভ। তাহলে রূপান্তর করা ভাল কোনটি? আমাদের কোন "বিধি" আয়ত্ত করা উচিত?

3) কখনও কখনও আমাদের পুনরাবৃত্তির "ইতিহাস" রাখা প্রয়োজন, এটি সহজেই একটি লুপ বিবৃতিতে সম্পন্ন করা যায়:

উদাহরণ:

List<string> history = new List<string>();
int sum=0;
for (int i=1;i<=100;++i)
{
   if(i==1) history.Add(i.ToString()+"'s result is:1.");
   else
   {
     StringBuilder sub = new StringBuilder();

      for(int j=1;j<=i;++j)
      {
          if(j==i) sbu.Append(j.ToString());
          else
          {
            sub.Append(j.ToString()+"+");
          }
      }
    sum +=i;
    sbu.Append("'s result is:"+sum+Environment.NewLine);
   }
}

নীচে ফলাফল:

1 এর ফলাফল 1।

1 + 2 এর ফলাফল 3।

1 + 2 + 3 এর ফলাফল 6 …………

তবে আমি মনে করি ইতিহাসকে পুনরাবৃত্তিতে রাখা শক্ত, কারণ একটি পুনরাবৃত্তভিত্তিক অ্যালগরিদম শেষ ফলাফলটি পাওয়ার দিকে মনোনিবেশ করে এবং কল-ব্যাক রিটার্ন করে। সুতরাং এগুলি সমস্ত প্রোগ্রামিং ভাষা দ্বারা স্বয়ংক্রিয়ভাবে স্ট্যাক আকারে মেমরি বরাদ্দ করে স্ট্যাকের মাধ্যমে সম্পন্ন হয়। এবং কীভাবে আমরা প্রতিটি "স্ট্যাক মানগুলি" বের করে নিতে এবং পুনরাবৃত্ত আলগোরিদিমের মাধ্যমে একাধিক মান ফিরিয়ে দিতে পারি?

এবং "একটি পুনরাবৃত্ত আলগোরিদিম থেকে একটি লুপ" সম্পর্কে কী? এগুলি কি একে অপরে রূপান্তরিত হতে পারে (আমি মনে করি এটি তাত্ত্বিকভাবে করা উচিত, তবে আমি আমার চিন্তাভাবনা প্রমাণ করার জন্য আরও সঠিক জিনিস চাই)


"পার্সুডো" এর অর্থ কী?
gnat

উত্তর:


30

আসলে আপনার প্রথমে ফাংশনটি ভেঙে দেওয়া উচিত:

একটি লুপের কয়েকটি অংশ রয়েছে:

  1. শিরোনাম এবং লুপ আগে প্রক্রিয়াজাতকরণ । কিছু নতুন ভেরিয়েবল ঘোষণা করতে পারে

  2. শর্ত, কখন লুপ থামাতে হবে।

  3. আসল লুপ বডি। এটি শিরোনামের কিছু ভেরিয়েবল এবং / অথবা পরামিতিগুলিতে পাস করেছে।

  4. লেজ; লুপ এবং রিটার্ন ফলাফলের পরে কী ঘটে।

বা এটি লিখতে:

foo_iterative(params){
    header
    while(condition){
        loop_body
    }
    return tail
}

পুনরাবৃত্তি কল করার জন্য এই ব্লকগুলি ব্যবহার করা বেশ সোজা is

foo_recursive(params){
    header
    return foo_recursion(params, header_vars)
}

foo_recursion(params, header_vars){
    if(!condition){
        return tail
    }

    loop_body
    return foo_recursion(params, modified_header_vars)
}

এট ভয়েইল; যে কোনও লুপের একটি লেজ পুনরাবৃত্ত সংস্করণ। লুপের শরীরে breakগুলি এবং continueগুলিগুলি এখনও প্রতিস্থাপন করতে হবে return tailএবং foo_recursion(params, modified_header_vars)প্রয়োজন অনুসারে ফিরে আসতে হবে তবে এটি যথেষ্ট সহজ।


অন্য পথে যাওয়া আরও জটিল; অংশে কারণ একাধিক পুনরাবৃত্ত কল হতে পারে। এর অর্থ হ'ল প্রতিবার যখন আমরা স্ট্যাক ফ্রেমটি পপ করব তখন একাধিক জায়গা থাকতে পারে যেখানে আমাদের চালিয়ে যাওয়া দরকার to এছাড়াও এমন পরিবর্তনগুলি থাকতে পারে যা আমাদের পুনরাবৃত্ত কল এবং কলটির মূল পরামিতিগুলি জুড়ে সংরক্ষণ করতে হবে।

আমরা এটি ঘিরে কাজ করতে একটি স্যুইচ ব্যবহার করতে পারি:

bar_recurse(params){
    if(baseCase){
        finalize
        return
    }
    body1
    bar_recurse(mod_params)
    body2
    bar_recurse(mod_params)
    body3
}


bar_iterative(params){
    stack.push({init, params})

    while(!stack.empty){
        stackFrame = stack.pop()

        switch(stackFrame.resumPoint){
        case init:
            if(baseCase){
                finalize
                break;
            }
            body1
            stack.push({resum1, params, variables})
            stack.push({init, modified_params})
            break;
        case resum1:
            body2
            stack.push({resum2, params, variables})
            stack.push({init, modified_params})
            break;
        case resum2:
            body3
            break;
        }
    }
}

0

@ র্যাচেট ফ্রিকের উত্তর অনুসরণ করে, আমি জাভাতে ফাইবোনাচি ফাংশনটি কীভাবে কিছুক্ষণের জন্য আবার লিখতে পারি তার এই উদাহরণটি তৈরি করেছি। মনে রাখবেন যে কিছুক্ষণের লুপের সাথে ফিবোনাচি পুনর্লিখনের অনেক সহজ (এবং দক্ষ) উপায় রয়েছে।

class CallContext { //this class is similar to the stack frame

    Object[] args;

    List<Object> vars = new LinkedList<>();

    int resumePoint = 0;

    public CallContext(Object[] args) {
        this.args = args;
    }

}


static int fibonacci(int fibNumber) {
    Deque<CallContext> callStack = new LinkedList<>();
    callStack.add(new CallContext(new Object[]{fibNumber}));
    Object lastReturn = null; //value of last object returned (when stack frame was dropped)
    while (!callStack.isEmpty()) {
        CallContext callContext = callStack.peekLast();
        Object[] args = callContext.args;
        //actual logic starts here
        int arg = (int) args[0];
        if (arg == 0 || arg == 1) {
            lastReturn = arg;
            callStack.removeLast();
        } else {
            switch (callContext.resumePoint) {
                case 0: //calculate fib(n-1)
                    callStack.add(new CallContext(new Object[]{arg - 1}));
                    callContext.resumePoint++;
                    break;
                case 1: //calculate fib(n-2)
                    callContext.vars.add(lastReturn); //fib1
                    callStack.add(new CallContext(new Object[]{arg - 2}));
                    callContext.resumePoint++;
                    break;
                case 2: // fib(n-1) + fib(n-2)
                    callContext.vars.add(lastReturn); //fib2
                    lastReturn = (int) callContext.vars.get(0) + (int) callContext.vars.get(1);
                    callStack.removeLast();
                    break;
            }
        }
    }
    return (int) lastReturn;
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.