حل رابطه‌های بازگشتی: Substitution، Recursion-Tree، و روش استاد

زمان اجرای هر الگوریتم تقسیم‌و‌غلبه توسط یک رابطه بازگشتی توصیف می‌شود، و حل آن رابطه برای درک کارایی الگوریتم ضروری است. این راهنمای جامع سه تکنیک استاندارد برای حل رابطه‌های بازگشتی را پوشش می‌دهد: روش substitution برای اثبات یک کران حدس‌زده‌شده، روش recursion-tree برای تولید یک حدس، و روش استاد به‌عنوان یک میان‌بر سریع برای یک دسته رایج از رابطه‌های بازگشتی.

رابطه‌های بازگشتیقضیه استادروش درخت بازگشت

~6 دقیقه مطالعه · آخرین به‌روزرسانی ۱۶ شهریور ۱۴۰۵

چرا الگوریتم‌های تقسیم‌و‌غلبه به رابطه‌های بازگشتی نیاز دارند

یک الگوریتم تقسیم‌و‌غلبه، همان‌طور که پیش‌تر در این مجموعه درباره ضرب ماتریس معرفی شد، یک مسئله به اندازه n را به زیرمسئله‌های کوچک‌تر می‌شکند، هرکدام را به‌طور بازگشتی حل می‌کند، و نتایج را ترکیب می‌کند. این ساختار به‌طور طبیعی یک Recurrence (رابطه بازگشتی) تولید می‌کند: یک معادله یا نامعادله که یک تابع را برحسب مقدارش روی ورودی‌های کوچک‌تر توصیف می‌کند. حل یک رابطه بازگشتی یعنی یافتن یک کران مجانبی صریح و بسته، که معمولاً با نمادگذاری‌ای که پیش‌تر در این مجموعه پوشش داده شد بیان می‌شود.

یک رابطه بازگشتی تقسیم‌و‌غلبه کلی این شکل را دارد:

T(n) = a · T(n/b) + f(n)

جایی که a تعداد زیرمسئله‌های ایجادشده است، n/b اندازه هر زیرمسئله است، و f(n) زمان صرف‌شده برای تقسیم مسئله و ترکیب راه‌حل‌های زیرمسئله است.

روش Substitution: حدس بزن و اثبات کن

Substitution Method شامل حدس زدن شکل راه‌حل، سپس استفاده از استقرای ریاضی برای اثبات درستی حدس است. این روش به هیچ فرمول خاصی نیاز ندارد، اما به یک حدس اولیه خوب نیاز دارد، که اغلب توسط تجربه یا یک تحلیل recursion-tree اطلاع‌رسانی می‌شود.

به‌عنوان یک مثال کارشده، اثبات اینکه T(n) = 2T(n/2) + n برابر O(n log n) است را در نظر بگیرید. حدس این است که T(n) ≤ cn log n برای یک ثابت c و n به‌اندازه کافی بزرگ.

فرض استقرایی: فرض کن T(n/2) ≤ c(n/2)log(n/2)

جایگذاری در رابطه بازگشتی:
T(n) = 2T(n/2) + n
     ≤ 2c(n/2)log(n/2) + n
     = cn log(n/2) + n
     = cn(log n - 1) + n
     = cn log n - cn + n
     ≤ cn log n

گام آخر هروقت c ≥ 1 برقرار است،
چون آنگاه -cn + n ≤ 0

این گام استقرایی را تأیید می‌کند؛ یک استدلال حالت‌پایه جداگانه برای n کوچک اثبات را کامل می‌کند، و ثابت می‌کند T(n) = O(n log n).

یک دام رایج هنگام استفاده از substitution، اثبات یک کران ضعیف‌تر از نیاز با استفاده از یک فرض استقرایی به‌اندازه کافی دقیق نیست. گاهی تکنیکی به نام Subtracting a Lower-Order Term (کم کردن یک جمله مرتبه‌پایین‌تر) ضروری است: به‌جای حدس زدن T(n) ≤ cn، حدس زدن T(n) ≤ cn - b برای یک ثابت b می‌تواند استقرا را وقتی حدس ساده‌تر شکست می‌خورد، پیش ببرد.

