آموزش الگوریتم مرتب سازی انتخابی (Selection Sort) + نمونه کد
در این مقاله، به طور کامل به آموزش الگوریتم مرتب سازی انتخابی (Selection Sort) میپردازیم. این الگوریتم یکی از سادهترین و در عین حال پرکاربردترین الگوریتمهای مرتبسازی است که در بسیاری از موارد میتواند به عنوان یک راهحل مناسب مورد استفاده قرار گیرد. ما در این آموزش، مفاهیم پایه، نحوه عملکرد، پیادهسازی (به زبانهای مختلف برنامهنویسی)، تحلیل پیچیدگی زمانی و مکانی، مزایا و معایب و کاربردهای الگوریتم Selection Sort را بررسی خواهیم کرد. هدف ما این است که شما پس از مطالعه این مقاله، درک کاملی از این الگوریتم داشته باشید و بتوانید آن را در پروژههای خود به کار ببرید.
فهرست مطالب
- مقدمه
- مرتبسازی چیست؟
- چرا مرتبسازی مهم است؟
- معرفی الگوریتم مرتبسازی انتخابی (Selection Sort)
- نحوه عملکرد الگوریتم Selection Sort
- توضیح گام به گام با مثال
- تصویرسازی فرآیند مرتبسازی
- پیادهسازی الگوریتم Selection Sort
- کد Python
- کد Java
- کد C++
- توضیح خط به خط کد
- تحلیل پیچیدگی زمانی و مکانی
- پیچیدگی زمانی بهترین، متوسط و بدترین حالت
- پیچیدگی مکانی
- مزایا و معایب الگوریتم Selection Sort
- مزایا
- معایب
- کاربردهای الگوریتم Selection Sort
- سناریوهای مناسب برای استفاده
- سناریوهای نامناسب برای استفاده
- مقایسه با سایر الگوریتمهای مرتبسازی
- مقایسه با Bubble Sort
- مقایسه با Insertion Sort
- مقایسه با Merge Sort
- مقایسه با Quick Sort
- بهینهسازی الگوریتم Selection Sort
- راهکارهایی برای بهبود عملکرد
- پرسشهای متداول (FAQ)
- سوالات رایج و پاسخ آنها
- نتیجهگیری
- خلاصه نکات کلیدی
- مسیرهای یادگیری بیشتر
1. مقدمه
مرتبسازی چیست؟
مرتبسازی فرآیندی است که طی آن، مجموعهای از دادهها (مانند اعداد، حروف، اشیاء و غیره) بر اساس یک معیار مشخص (مانند مقدار عددی، ترتیب الفبایی، ویژگیهای خاص و غیره) به ترتیب خاصی (صعودی یا نزولی) چیده میشوند. هدف از مرتبسازی، سازماندهی دادهها به گونهای است که جستجو، دسترسی و پردازش آنها آسانتر و سریعتر شود.
چرا مرتبسازی مهم است؟
مرتبسازی یکی از مهمترین و پرکاربردترین عملیات در علوم کامپیوتر و برنامهنویسی است. دلیل اهمیت آن به شرح زیر است:
- بهبود سرعت جستجو: مرتبسازی دادهها، جستجو را به میزان قابل توجهی سرعت میبخشد. به عنوان مثال، جستجو در یک لیست مرتب شده با استفاده از الگوریتم جستجوی دودویی (Binary Search) بسیار سریعتر از جستجو در یک لیست نامرتب است.
- بهینهسازی عملیات پردازش: بسیاری از الگوریتمها و عملیات پردازش دادهها، به دادههای مرتب شده نیاز دارند. مرتبسازی دادهها، این امکان را فراهم میکند که این الگوریتمها به صورت کارآمدتر و سریعتر اجرا شوند.
- سازماندهی دادهها: مرتبسازی به سازماندهی و نمایش بهتر دادهها کمک میکند. این امر باعث میشود که درک و تحلیل دادهها آسانتر شود.
- پیشپردازش دادهها: در بسیاری از موارد، مرتبسازی به عنوان یک مرحله پیشپردازش برای سایر الگوریتمها و عملیات استفاده میشود.
معرفی الگوریتم مرتبسازی انتخابی (Selection Sort)
الگوریتم مرتبسازی انتخابی (Selection Sort) یک الگوریتم مرتبسازی ساده و مقایسهای است. این الگوریتم با پیدا کردن کوچکترین (یا بزرگترین) عنصر در لیست و جابجایی آن با عنصر اول، شروع میکند. سپس، کوچکترین (یا بزرگترین) عنصر باقیمانده را پیدا کرده و آن را با عنصر دوم جابجا میکند. این فرآیند تا زمانی که کل لیست مرتب شود، ادامه مییابد.
2. نحوه عملکرد الگوریتم Selection Sort
توضیح گام به گام با مثال
فرض کنید میخواهیم لیست زیر را با استفاده از الگوریتم Selection Sort به صورت صعودی مرتب کنیم:
[64, 25, 12, 22, 11]
گام 1:
- کوچکترین عنصر در لیست را پیدا میکنیم. در این مثال، کوچکترین عنصر 11 است.
- عنصر 11 را با عنصر اول (64) جابجا میکنیم.
- لیست به شکل زیر در میآید:
[11, 25, 12, 22, 64]
گام 2:
- حالا از عنصر دوم (25) به بعد، کوچکترین عنصر را پیدا میکنیم. در این مثال، کوچکترین عنصر 12 است.
- عنصر 12 را با عنصر دوم (25) جابجا میکنیم.
- لیست به شکل زیر در میآید:
[11, 12, 25, 22, 64]
گام 3:
- از عنصر سوم (25) به بعد، کوچکترین عنصر را پیدا میکنیم. در این مثال، کوچکترین عنصر 22 است.
- عنصر 22 را با عنصر سوم (25) جابجا میکنیم.
- لیست به شکل زیر در میآید:
[11, 12, 22, 25, 64]
گام 4:
- از عنصر چهارم (25) به بعد، کوچکترین عنصر را پیدا میکنیم. در این مثال، کوچکترین عنصر 25 است (خودش).
- نیازی به جابجایی نیست.
- لیست به شکل زیر باقی میماند:
[11, 12, 22, 25, 64]
گام 5:
- عنصر آخر (64) به خودی خود مرتب شده است.
در نهایت، لیست مرتب شده به شکل زیر خواهد بود: [11, 12, 22, 25, 64]
تصویرسازی فرآیند مرتبسازی
(تصویرسازی فرآیند مرتب سازی با استفاده از نمودارها و انیمیشن ها در این متن ممکن نیست. توصیه می شود برای فهم بهتر، به دنبال ویدیوهای آموزشی یا تصاویر متحرک در اینترنت بگردید که فرآیند Selection Sort را به صورت بصری نمایش می دهند.)
3. پیادهسازی الگوریتم Selection Sort
کد Python
def selection_sort(list_):
n = len(list_)
for i in range(n):
min_index = i
for j in range(i+1, n):
if list_[j] < list_[min_index]:
min_index = j
list_[i], list_[min_index] = list_[min_index], list_[i]
return list_
# مثال استفاده:
my_list = [64, 25, 12, 22, 11]
sorted_list = selection_sort(my_list)
print("Sorted list:", sorted_list)
کد Java
public class SelectionSort {
public static void selectionSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
int min_idx = i;
for (int j = i + 1; j < n; j++)
if (arr[j] < arr[min_idx])
min_idx = j;
int temp = arr[min_idx];
arr[min_idx] = arr[i];
arr[i] = temp;
}
}
public static void main(String args[]) {
int arr[] = {64, 25, 12, 22, 11};
selectionSort(arr);
System.out.println("Sorted array");
for (int i=0; i
کد C++
#include
using namespace std;
void selectionSort(int arr[], int n) {
int i, j, min_idx;
for (i = 0; i < n-1; i++) { min_idx = i; for (j = i+1; j < n; j++) if (arr[j] < arr[min_idx]) min_idx = j; swap(arr[min_idx], arr[i]); } } void printArray(int arr[], int size) { int i; for (i=0; i < size; i++) cout << arr[i] << " "; cout << endl; } int main() { int arr[] = {64, 25, 12, 22, 11}; int n = sizeof(arr)/sizeof(arr[0]); selectionSort(arr, n); cout << "Sorted array: \n"; printArray(arr, n); return 0; }
توضیح خط به خط کد
توضیح کد Python:
def selection_sort(list_):
: تعریف یک تابع به نامselection_sort
که یک لیست به عنوان ورودی میگیرد.n = len(list_):
: طول لیست را در متغیرn
ذخیره میکند.for i in range(n):
: یک حلقهfor
که از 0 تاn-1
تکرار میشود. این حلقه برای پیمایش عناصر لیست است.min_index = i:
: در هر تکرار، فرض میکنیم که عنصر فعلی (با اندیسi
) کوچکترین عنصر است و اندیس آن را در متغیرmin_index
ذخیره میکنیم.for j in range(i+1, n):
: یک حلقهfor
داخلی که ازi+1
تاn-1
تکرار میشود. این حلقه برای پیدا کردن کوچکترین عنصر در قسمت باقیمانده لیست است.if list_[j] < list_[min_index]:
: اگر عنصری با اندیسj
کوچکتر از عنصری با اندیسmin_index
باشد، اندیسj
را درmin_index
ذخیره میکنیم.list_[i], list_[min_index] = list_[min_index], list_[i]:
: پس از پیدا کردن کوچکترین عنصر، آن را با عنصر فعلی (با اندیسi
) جابجا میکنیم.return list_:
: لیست مرتب شده را برمیگرداند.
توضیح کد Java:
public static void selectionSort(int[] arr)
: تابع مرتب سازی Selection Sort را تعریف می کند که یک آرایه integer به عنوان ورودی می گیرد.int n = arr.length;
: طول آرایه را در متغیر n ذخیره می کند.for (int i = 0; i < n - 1; i++)
: حلقه بیرونی که از 0 تا n-2 تکرار می شود.int min_idx = i;
: اندیس کوچکترین عنصر را در زیرآرایه فعلی برابر با i در نظر می گیرد.for (int j = i + 1; j < n; j++)
: حلقه داخلی که از i+1 تا n-1 تکرار می شود.if (arr[j] < arr[min_idx])
: اگر عنصر jام از عنصر min_idx ام کوچکتر باشد، min_idx را برابر j قرار می دهد.int temp = arr[min_idx]; arr[min_idx] = arr[i]; arr[i] = temp;
: مقدار عنصر min_idx ام را با مقدار عنصر i ام تعویض می کند.public static void main(String args[])
: متد اصلی برنامه.int arr[] = {64, 25, 12, 22, 11};
: یک آرایه integer با مقادیر اولیه تعریف می کند.selectionSort(arr);
: تابع مرتب سازی Selection Sort را بر روی آرایه arr فراخوانی می کند.System.out.println("Sorted array");
: چاپ عبارت "Sorted array" در کنسول.for (int i=0; i
: حلقه ای که عناصر آرایه مرتب شده را در کنسول چاپ می کند.
توضیح کد C++:
#include
: سرآیند iostream را برای استفاده از توابع ورودی/خروجی اضافه می کند.using namespace std;
: فضای نام std را برای استفاده از توابع استاندارد C++ اضافه می کند.void selectionSort(int arr[], int n)
: تابع مرتب سازی Selection Sort را تعریف می کند که یک آرایه integer و طول آن را به عنوان ورودی می گیرد.int i, j, min_idx;
: متغیرهای i، j و min_idx را تعریف می کند.for (i = 0; i < n-1; i++)
: حلقه بیرونی که از 0 تا n-2 تکرار می شود.min_idx = i;
: اندیس کوچکترین عنصر را در زیرآرایه فعلی برابر با i در نظر می گیرد.for (j = i+1; j < n; j++) if (arr[j] < arr[min_idx]) min_idx = j;
: حلقه داخلی که از i+1 تا n-1 تکرار می شود و اگر عنصر jام از عنصر min_idx ام کوچکتر باشد، min_idx را برابر j قرار می دهد.swap(arr[min_idx], arr[i]);
: مقدار عنصر min_idx ام را با مقدار عنصر i ام تعویض می کند.void printArray(int arr[], int size)
: تابع چاپ آرایه را تعریف می کند که یک آرایه integer و طول آن را به عنوان ورودی می گیرد.int i; for (i=0; i < size; i++) cout << arr[i] << " ";
: حلقه ای که عناصر آرایه را در کنسول چاپ می کند.int main()
: تابع اصلی برنامه.int arr[] = {64, 25, 12, 22, 11};
: یک آرایه integer با مقادیر اولیه تعریف می کند.int n = sizeof(arr)/sizeof(arr[0]);
: طول آرایه را محاسبه می کند.selectionSort(arr, n);
: تابع مرتب سازی Selection Sort را بر روی آرایه arr فراخوانی می کند.cout << "Sorted array: \n";
: چاپ عبارت "Sorted array:" در کنسول.printArray(arr, n);
: تابع چاپ آرایه را فراخوانی می کند.
4. تحلیل پیچیدگی زمانی و مکانی
پیچیدگی زمانی بهترین، متوسط و بدترین حالت
الگوریتم Selection Sort همواره O(n2) است. این بدان معناست که در بهترین، متوسط و بدترین حالت، زمان اجرای الگوریتم متناسب با مربع تعداد عناصر لیست است. دلیل این امر این است که الگوریتم در هر صورت، باید تمام عناصر لیست را برای پیدا کردن کوچکترین عنصر بررسی کند.
- بهترین حالت: O(n2)
- حالت متوسط: O(n2)
- بدترین حالت: O(n2)
پیچیدگی مکانی
پیچیدگی مکانی الگوریتم Selection Sort O(1) است. این بدان معناست که الگوریتم به مقدار ثابتی از حافظه اضافی نیاز دارد، صرف نظر از تعداد عناصر لیست. الگوریتم Selection Sort یک الگوریتم درجا (in-place) است، به این معنی که نیازی به ایجاد یک لیست جدید برای مرتبسازی ندارد و فقط از حافظه موجود برای جابجایی عناصر استفاده میکند.
5. مزایا و معایب الگوریتم Selection Sort
مزایا
- سادگی: الگوریتم Selection Sort بسیار ساده است و درک و پیادهسازی آن آسان است.
- کارآمد برای لیستهای کوچک: برای لیستهای کوچک، Selection Sort میتواند سریعتر از الگوریتمهای پیچیدهتر مانند Merge Sort یا Quick Sort باشد.
- حداقل تعداد جابجایی: Selection Sort کمترین تعداد جابجایی را در بین الگوریتمهای مرتبسازی مقایسهای دارد. این ویژگی میتواند در مواردی که جابجایی عناصر هزینه بالایی دارد، مفید باشد.
- پیچیدگی مکانی کم: Selection Sort یک الگوریتم درجا است و به حافظه اضافی کمی نیاز دارد.
معایب
- کارآمدی پایین برای لیستهای بزرگ: برای لیستهای بزرگ، Selection Sort بسیار کندتر از الگوریتمهای پیچیدهتر مانند Merge Sort یا Quick Sort است.
- پیچیدگی زمانی درجه دو: پیچیدگی زمانی O(n2) باعث میشود که Selection Sort برای لیستهای بزرگ غیرعملی باشد.
- عدم سازگاری با دادههای تقریبا مرتب: Selection Sort حتی اگر لیست تقریبا مرتب باشد، باز هم تمام عناصر را بررسی میکند و بهبودی در عملکرد نخواهد داشت.
6. کاربردهای الگوریتم Selection Sort
سناریوهای مناسب برای استفاده
- لیستهای کوچک: زمانی که تعداد عناصر لیست کم باشد (مثلاً کمتر از 100 عنصر)، Selection Sort میتواند یک انتخاب مناسب باشد.
- جابجایی پرهزینه: در مواردی که جابجایی عناصر هزینه بالایی دارد، Selection Sort به دلیل داشتن حداقل تعداد جابجایی، میتواند یک انتخاب خوب باشد.
- سادگی و سهولت پیادهسازی: زمانی که نیاز به یک الگوریتم مرتبسازی ساده و سریع برای پیادهسازی دارید، Selection Sort میتواند یک گزینه مناسب باشد.
- محدودیت حافظه: در محیطهایی که محدودیت حافظه وجود دارد، Selection Sort به دلیل داشتن پیچیدگی مکانی O(1)، میتواند یک انتخاب مناسب باشد.
سناریوهای نامناسب برای استفاده
- لیستهای بزرگ: برای لیستهای بزرگ، Selection Sort به دلیل داشتن پیچیدگی زمانی O(n2)، بسیار کند است و باید از الگوریتمهای پیچیدهتر مانند Merge Sort یا Quick Sort استفاده کرد.
- نیاز به سرعت بالا: زمانی که سرعت مرتبسازی اهمیت زیادی دارد، Selection Sort نمیتواند گزینه مناسبی باشد.
- دادههای تقریبا مرتب: برای دادههایی که تقریبا مرتب هستند، الگوریتمهای دیگری مانند Insertion Sort میتوانند بسیار کارآمدتر باشند.
7. مقایسه با سایر الگوریتمهای مرتبسازی
مقایسه با Bubble Sort
- Selection Sort معمولا بهتر از Bubble Sort عمل میکند، زیرا تعداد جابجاییهای کمتری دارد. با این حال، هر دو الگوریتم دارای پیچیدگی زمانی O(n2) هستند.
- در Selection Sort، فقط یک جابجایی در هر تکرار حلقه بیرونی انجام میشود، در حالی که در Bubble Sort ممکن است چندین جابجایی در هر تکرار انجام شود.
مقایسه با Insertion Sort
- Insertion Sort معمولا برای لیستهای کوچک و دادههای تقریبا مرتب، سریعتر از Selection Sort است.
- پیچیدگی زمانی Insertion Sort در بهترین حالت O(n) است، در حالی که پیچیدگی زمانی Selection Sort همواره O(n2) است.
- Insertion Sort یک الگوریتم تطبیقی (adaptive) است، به این معنی که با مرتب بودن بیشتر دادهها، عملکرد آن بهبود مییابد. Selection Sort تطبیقی نیست.
مقایسه با Merge Sort
- Merge Sort یک الگوریتم مرتبسازی تقسیم و غلبه (divide and conquer) است و دارای پیچیدگی زمانی O(n log n) است. بنابراین، برای لیستهای بزرگ بسیار سریعتر از Selection Sort است.
- Merge Sort به حافظه اضافی نیاز دارد (پیچیدگی مکانی O(n))، در حالی که Selection Sort یک الگوریتم درجا است.
مقایسه با Quick Sort
- Quick Sort نیز یک الگوریتم مرتبسازی تقسیم و غلبه است و دارای پیچیدگی زمانی متوسط O(n log n) است. در عمل، Quick Sort معمولا سریعتر از Merge Sort است.
- پیچیدگی زمانی بدترین حالت Quick Sort O(n2) است، اما با انتخاب استراتژی مناسب برای انتخاب عنصر محوری (pivot)، میتوان این احتمال را کاهش داد.
- Quick Sort نیز به طور معمول به حافظه اضافی نیاز دارد (به صورت لگاریتمی), اما پیاده سازی inplace آن وجود دارد (البته پیچیده تر است).
8. بهینهسازی الگوریتم Selection Sort
راهکارهایی برای بهبود عملکرد
به طور کلی، بهینهسازی الگوریتم Selection Sort به دلیل سادگی و طبیعت ذاتی آن، بسیار محدود است. با این حال، میتوان برخی از جنبههای آن را بهبود بخشید:
- کاهش مقایسهها: در پیادهسازی استاندارد، الگوریتم همواره تمام عناصر را برای پیدا کردن کوچکترین عنصر بررسی میکند. در صورتی که اطلاعاتی از قبل در مورد دادهها داشته باشیم (مثلاً میدانیم که دادهها در یک بازه مشخص قرار دارند)، میتوانیم از این اطلاعات برای کاهش تعداد مقایسهها استفاده کنیم.
- استفاده از دستورالعملهای سختافزاری: در برخی از معماریهای سختافزاری، دستورالعملهای خاصی برای پیدا کردن حداقل و حداکثر مقدار در یک آرایه وجود دارد. استفاده از این دستورالعملها میتواند عملکرد الگوریتم را بهبود بخشد.
- بهینهسازی کد: با استفاده از تکنیکهای بهینهسازی کد (مانند استفاده از متغیرهای محلی، حذف محاسبات تکراری و غیره)، میتوان عملکرد الگوریتم را کمی بهبود بخشید.
نکته مهم: با وجود این بهینهسازیها، پیچیدگی زمانی الگوریتم Selection Sort همچنان O(n2) باقی میماند. بنابراین، برای لیستهای بزرگ، استفاده از الگوریتمهای مرتبسازی کارآمدتر (مانند Merge Sort یا Quick Sort) همچنان توصیه میشود.
9. پرسشهای متداول (FAQ)
سوالات رایج و پاسخ آنها
-
سوال: آیا الگوریتم Selection Sort یک الگوریتم پایدار (stable) است؟
پاسخ: خیر، الگوریتم Selection Sort یک الگوریتم پایدار نیست. الگوریتم پایدار الگوریتمی است که ترتیب عناصر با مقادیر برابر را پس از مرتبسازی حفظ میکند. Selection Sort این ویژگی را ندارد، زیرا در هنگام جابجایی عناصر، ممکن است ترتیب عناصر با مقادیر برابر تغییر کند.
-
سوال: آیا میتوان الگوریتم Selection Sort را برای مرتبسازی لیستهای پیوندی (linked lists) استفاده کرد؟
پاسخ: بله، میتوان الگوریتم Selection Sort را برای مرتبسازی لیستهای پیوندی استفاده کرد. با این حال، پیادهسازی آن کمی پیچیدهتر از پیادهسازی برای آرایهها است. به جای جابجایی مستقیم عناصر، باید اشارهگرها (pointers) را تغییر داد.
-
سوال: چه زمانی باید از Selection Sort به جای Bubble Sort استفاده کرد؟
پاسخ: Selection Sort معمولا بهتر از Bubble Sort است، زیرا تعداد جابجاییهای کمتری دارد. با این حال، هر دو الگوریتم دارای پیچیدگی زمانی O(n2) هستند و برای لیستهای بزرگ مناسب نیستند.
-
سوال: آیا Selection Sort در عمل استفاده میشود؟
پاسخ: Selection Sort در عمل به ندرت به عنوان الگوریتم اصلی مرتبسازی استفاده میشود، زیرا الگوریتمهای کارآمدتری مانند Merge Sort و Quick Sort وجود دارند. با این حال، Selection Sort به دلیل سادگی و کم حجم بودن، ممکن است در برخی از موارد خاص (مانند سیستمهای تعبیهشده با محدودیت حافظه) مورد استفاده قرار گیرد.
10. نتیجهگیری
خلاصه نکات کلیدی
- الگوریتم Selection Sort یک الگوریتم مرتبسازی ساده و مقایسهای است.
- این الگوریتم با پیدا کردن کوچکترین عنصر در لیست و جابجایی آن با عنصر اول، شروع میکند.
- پیچیدگی زمانی Selection Sort همواره O(n2) است.
- پیچیدگی مکانی Selection Sort O(1) است (الگوریتم درجا).
- Selection Sort برای لیستهای کوچک و جابجایی پرهزینه مناسب است.
- Selection Sort برای لیستهای بزرگ و نیاز به سرعت بالا مناسب نیست.
مسیرهای یادگیری بیشتر
- مطالعه و پیادهسازی سایر الگوریتمهای مرتبسازی (مانند Merge Sort، Quick Sort، Insertion Sort و غیره).
- یادگیری تحلیل پیچیدگی الگوریتمها.
- شرکت در چالشهای برنامهنویسی و حل مسائل مرتبسازی.
- مطالعه منابع آنلاین و کتابهای مرتبط با الگوریتمها و ساختمان دادهها.
```