লেজ পুনরাবৃত্তি কি?


52

আমি পুনরাবৃত্তি সাধারণ ধারণা জানি। কুইকোর্টের অ্যালগরিদম অধ্যয়ন করার সময় আমি লেজ পুনরাবৃত্তির ধারণাটি পেয়েছিলাম । 18:30 সেকেন্ডে এমআইটি থেকে দ্রুত সাজানোর অ্যালগরিদমের এই ভিডিওতে অধ্যাপক বলেছেন যে এটি একটি লেজ রিকার্সিভ অ্যালগরিদম। পুচ্ছ পুনরাবৃত্তি আসলে কী বোঝায় তা আমার কাছে পরিষ্কার নয়।

কেউ সঠিক উদাহরণ দিয়ে ধারণাটি ব্যাখ্যা করতে পারেন?

এখানে এসও সম্প্রদায় দ্বারা সরবরাহ করা কিছু উত্তর ।


আপনি যে প্রসঙ্গে পুচ্ছ পুনরাবৃত্তি শব্দটির মুখোমুখি হয়েছেন সে প্রসঙ্গে আমাদের আরও বলুন । লিঙ্ক করবেন? উদ্ধৃতি?
এ.চুল্জ

@ এ.চুলজ আমি প্রসঙ্গে লিঙ্কটি রেখেছি।
গিগ 9

5
তাকান " লেজ-পুনরাবৃত্তির কি? Stackoverflow এ"
মাস

2
@ আজমার্টিন প্রশ্নটি স্ট্যাক ওভারফ্লোতে সীমান্তরেখা তবে কম্পিউটার সায়েন্সের উপর দৃ firm়ভাবে অন-টপিক , সুতরাং নীতিগতভাবে কম্পিউটার বিজ্ঞানের আরও ভাল উত্তর দেওয়া উচিত। এটি এখানে ঘটেনি, তবে আরও ভাল উত্তরের আশায় এখানে পুনরায় জিজ্ঞাসা করা ঠিক আছে। গীক, আপনার নিজের প্রশ্নের আগেও তাই উল্লেখ করা উচিত ছিল, যাতে লোকেরা ইতিমধ্যে যা বলেছে তার পুনরাবৃত্তি না করে।
গিলস 15:59-তে

1
এছাড়াও আপনার বলা উচিত যে অস্পষ্ট অংশটি বা আপনি পূর্ববর্তী উত্তরগুলি দ্বারা কেন সন্তুষ্ট নন, আমি মনে করি এসও লোকেরা ভাল উত্তর সরবরাহ করে তবে আপনাকে আবার এটি জিজ্ঞাসা করার কারণ কী?

উত্তর:


52

টেল রিকার্সন পুনরাবৃত্তির একটি বিশেষ ক্ষেত্রে যেখানে কলিং ফাংশনটি পুনরাবৃত্তি কল করার পরে আর কোনও গণনা করে না। উদাহরণস্বরূপ, ফাংশন

int f (int x, int y) {
  যদি (y == 0) {
    রিটার্ন এক্স;
  }

  রিটার্ন এফ (x * y, y-1);
}

লেজ রিকার্সিভ (যেহেতু চূড়ান্ত নির্দেশটি একটি পুনরাবৃত্ত কল) যদিও এই ফাংশনটি লেজ পুনরাবৃত্তি নয়:

int g (int x) {
  যদি (x == 1)
    প্রত্যাবর্তন 1;
  }

  int y = g (x-1);

  এক্স x ওয়াই;
}

যেহেতু এটি পুনরাবৃত্তি কল ফিরে আসার পরে কিছু গণনা করে।

টেল পুনরুক্তি গুরুত্বপূর্ণ কারণ এটি সাধারণ পুনরাবৃত্তির চেয়ে আরও দক্ষতার সাথে প্রয়োগ করা যেতে পারে। যখন আমরা একটি সাধারণ পুনরাবৃত্তি কল করি, আমাদের কল স্ট্যাকের দিকে রিটার্নের ঠিকানাটি চাপতে হবে তারপরে ডাকা ফাংশনটিতে ঝাঁপ দাও। এর অর্থ হ'ল আমাদের একটি কল স্ট্যাকের প্রয়োজন যার আকার পুনরাবৃত্ত কলগুলির গভীরতায় রৈখিক। যখন আমাদের পুচ্ছ পুনরাবৃত্তি হয় আমরা জানি যে আমরা পুনরাবৃত্ত কল থেকে ফিরে আসার সাথে সাথে আমরা তত্ক্ষণাত্ ফিরে আসতে চলেছি, সুতরাং আমরা পুনরাবৃত্ত ফাংশনগুলির সম্পূর্ণ শৃঙ্খলা বাদ দিতে পারি এবং সরাসরি কলারটিতে ফিরে যেতে পারি। এর অর্থ আমাদের পুনরাবৃত্তির কলগুলির জন্য আমাদের কোনও কল স্ট্যাকের প্রয়োজন নেই এবং চূড়ান্ত কলটিকে একটি সহজ জাম্প হিসাবে কার্যকর করতে পারি, যা আমাদের স্থান বাঁচায়।