روش Recursion-Tree: تصویرسازی کل کار

Recursion-Tree Method راهی سیستماتیک برای تولید یک حدس خوب برای روش substitution با تصویرسازی رابطه بازگشتی به‌صورت یک درخت فراهم می‌کند، جایی که هر گره هزینه یک زیرمسئله در یک سطح بازگشت را نشان می‌دهد.

رابطه بازگشتی T(n) = 3T(n/4) + Θ(n²) را در نظر بگیرید. درخت بازگشت این‌طور به‌نظر می‌رسد:

سطح 0:              n²                          — هزینه: n²
سطح 1:      (n/4)²  (n/4)²  (n/4)²               — هزینه: 3(n/4)²
سطح 2:  9 گره، هرکدام (n/16)²                    — هزینه: 9(n/16)²
...ادامه تا زیرمسئله‌ها به اندازه 1 برسند...

سطح i دارای 3^i گره است، هرکدام به اندازه n/4^i،
پس هزینه در سطح i برابر 3^i · (n/4^i)² است
                        = n² · (3/16)^i

جمع هزینه در سراسر همه سطوح، از سطح ۰ تا برگ‌ها، یک سری هندسی می‌دهد:

T(n) = n² · Σ (i=0 تا log₄n) (3/16)^i

از آنجا که 3/16 < 1، این سری هندسی به
یک ثابت همگرا می‌شود با رشد تعداد جملات، محدودشده توسط:
1 / (1 - 3/16) = 16/13

بنابراین T(n) = O(n²)

درخت بازگشت آشکار می‌کند هزینه توسط سطح ریشه غالب است، چون نسبت بین سطوح به‌طور هندسی کوچک می‌شود. این بینش — که سطح بالا غالب است — تبدیل به حدسی می‌شود که باید با استفاده از روش substitution توصیف‌شده در بالا به‌طور دقیق تأیید شود.

روش استاد: یک فرمول مستقیم برای موارد رایج

Master Method یک راه‌حل سریع و "کتاب‌آشپزی" برای رابطه‌های بازگشتی فرم استاندارد تقسیم‌و‌غلبه T(n) = aT(n/b) + f(n) فراهم می‌کند، جایی که a ≥ 1 و b > 1 ثابت‌اند و f(n) از نظر مجانبی مثبت است. با مقایسه f(n) در برابر n^(log_b a)، هزینه‌ای که خود بازگشت (نادیده‌گرفتن گام ترکیب) تولید می‌کند، کار می‌کند.

قضیه استاد — سه حالت:

حالت ۱: اگر f(n) = O(n^(log_b a - ε)) برای یک ε > 0،
        آنگاه T(n) = Θ(n^(log_b a))
        (زیرمسئله‌های بازگشتی غالب‌اند)

حالت ۲: اگر f(n) = Θ(n^(log_b a))،
        آنگاه T(n) = Θ(n^(log_b a) · log n)
        (هزینه بازگشت و ترکیب متوازن‌اند)

حالت ۳: اگر f(n) = Ω(n^(log_b a + ε)) برای یک ε > 0،
        و شرط قاعده‌مندی a·f(n/b) ≤ c·f(n)
        برای یک c < 1 و n بزرگ برقرار باشد،
        آنگاه T(n) = Θ(f(n))
        (گام ترکیب غالب است)

به‌کارگیری این روی رابطه‌های بازگشتی ضرب ماتریس پیش‌تر در این مجموعه، روش را ملموس می‌کند.

تقسیم‌و‌غلبه ساده: T(n) = 8T(n/2) + Θ(n²)
a = 8, b = 2, پس n^(log_b a) = n^(log₂8) = n³
f(n) = n² = O(n^(3-ε)) برای ε = 1  → حالت ۱
T(n) = Θ(n³)

الگوریتم اشتراسن: T(n) = 7T(n/2) + Θ(n²)
a = 7, b = 2, پس n^(log_b a) = n^(log₂7) ≈ n^2.807
f(n) = n² = O(n^(2.807-ε))  → حالت ۱
T(n) = Θ(n^log₂7) ≈ Θ(n^2.807)

