مرتبسازی؛ نخستین الگوریتمهای کلاسیک
مرتبسازی چیست و چرا مهم است؛ پیادهسازی مرتبسازی حبابی و انتخابی در پایتون و مقایسهٔ کارایی آنها.
آنچه در این درس میآموزید
- توضیح دهید مرتبسازی چه مسئلهای را حل میکند
- مرتبسازی حبابی و انتخابی را در پایتون پیادهسازی کنید
- کارایی دو الگوریتم را با درس پیچیدگی (Big-O) مقایسه کنید
فهرست مطالب
مرتبسازی (Sorting) یعنی چیدن عناصر یک مجموعه بر اساس قاعدهای مشخص — معمولاً از کوچک به بزرگ. شاید ساده به نظر برسد، اما مرتبسازی یکی از قدیمیترین مسائل علوم کامپیوتر است: تقریباً هر برنامهٔ جدی جایی به دادهٔ مرتبشده نیاز دارد، از فهرست تماسها تا نتایج جستجو. به همین دلیل صدها الگوریتم مرتبسازی ساخته شده و مقایسهٔ آنها بهترین تمرین برای درک مفهوم «کارایی» است.
در این درس دو الگوریتم کلاسیک را خودتان پیادهسازی میکنید و بعد با ابزار درس قبل (نماد O بزرگ) هزینهٔ آنها را میسنجید.
مرتبسازی حبابی (Bubble Sort)
ایدهٔ حبابی سادهترین توصیف ممکن را دارد: یکبهیک روی آرایه راه بروید؛ اگر دو همسایه جایبهجایند، جابهجایشان کنید. با هر دورِ کامل، بزرگترین عنصرِ باقیمانده مثل حباب به انتهای آرایه میرود.
def bubble_sort(numbers):
data = list(numbers)
n = len(data)
for i in range(n):
for j in range(n - 1 - i):
if data[j] > data[j + 1]:
data[j], data[j + 1] = data[j + 1], data[j]
return data
print(bubble_sort([5, 2, 8, 1, 9, 3]))[1, 2, 3, 5, 8, 9]
خطبهخط:
data = list(numbers)یک کپی میسازد تا آرایهٔ اصلی صاحب تابع تغییر نکند؛ این ادب حرفهای است.- حلقهٔ بیرونی
nدور کامل میزند؛ حلقهٔ درونی باn - 1 - iهر بار کوتاهتر میشود، چون انتهای آرایه بعد از هر دور مرتب است. data[j], data[j + 1] = data[j + 1], data[j]جابهجایی همزمان پایتونی است؛ نیازی به متغیر کمکی نیست.- اگر دو عنصر برابر باشند شرط
>برقرار نمیشود، پس ترتیب عناصر برابر حفظ میشود (پایداری در این پیادهسازی).
مرتبسازی انتخابی (Selection Sort)
ایدهٔ انتخابی: در هر گام، کوچکترین عنصرِ بخشِ مرتبنشده را «انتخاب» کنید و به ابتدای همان بخش ببرید.
def selection_sort(numbers):
data = list(numbers)
for i in range(len(data)):
min_index = i
for j in range(i + 1, len(data)):
if data[j] < data[min_index]:
min_index = j
data[i], data[min_index] = data[min_index], data[i]
return data
print(selection_sort([64, 25, 12, 22, 11]))[11, 12, 22, 25, 64]
نکتهٔ جالب: برای آرایهٔ خالی هم درست کار میکند — selection_sort([]) خروجی [] میدهد، چون حلقهها اصلاً اجرا نمیشوند. آزمودن «حالت مرزی» مثل ورودی خالی عادت مهمی است.
کدام بهتر است؟
هر دو در بدترین حالت O(n²) مقایسه انجام میدهند، اما تفاوت مهمی دارند:
| معیار | حبابی | انتخابی |
|---|---|---|
| تعداد مقایسه | O(n²) | O(n²) |
| تعداد جابهجایی (Swap) | تا O(n²) | حداکثر n-1 |
| رفتار روی دادهٔ تقریباً مرتب | با بهینهسازی، نزدیک O(n) | همیشه O(n²) |
| پایداری (Stable) | بله (این پیادهسازی) | خیر |
انتخابی جابهجایی کمتری دارد و وقتی «نوشتن» گران باشد (مثلاً حافظهٔ فلش) بهتر است؛ حبابی بهینهشده روی دادهٔ تقریباً مرتب سریعتر تمام میشود.
تمرینها
تمرین
تمرین ۱ — شمارش جابهجاییها
تابع bubble_sort را طوری تغییر دهید که علاوه بر آرایهٔ مرتبشده، تعداد جابهجاییهای انجامشده را هم برگرداند. روی ورودی [5, 1, 4, 2, 8] چند جابهجایی انجام میشود؟
# Write your code hereنمایش راهحل
def bubble_sort_count(numbers):
data = list(numbers)
n = len(data)
swaps = 0
for i in range(n):
for j in range(n - 1 - i):
if data[j] > data[j + 1]:
data[j], data[j + 1] = data[j + 1], data[j]
swaps += 1
return data, swaps
result, count = bubble_sort_count([5, 1, 4, 2, 8])
print(result, count)[1, 2, 4, 5, 8] 4
::: :::
خلاصه
- مرتبسازی چیدن دادهها بر اساس قاعدهای مشخص است و پایهٔ بیشمار کاربرد واقعی.
- حبابی با جابهجایی همسایهها کار میکند؛ انتخابی کوچکترین عنصر باقیمانده را برمیدارد.
- هر دو در بدترین حالت O(n²) هستند، اما تعداد جابهجایی و رفتار روی دادهٔ مرتب تفاوتهای عملی مهمی ایجاد میکند.
- در پایتون واقعی از
sorted()با پیچیدگی O(n log n) استفاده کنید.
با این درس، مثلث «الگوریتم، پیچیدگی، پیادهسازی» کامل شد؛ حالا میتوانید سراغ ساختارهای دادهٔ واقعیتر بروید.