2
আপনি লিখেছেন "এর অর্থ আমাদের পুনরাবৃত্তির সমস্ত কলের জন্য কোনও কল স্ট্যাকের প্রয়োজন নেই"। কল স্ট্যাক সবসময় থাকবে, কেবল যে কলটির স্ট্যাকের মধ্যে ফেরতের ঠিকানা লেখা উচিত নয়, তাই না?
গীক

2
এটি আপনার গণনার মডেলটিকে কিছুটা ডিগ্রী নির্ভর করে :) তবে হ্যাঁ, একটি বাস্তব কম্পিউটারে কল স্ট্যাকটি এখনও রয়েছে, আমরা কেবল এটি ব্যবহার করছি না।
ম্যাট লুইস

যদি এটি চূড়ান্ত কল হয় তবে লুপের জন্য। সুতরাং আপনি উপরে আপনার সমস্ত গণনা করেন তবে তাদের কয়েকটি লুপের মতো করে করেনdef recurse(x): if x < 0 return 1; for i in range 100{ (do calculations) recurse(x)}
thed0ctor

13

সরলভাবে বলা হয়েছে, টেল রিকার্সন এমন একটি পুনরাবৃত্তি যা সংকলকটি "গোটো" কমান্ডের মাধ্যমে পুনরাবৃত্ত কলকে প্রতিস্থাপন করতে পারে, তাই সংকলিত সংস্করণটিকে স্ট্যাকের গভীরতা বাড়াতে হবে না।

কখনও কখনও একটি লেজ-পুনরাবৃত্তি ফাংশন ডিজাইনের জন্য অতিরিক্ত পরামিতিগুলির সাহায্যে আপনাকে একটি সহায়ক ফাংশন তৈরি করতে হবে।

উদাহরণস্বরূপ, এই হল না একটি পুচ্ছ-রিকার্সিভ ফাংশন:

int factorial(int x) {
    if (x > 0) {
        return x * factorial(x - 1);
    }
    return 1;
}

তবে এটি একটি পুচ্ছ-পুনরাবৃত্তি ফাংশন:

int factorial(int x) {
    return tailfactorial(x, 1);
}

int tailfactorial(int x, int multiplier) {
    if (x > 0) {
        return tailfactorial(x - 1, x * multiplier);
    }
    return multiplier;
}

কারণ সংকলক এর পুনরুক্তি ফাংশনটিকে পুনরায় লিখতে পারে এমন কোনও পুনঃবিবেচনাকারী হিসাবে, এর মতো কিছু ব্যবহার করে (সিউডোকোড):

int tailfactorial(int x, int multiplier) {
    start:
    if (x > 0) {
        multiplier = x * multiplier;
        x--;
        goto start;
    }
    return multiplier;
}

সংকলকটির নিয়মটি খুব সহজ: আপনি " return thisfunction(newparameters);" যখন খুঁজে পান, তখন এটি " " দিয়ে প্রতিস্থাপন করুন parameters = newparameters; goto start;। তবে এটি কেবল তখনই করা যেতে পারে যখন পুনরাবৃত্ত কলের দ্বারা প্রত্যাবর্তিত মানটি সরাসরি ফিরে আসে।

যদি কোনও ফাংশনের সমস্ত পুনরাবৃত্ত কলগুলি এইভাবে প্রতিস্থাপন করা যায়, তবে এটি একটি লেজ-পুনরাবৃত্তি ফাংশন।


13

আমার উত্তরটি কম্পিউটার প্রোগ্রামগুলির স্ট্রাকচার এবং ব্যাখ্যার বইটিতে প্রদত্ত ব্যাখ্যার ভিত্তিতে তৈরি হয়েছে । আমি এই বইটি কম্পিউটার বিজ্ঞানীদের কাছে অত্যন্ত সুপারিশ করি।