یک مثال رایج دیگر T(n) = 2T(n/2) + n است، که الگوریتم‌هایی مانند merge sort را توصیف می‌کند.

a = 2, b = 2, پس n^(log_b a) = n^(log₂2) = n¹ = n
f(n) = n = Θ(n^1)  → حالت ۲ دقیقاً اعمال می‌شود
T(n) = Θ(n log n)

چرا روش استاد محدودیت دارد

روش استاد هر رابطه بازگشتی ممکن را پوشش نمی‌دهد. یک شکاف بین حالت ۱ و حالت ۲ وجود دارد، و شکاف دیگری بین حالت ۲ و حالت ۳، جایی که f(n) از نظر مجانبی بزرگ‌تر یا کوچک‌تر از تابع مقایسه است اما نه با یک فاکتور چندجمله‌ای. در این موارد شکاف، و هروقت شرط قاعده‌مندی در حالت ۳ شکست بخورد، روش استاد صرفاً اعمال نمی‌شود، و باید به‌جای آن از روش‌های substitution یا recursion-tree توصیف‌شده در بالا استفاده شود.

علاوه‌براین، روش استاد فقط رابطه‌های بازگشتی از این فرم مشخص تقسیم‌و‌غلبه با زیرمسئله‌هایی به اندازه یکسان را مدیریت می‌کند. رابطه‌های بازگشتی با اندازه زیرمسئله نابرابر، مانند آن‌هایی که از برخی الگوریتم‌های تصادفی که بعداً در این مجموعه بحث می‌شوند ناشی می‌شوند، به تکنیک‌های عمومی‌تری مانند روش Akra-Bazzi نیاز دارند، گسترشی که در بخش‌های پیشرفته‌تر نظریه رابطه بازگشتی پوشش داده می‌شود.

انتخاب ابزار درست

در عمل، روش استاد باید ابتدا برای هر رابطه بازگشتی استاندارد تقسیم‌و‌غلبه امتحان شود، چون تا حد زیادی سریع‌ترین تکنیک هنگام قابل‌اعمال‌بودن است. وقتی شرایط روش استاد برآورده نمی‌شوند، روش recursion-tree راهی سیستماتیک برای تولید یک حدس آگاهانه درباره شکل راه‌حل فراهم می‌کند، و روش substitution سپس اثبات دقیق درست بودن حدس را فراهم می‌کند. با هم، این سه تکنیک اکثریت قریب‌به‌اتفاق رابطه‌های بازگشتی مواجه‌شده هنگام تحلیل الگوریتم‌های تقسیم‌و‌غلبه را پوشش می‌دهند.

نوشته و پژوهش‌شده توسط دکتر شاهین صیامی

مقالات مرتبط

ساختارهای داده ابتدایی: پشته‌ها، صف‌ها، لیست‌های پیوندی، و درخت‌ها

پیش از پرداختن به ساختارهای داده پیشرفته، تسلط بر بلوک‌های سازنده ابتدایی ضروری است، چون تقریباً هر ساختار پیچیده‌ای از این پایه‌ها ساخته می‌شود. این راهنمای جامع پشته‌ها و صف‌های مبتنی بر آرایه، لیست‌های پیوندی تکی و دوگانه، و تکنیک‌های استاندارد نمایش درخت‌های ریشه‌دار را پوشش می‌دهد، شامل نمایش ظریف فرزند-چپ راهبر-راست برای درخت‌هایی با شاخه‌بندی نامحدود.

ادامه

یافتن میانه بدون مرتب‌سازی کامل: الگوریتم‌های انتخاب زمان-خطی

یافتن k-امین کوچک‌ترین عنصر در یک آرایه مرتب‌نشده نیازمند هزینه کامل Θ(n log n) مرتب‌سازی نیست؛ می‌تواند در زمان خطی انجام شود. این راهنمای جامع مورد بدیهی یافتن حداقل یا حداکثر، یک الگوریتم انتخاب تصادفی ظریف با زمان مورد انتظار خطی، و یک الگوریتم قطعی پیچیده‌تر که زمان خطی را حتی در بدترین‌حالت تضمین می‌کند را پوشش می‌دهد.

ادامه

شکستن مانع n log n: توضیح الگوریتم‌های مرتب‌سازی زمان-خطی

