وابستگی های دایره ای با الگوریتم کان

آیا تا به حال احساس کرده اید که در یک حلقه حواس پرت شده به دام افتاده اید “من نیاز دارم این قبل این که“– فقط برای پیدا کردن این که همچنین به این؟ 🤯 این جایی است که الگوریتم کان سوار شدن بر روی اسب سفید (یا شاید یک چرخه ، که می داند) برای نجات شما از سیاه چاله وابستگی دایره ای مخوف!
چه چیز بزرگی در مورد وابستگی های مدور وجود دارد؟
تصور کنید که لیستی از کارها دارید: پخت کیکبا کیک را یخ بزنیدوت تزئین کردنبشر بدیهی است ، شما نمی توانید قبل از پختن کیک را یخ بزنید و تا بعد از یخ زدگی نمی توانید تزئین کنید. این به اندازه کافی آسان است. اما زندگی (یا کد) همیشه خیلی ساده نیست. بعضی اوقات وظایف به یکدیگر در a مراجعه می کنند چرخه“مانند” نمی توانم قبل از B انجام دهم “،” نمی توانم قبل از C انجام دهم “و” نمی توانم قبل از A. C را انجام دهم ” 🔁
مرتب سازی این است که چگونه ما یک ترتیب معتبر از وظایف (یا ماژول ها ، کلاس ها یا مأموریت ها به مریخ ، شما آن را نامگذاری می کنیم) ، اگر آن را نامگذاری کنید). قوطی اصلاً وجود دارد اگر چرخه ای پیدا شود ، خوب ، زمان آن برای شکستن کنفت یا ذوب شدن است ، زیرا نمی توانید همه آنها را در یک زنجیره خطی مرتب داشته باشید.
الگوریتم کان را وارد کنید
الگوریتم کان یک روش ساختاری و مبتنی بر حل وابستگی است. در اینجا نمای کلی 20 ثانیه ای وجود دارد:
-
همه چیز را با لبه های ورودی صفر پیدا کنید 🤔
- اگر یک مورد پیش نیاز ندارد (هیچ کاری که باید از قبل انجام شود) ، آن را در یک پرتاب کنید صفبشر
-
موارد را از صف بکشید
- برای هر موردی که می خواهید ، آن را به نتیجه (سفارش مرتب شده شما).
- سپس با از بین بردن لبه های آن و کاهش آن ، “تکمیل” آن مورد را شبیه سازی می کنید در درجه (تعداد پیش نیازها) بسته به آن کارها.
- هر وظیفه ای که اکنون پیش نیازهای صفر دارد نیز مورد استفاده قرار می گیرد.
-
بشویید و تکرار کنید
- ادامه دهید تا زمانی که موارد موجود در صف را تمام نکنید.
-
هرگونه باقیمانده را تشخیص دهید
- اگر وظایفی با پیش نیازهای غیر صفر باقی مانده است ، شما یک مورد دریافت کرده اید چرخهبشر 🚨 هیچ دستور معتبری برای آنها وجود ندارد.
قطعه کد
در اینجا یک نسخه ساده پایتون وجود دارد که الگوریتم کان را نشان می دهد:
def kahn_sort(nodes, edges):
"""
nodes: list of unique items
edges: list of (A, B) meaning 'A must come before B'
returns: a list in valid topological order, or None if a cycle is detected
"""
from collections import deque
# 1) Build adjacency & in-degree
adjacency = {n: [] for n in nodes}
in_degree = {n: 0 for n in nodes}
for a, b in edges:
adjacency[a].append(b)
in_degree[b] += 1
# 2) Find all nodes with zero in-degree
queue = deque([n for n in nodes if in_degree[n] == 0])
result = []
# 3) Process the queue
while queue:
current = queue.popleft()
result.append(current)
# 'Remove' edges by reducing in-degree of children
for child in adjacency[current]:
in_degree[child] -= 1
if in_degree[child] == 0:
queue.append(child)
# 4) Detect leftover nodes (cycle)
if len(result) < len(nodes):
return None # cycle found
return result
if __name__ == "__main__":
# Example usage:
tasks = ["Bake", "Frost", "Decorate"]
dependencies = [
("Bake", "Frost"), # Bake before Frost
("Frost", "Decorate"), # Frost before Decorate
]
order = kahn_sort(tasks, dependencies)
if order is None:
print("Uh oh, cycle detected! No valid order.")
else:
print("Topological order:", order)
چرا زحمت می کشید؟
- برنامه ریزی: بیایید بگوییم که شما در یک پروژه وظایفی دارید که فقط می تواند پس از برخی کارهای دیگر اتفاق بیفتد. الگوریتم کان در صورت غیرممکن ، دنباله ای کامل را به شما می دهد یا فریاد می زند.
- خطوط لوله بسازید: پروژه هایی که ماژول هایی دارند که به یکدیگر مراجعه می کنند ، می توانند به انواع توپولوژیکی متکی باشند تا نظم ساخت را تشخیص دهند.
- نصب: هنگامی که وابستگی ها وابستگی دارند ، می خواهید اطمینان حاصل کنید که همه چیز در دنباله مناسب نصب شده است. اگر یک مرجع دایره ای وجود داشته باشد ، الگوریتم Kahn قبل از اینکه یک حلقه بی پایان نصب را امتحان کنید ، آن را پیدا می کند.
گچ های بالقوه
- چرخه: اگر نمودار شما چرخه ای باشد ، راه حل شسته و رفته وجود ندارد. شما باید با از بین بردن یا بازسازی وابستگی ها ، آن را بشکنید.
- چندین سفارش معتبر: اگر وظایف خاصی به یکدیگر بستگی نداشته باشد ، لیست نهایی می تواند از دویدن متفاوت باشد. وحشت نکنید – هر دو درست هستند!
- جزئی کامل: اگر با الگوریتم به عنوان یک فرآیند رفتار می کنید ، ممکن است بخواهید سفارشات جزئی را اداره کنید (مانند هر کاری که می توانید انجام دهید ، نادیده گرفتن قسمت چرخه ای). این انتخاب شماست.
پیچیدگی زمانی
-
ساخت نقشه های مجاورت و درج
- اولیه سازی ساختارها o (n) است که در آن حرف تعداد گره ها است.
- جمع آوری آنها با استفاده از لیست لبه o (e) است ، که در آن اشمیه تعداد لبه ها است.
- ابتدای صف (یافتن تمام گره ها با درجه = 0): o (n).
-
پردازش صف
- هر گره دقیقاً یک بار از بین می رود و هر لبه دقیقاً یک بار در نظر گرفته می شود که ما کودک خود را کاهش می دهیم.
- کل کار در این مرحله O (N + E) است.
در کل، پیچیدگی زمانی است o (n + e)بشر
پیچیدگی فضا
- لیست مجاورت: o (n + e) - ما لیستی از لبه ها را از هر گره ذخیره می کنیم ، که در کل نگه داشته می شود اشمیه لبه ها به علاوه سربار برای حرف گره ها
- نقشه in_degree: o (n) – یک عدد صحیح در هر گره را ذخیره می کند.
- صف: o (n) در بدترین حالت (اگر بسیاری از گره ها به طور هم زمان درجه = 0 دارند).
- لیست نتیجه: o (n) برای نگه داشتن ترتیب توپولوژیکی نهایی.
از این رو استفاده از فضای کل است o (n + e)بشر
بسته بندی
الگوریتم کان ممکن است فانتزی به نظر برسد ، اما اساساً فقط یک روش سیستماتیک برای “جداسازی” مکرر موارد بدون پیش نیازهای باقی مانده است. در پایان ، یا:
- شما یک ترتیب با شکوه و بدون چرخه از وظایف دارید ، یا
- شما می فهمید که یک چرخه وجود دارد ، مودبانه بازوهای خود را جمع کنید و بگویید “نه!”بشر
بنابراین دفعه بعد که با یک وب هرج و مرج از کارها روبرو هستید ، کان درست در آنجا خواهد بود ، صف در دست ، آماده برای سفارش به جنون. از سادگی انواع توپولوژیکی لذت ببرید ، و ممکن است وظایف شما هرگز در بیهودگی دایره ای یکدیگر را تعقیب نکنند!