AlgoVerse

مرتب‌سازی هرمی

آرایه را به یک هرم بیشینه تبدیل می‌کند و بعد بارها بزرگ‌ترین عضو را از ریشه برمی‌دارد و به انتهای آرایه می‌برد.

هرم بیشینه درخت دودویی کاملی است که هر گره از فرزندانش کوچک‌تر نیست، پس بزرگ‌ترین عضو همیشه در ریشه است. این درخت را می‌شود بدون اشاره‌گر در خود آرایه نگه داشت: فرزندان خانه‌ی i در 2i + 1 و 2i + 2 هستند.

ادامه‌ی توضیح ↓
ورودی:
n=10خروجی PDF

ده عدد درهم؛ اول هرم ساخته می‌شود، بعد عضوها یکی‌یکی از ریشه برداشته می‌شوند.

  1. def heap_sort(a):
  2. n = len(a)
  3. for i in range(n // 2 - 1, -1, -1):
  4. sift_down(a, i, n)
  5. for end in range(n - 1, 0, -1):
  6. a[0], a[end] = a[end], a[0]
  7. sift_down(a, 0, end)
  8. return a
  9. def sift_down(a, i, size):
  10. while True:
  11. largest = i
  12. left = 2 * i + 1
  13. right = 2 * i + 2
  14. if left < size:
  15. if a[left] > a[largest]:
  16. largest = left
  17. if right < size:
  18. if a[right] > a[largest]:
  19. largest = right
  20. if largest == i:
  21. return
  22. a[i], a[largest] = a[largest], a[i]
  23. i = largest

ناوردا: در مرحله‌ی دوم، a[0..end−1] یک هرم بیشینه است و a[end..n−1] بزرگ‌ترین عضوها را مرتب‌شده دارد.

شروع اجرا

413216910148740113223164951061478879

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

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

a list

4132169101487

Call stack

  1. heap_sort()خط 1
گام ۱ از ۴۲۷
خط سیاه = extract · خط نارنجی = گام کلیدیcompare: 0/42 · swap: 0/21 · extract: 0/9

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

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

    • comparisons
    • swaps
    • ورودی فعلی (n=10)
    020406080468101214n = تعداد عضوهای آرایهcomparisonsswaps
    نمایش به شکل جدول
    ncomparisonsswaps
    46.42.8
    615.27
    826.312
    1039.818.1
    1252.324.8
    1463.528.3
    توضیح

    ایده

    هرم بیشینه درخت دودویی کاملی است که هر گره از فرزندانش کوچک‌تر نیست، پس بزرگ‌ترین عضو همیشه در ریشه است. این درخت را می‌شود بدون اشاره‌گر در خود آرایه نگه داشت: فرزندان خانه‌ی i در 2i + 1 و 2i + 2 هستند.

    مرتب‌سازی هرمی دو مرحله دارد:

    1. ساخت هرم: از آخرین گره‌ی غیربرگ به سمت ریشه، روی هر گره sift_down را اجرا کن تا آرایه هرم بیشینه شود.
    2. برداشتن از ریشه: ریشه (بزرگ‌ترین عضو) را با آخرین خانه‌ی هرم جابه‌جا کن، اندازه‌ی هرم را یکی کم کن و ریشه‌ی تازه را با sift_down پایین ببر. تا وقتی هرم یک عضو دارد، تکرار کن.

    sift_down

    گره را با بزرگ‌ترین فرزندش مقایسه کن. اگر فرزند بزرگ‌تر بود، جابه‌جا کن و از جای تازه ادامه بده؛ وگرنه کار تمام است. چون ارتفاع هرم log n است، هر sift_down حداکثر O(log n) کار دارد.

    هزینه

    • ساخت هرم O(n) است و مرحله‌ی دوم n − 1 بار sift_down اجرا می‌کند، پس زمان در همه‌ی حالت‌ها O(n log n) است.
    • مرتب‌سازی درجا انجام می‌شود: حافظه‌ی اضافه O(1).
    • مرتب‌سازی هرمی پایدار نیست: جابه‌جایی‌های دور ممکن است ترتیب عضوهای برابر را عوض کنند.

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

    • بالای میله‌ها همان آرایه به شکل درخت هرم کشیده شده است. فقط خانه‌هایی که هنوز در هرم‌اند در درخت دیده می‌شوند.
    • میله‌های سیاه بخش مرتب‌شده‌ی انتهای آرایه‌اند که هر دور یکی بزرگ‌تر می‌شود.
    • با سطح جزئیات «هر دور حلقه» فقط برداشتن‌ها را از ریشه ببین.