هر الگوریتم مرتب‌سازی مبتنی بر مقایسه در بدترین‌حالت حداقل به زمان Ω(n log n) نیاز دارد، اما الگوریتم‌هایی که کاملاً از مقایسه اجتناب می‌کنند می‌توانند تحت شرایط درست در زمان خطی مرتب کنند. این راهنمای جامع کران پایین مرتب‌سازی مبتنی‌بر‌مقایسه را با استدلال درخت تصمیم اثبات می‌کند، سپس سه الگوریتم زمان-خطی — counting sort، radix sort، و bucket sort — را همراه با فرضیات ورودی خاصی که هرکدام نیاز دارند توضیح می‌دهد.

ادامه

Quicksort: راهنمای کامل توصیف، کارایی، و تصادفی‌سازی

Quicksort یکی از پراستفاده‌ترین الگوریتم‌های مرتب‌سازی در عمل است، که به‌خاطر کارایی عالی حالت‌میانگین و عملیات درجا ارزشمند است، با وجود داشتن بدترین‌حالت نظری ضعیف. این راهنمای جامع الگوریتم مبتنی بر partition را با جزئیات پوشش می‌دهد، هم زمان اجرای بدترین‌حالت و هم مورد انتظار آن را تحلیل می‌کند، و توضیح می‌دهد تصادفی‌سازی چگونه آن را به یک الگوریتم به‌طور قابل‌اعتماد کارآمد صرف‌نظر از ترتیب ورودی تبدیل می‌کند.

ادامه

Heapsort و صف‌های اولویت: راهنمای کامل هیپ دودویی

هیپ دودویی یکی از ظریف‌ترین ساختارهای داده در علوم کامپیوتر است، که هم یک الگوریتم مرتب‌سازی کارآمد درجا و هم انتزاع صف اولویت مورد استفاده در سراسر طراحی الگوریتم را ممکن می‌سازد. این راهنمای جامع ویژگی‌های هیپ و نمایش آرایه‌ای، عملیات اصلی heapify، ساخت یک هیپ از یک آرایه مرتب‌نشده، الگوریتم کامل heapsort، و عملیات‌های صف اولویت ساخته‌شده روی هیپ‌ها را پوشش می‌دهد.

ادامه

