AlgoVerse

مجموعه‌های مجزا (Union-Find)

یال‌ها را یکی‌یکی می‌خواند و مجموعه‌ی دو سرشان را یکی می‌کند؛ با «ادغام بر اساس رتبه» و «فشرده‌سازی مسیر» هر عمل تقریباً O(1) است.

ساختار مجموعه‌های مجزا دو عمل دارد: FIND(x) (نماینده‌ی مجموعه‌ی x) و UNION(x, y) (یکی کردن دو مجموعه). هر مجموعه یک درخت است و ریشه‌اش نماینده است؛ parent[x] به پدر x اشاره می‌کند.

ادامه‌ی توضیح ↓
ورودی:
V=8 · E=7 · src=Aخروجی PDF

هشت گره؛ ادغام‌ها دو درخت با عمق ۲ می‌سازند. برای یال آخر، D — H، دو FIND از دو پله پایین‌تر شروع می‌شوند و فشرده‌سازی مسیر D و H را مستقیم به ریشه‌هایشان وصل می‌کند.

  1. def union_find(graph, src):
  2. parent = {v: v for v in graph}
  3. rank = {v: 0 for v in graph}
  4. for u in graph:
  5. for v, _ in graph[u]:
  6. if u > v:
  7. continue # each undirected edge once
  8. ru = find(parent, u)
  9. rv = find(parent, v)
  10. if ru == rv:
  11. continue
  12. if rank[ru] < rank[rv]:
  13. ru, rv = rv, ru
  14. parent[rv] = ru
  15. if rank[ru] == rank[rv]:
  16. rank[ru] = rank[ru] + 1
  17. return parent
  18. def find(parent, x):
  19. if parent[x] == x:
  20. return x
  21. root = find(parent, parent[x])
  22. parent[x] = root
  23. return root

ناوردا: هر مجموعه یک درخت است که ریشه‌اش نماینده‌ی آن است؛ دو گره در یک مجموعه‌اند اگر و فقط اگر FIND هر دو یک ریشه بدهد.

شروع اجرا

ACEGBFDH
  • گره‌ی جاری (x)
  • درخت کوتاه‌ترین مسیر تا اینجا
  • یالِ در حال بررسی

درخت فراخوانی‌های بازگشتی

نارنجی پر = فراخوانی در حال اجرا · حاشیه‌ی نارنجی = هنوز روی پشته · خاکستری = تمام شده

متغیرهای محلی

src'A'

نارنجی = در همین گام عوض شد

graph dict
  • 'A': [('B', 1)]
  • 'C': [('D', 1)]
  • 'E': [('F', 1)]
  • 'G': [('H', 1)]
  • 'B': [('A', 1), ('D', 1)]
  • 'F': [('E', 1), ('H', 1)]
  • 'D': [('C', 1), ('B', 1), ('H', 1)]
  • 'H': [('G', 1), ('F', 1), ('D', 1)]

Call stack

  1. union_find()خط 1
گام ۱ از ۱۸۷
خط سیاه = check · خط نارنجی = گام کلیدیis_root: 0/22 · check: 0/7 · union: 0/7 · taller: 0/7 · compress: 0/8

    رشد تعداد عملیات با اندازه‌ی ورودی

    میانگین ۵ گراف تصادفی برای هر n (با seed ثابت). نشانگر توخالی = ورودی فعلی.

    • is_root
    • compress
    • ورودی فعلی (n=8)
    050100150200481216202428n = تعداد گره‌هاis_rootcompress
    نمایش به شکل جدول
    nis_rootcompress
    4154.6
    844.617
    126725.4
    1691.435.4
    20118.647.8
    24121.447
    2815863.6
    توضیح

    ایده

    ساختار مجموعه‌های مجزا دو عمل دارد: FIND(x) (نماینده‌ی مجموعه‌ی x) و UNION(x, y) (یکی کردن دو مجموعه). هر مجموعه یک درخت است و ریشه‌اش نماینده است؛ parent[x] به پدر x اشاره می‌کند.

    دو ترفند

    • ادغام بر اساس رتبه: درخت کوتاه‌تر زیر ریشه‌ی درخت بلندتر می‌رود، پس ارتفاع درخت‌ها حداکثر log n است.
    • فشرده‌سازی مسیر: FIND هر گره‌ای را که در راه دید، مستقیم به ریشه وصل می‌کند تا دفعه‌ی بعد سریع‌تر باشد.

    با هر دو، هر عمل به‌طور میانگین O(α(n)) است؛ α تابع معکوس آکرمان است که در عمل از ۵ بیشتر نمی‌شود.

    کاربرد

    مؤلفه‌های همبند، تشخیص دور و الگوریتم کروسکال (که اینجا بدون این دو ترفند پیاده شده).

    در trace به چه چیزی نگاه کنی

    • برچسب کنار هر گره parent آن است؛ ریشه‌ها به خودشان اشاره می‌کنند.
    • در ورودی «مثال به سبک کتاب»، یال آخر را ببین: FIND مسیر را کوتاه می‌کند.