পদ্ধতির এ: লিনিয়ার রিকার্সিভ প্রক্রিয়া

(define (factorial n)
 (if (= n 1)
  1
  (* n (factorial (- n 1)))))

পদ্ধতির এটির প্রক্রিয়াটির আকারটি দেখতে এরকম দেখাচ্ছে:

(factorial 5)
(* 5 (factorial 4))
(* 5 (* 4 (factorial 3)))
(* 5 (* 4 (* 3 (factorial 2))))
(* 5 (* 4 (* 3 (* 2 (factorial 1)))))
(* 5 (* 4 (* 3 (* 2 (* 1)))))
(* 5 (* 4 (* 3 (* 2))))
(* 5 (* 4 (* 6)))
(* 5 (* 24))
120

পদ্ধতির বি: লিনিয়ার আইট্রেটিভ প্রক্রিয়া

(define (factorial n)
 (fact-iter 1 1 n))

(define (fact-iter product counter max-count)
 (if (> counter max-count)
  product
  (fact-iter (* counter product)
             (+ counter 1)
             max-count)))

পদ্ধতির বিয়ের প্রক্রিয়াটির আকারটি দেখতে এরকম দেখাচ্ছে:

(factorial 5)
(fact-iter 1 1 5)
(fact-iter 1 2 5)
(fact-iter 2 3 5)
(fact-iter 6 4 5)
(fact-iter 24 5 5)
(fact-iter 120 6 5)
120

লিনিয়ার ইটারেটিভ প্রসেস (অ্যাপ্রোচ বি) প্রক্রিয়াটি পুনরাবৃত্তি পদ্ধতি হলেও ধ্রুব স্থানে চলে। এটিও লক্ষ করা উচিত যে এই পদ্ধতির মধ্যে একটি সেট ভেরিয়েবলগুলি যে কোনও পর্যায়ে প্রক্রিয়াটির অবস্থা নির্ধারণ করে। {product, counter, max-count}। এটিও এমন একটি কৌশল যা দ্বারা পুচ্ছ পুনরাবৃত্তি সংকলক অপ্টিমাইজেশানকে মঞ্জুরি দেয়।

অ্যাপ্রোচ এ-তে আরও গোপন তথ্য রয়েছে যা দোভাষী তার রক্ষণাবেক্ষণ করেন যা মূলত পিছিয়ে যাওয়া ক্রিয়াকলাপগুলির শৃঙ্খলা।


5

টেইল-পুনরাবৃত্তি পুনরাবৃত্তির একটি ফর্ম যাতে পুনরাবৃত্তি কলগুলি ফাংশনের শেষ নির্দেশনা (এটিই পুচ্ছ অংশটি আসে) তদুপরি, পুনরাবৃত্ত কলটি পূর্ববর্তী মানগুলি সংরক্ষণ করে (ফাংশনের প্যারামিটারগুলি ব্যতীত অন্য রেফারেন্সগুলি) মেমরি কোষের রেফারেন্সের সাথে তৈরি করা উচিত নয়। এইভাবে, আমরা পূর্ববর্তী মানগুলি এবং সমস্ত পুনরাবৃত্ত কলগুলির জন্য একটি স্ট্যাক ফ্রেমই যথেষ্ট নয়; পুচ্ছ-পুনরাবৃত্তি পুনরাবৃত্তির অ্যালগরিদমগুলির অনুকূলকরণের একটি উপায়। অন্য সুবিধা / অপ্টিমাইজেশন হ'ল পুনরাবৃত্তির পরিবর্তে পুনরাবৃত্তি ব্যবহার করে এমন একটি সমপরিমাণে একটি লেজ-পুনরাবৃত্তির অ্যালগরিদমকে রূপান্তর করার একটি সহজ উপায় রয়েছে। হ্যাঁ, কুইকোর্টের জন্য অ্যালগরিদমটি আসলেই লেজ-পুনরাবৃত্ত হয়।

QUICKSORT(A, p, r)
    if(p < r)
    then
        q = PARTITION(A, p, r)
        QUICKSORT(A, p, q–1)
        QUICKSORT(A, q+1, r)

এখানে পুনরাবৃত্তি সংস্করণ:

QUICKSORT(A)
    p = 0, r = len(A) - 1
    while(p < r)
        q = PARTITION(A, p, r)
        r = q - 1

    p = 0, r = len(A) - 1
    while(p < r)
        q = PARTITION(A, p, r)
        p = q + 1
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.