<h2>Why Randomness Enters Algorithm Analysis</h2> <p>The worst-case, best-case, and average-case running times discussed earlier in this series all assume the algorithm itself behaves deterministically, and any variation comes purely from the input. A different situation arises when either the input distribution is unknown or an algorithm deliberately makes random choices during its own execution. Both situations require the tools of <code>Probabilistic Analysis</code>.</p> <h2>The Hiring Problem: A Motivating Example</h2> <p>Consider a company interviewing candidates one at a time for a position, always hiring the current best candidate seen so far and firing the previous hire. Each interview costs a small amount, but each hire costs significantly more, since it involves paperwork, onboarding, and severance for the person being replaced. The question is: what is the expected total hiring cost across the entire process?</p> <pre class="code-block"><code>HIRE-ASSISTANT(n): best = candidate 0 (a placeholder, ranked worst) for i = 1 to n: interview candidate i if candidate i is better than best: best = candidate i hire candidate i</code></pre><br> <p>If candidates arrive in the worst possible order — already sorted from worst to best — every single candidate is hired, resulting in <code>n</code> hires, a costly worst case. But if the order of candidates is random, far fewer hires are expected on average, since a random arrival order makes it unlikely that many consecutive candidates each set a new record.</p> <h2>Two Approaches to Handling the Order of Inputs</h2> <p>There are two distinct ways to reason about this randomness, and it is important not to confuse them.</p> <ul> <li><code>Probabilistic Analysis of a Deterministic Algorithm</code>: assume the input itself comes from some probability distribution (such as a uniformly random ordering of candidates), and analyze the expected running time of a fixed, non-random algorithm over that input distribution.</li> <li><code>Randomized Algorithms</code>: the algorithm itself makes random choices during execution (such as randomly shuffling the candidate order before processing them, regardless of the order they actually arrived in), guaranteeing good expected performance for any input, since the randomness comes from the algorithm rather than an assumption about the input.</li> </ul> <p>The second approach is generally more powerful and reliable in practice, since it removes any dependence on assumptions about how inputs are distributed in the real world, which may not hold. A <code>Randomized Algorithm</code> for the hiring problem simply permutes the candidates randomly before running the same procedure, guaranteeing the same good expected cost regardless of the input's original order.</p> <h2>Indicator Random Variables: A Powerful Analytical Tool</h2> <p>Computing an expected value directly can be complicated when many interacting events are involved. <code>Indicator Random Variables</code> provide an elegant technique that dramatically simplifies such calculations, especially when combined with the linearity of expectation.</p> <p>For an event <code>A</code>, define the indicator random variable:</p> <pre class="code-block"><code>I{A} = 1 if A occurs I{A} = 0 if A does not occur Key property: E[I{A}] = Pr{A}</code></pre><br> <p>The expected value of an indicator variable simply equals the probability of the event it indicates. This becomes powerful when combined with <code>Linearity of Expectation</code>, which states that the expected value of a sum of random variables equals the sum of their expected values, regardless of whether the variables are independent.</p> <pre class="code-block"><code>E[X1 + X2 + ... + Xn] = E[X1] + E[X2] + ... + E[Xn] This holds even when the Xi are NOT independent — a crucial and often surprising fact</code></pre><br> <h2>Applying Indicator Variables to the Hiring Problem</h2> <p>Let <code>Xi</code> be the indicator random variable for the event that candidate <code>i</code> is hired. The total number of hires is <code>X = X1 + X2 + ... + Xn</code>. By linearity of expectation:</p> <pre class="code-block"><code>E[X] = E[X1] + E[X2] + ... + E[Xn] = Σ Pr{candidate i is hired}</code></pre><br> <p>Candidate <code>i</code> is hired precisely when candidate <code>i</code> is the best among the first <code>i</code> candidates seen so far. If the candidates arrive in a uniformly random order, candidate <code>i</code> is equally likely to be the best, second-best, or any rank among the first <code>i</code> candidates, so:</p> <pre class="code-block"><code>Pr{candidate i is hired} = 1/i Therefore: E[X] = Σ (i=1 to n) 1/i = H(n) This is the Harmonic Series, and H(n) = Θ(ln n)</code></pre><br> <p>This remarkable result shows that, despite there being <code>n</code> candidates, the expected number of hires grows only logarithmically with <code>n</code>, a dramatic improvement over the worst-case scenario of <code>n</code> hires. This calculation, made simple through indicator variables, would be considerably more complex using direct probability calculations involving joint distributions.</p> <h2>Why This Technique Generalizes So Widely</h2> <p>The indicator random variable technique is not specific to the hiring problem; it is a general tool applicable whenever a quantity of interest can be expressed as a sum of simpler zero-or-one outcomes, even when those outcomes are correlated with each other. This makes it one of the most broadly useful techniques in the probabilistic analysis of algorithms, and it reappears throughout later topics in this series wherever expected running time needs to be computed.</p> <h2>Why Randomization Matters for Real-World Algorithm Design</h2> <p>Randomized algorithms are used throughout computer science specifically because they can guarantee good expected performance without needing any assumption about the distribution of real-world inputs, protecting against adversarial or unusually structured inputs that could otherwise trigger an algorithm's worst case. A prominent example, explored in depth later in this series, is randomized quicksort, where randomly shuffling the input before sorting protects against the specific input orderings that would otherwise trigger quicksort's quadratic worst case.</p>

برخی الگوریتم‌ها در حین اجرا انتخاب‌های تصادفی می‌کنند، و تحلیل رفتار مورد انتظارشان نیازمند جعبه‌ابزاری متفاوت از تحلیل بدترین‌حالت به‌تنهایی است. این راهنمای جامع تحلیل احتمالاتی را از طریق مسئله کلاسیک استخدام معرفی می‌کند، متغیرهای تصادفی نشانگر را به‌عنوان یک ابزار تحلیلی قدرتمند توضیح می‌دهد، و نشان می‌دهد تصادفی‌سازی چگونه می‌تواند کارایی مورد انتظار یک الگوریتم را بهبود بخشد.

ادامه