- شروع کننده موضوع
- #1
neda.m
کاربر خاکانجمنخورده
- ارسالها
- 1,720
- امتیاز
- 2,682
- نام مرکز سمپاد
- فرزانگان 1
- شهر
- تهران
- دانشگاه
- شهید رجائی تهران
- رشته دانشگاه
- مهندسی عمران - ژئوتکنیک
لگوریتم مرتبسازی، در علوم کامپیوتر و ریاضی، الگوریتمی است که لیستی از دادهها را به ترتیبی مشخص میچیند.
پر استفادهترین ترتیبها، ترتیبهای عددی و لغتنامهای هستند. مرتبسازی کارا در بهینه سازی الگوریتمهایی که به لیستهای مرتب شده نیاز دارند (مثل جستجو و ترکیب) اهمیت زیادی دارد.
از ابتدای علم کامپیوتر مسائل مرتبسازی تحقیقات فراوانی را متوجه خود ساختند، شاید به این علت که در عین ساده بودن، حل آن به صورت کارا پیچیدهاست. برای مثال مرتبسازی حبابی در سال ۱۹۵۶ به وجود آمد. در حالی که بسیاری این را یک مسئلهٔ حل شده میپندارند، الگوریتم کارآمد جدیدی همچنان ابداع میشوند (مثلاً مرتبسازی کتاب خانهای در سال ۲۰۰۴ مطرح شد).
مبحث مرتبسازی در کلاسهای معرفی علم کامپیوتر بسیار پر کاربرد است، مبحثی که در آن وجود الگوریتمهای فراوان به آشنایی با ایدههای کلی و مراحل طراحی الگوریتمهای مختلف کمک میکند؛ مانند تحلیل الگوریتم، دادهساختارها، الگوریتمهای تصادفی، تحلیل بدترین و بهترین حالت و حالت میانگین، هزینهٔ زمان و حافظه، و حد پایین.
سه تا از معروف ترین الگوریتم ها رو گذاشتم اینجا، اگه خواستین بقیه اش رو هم بخونین، برین تو ویکی پدیا ببینید
مرتب سازی حبابی:
(به انگلیسی: Bubble Sort)
فرض کنید میخواهیم n داده به صورت صعودی مرتب شوند. عنصر اول را با با عنصر دوم مقایسه کرده، و در صورتی که عنصر اول بزرگتر باشد باشد جای عنصر اول و دوم را عوض میکنیم. همین کار را با عناصر دوم و سوم انجام میدهیم و همینطور عناصر سوم و چهارم ، الی آخر. وقتی این کار تمام شد بزرگترین عنصر بین دادهها به آخر لیست میرسد . حالا یک بار دیگر از اول این کار را انجام میدهیم اما این بار تا عنصر (n -۱)ام ادامه میدهیم (عنصر nام در مرحله اول در جای خودش قرار گرفته). باز هم این کار را تا عنصر (n - ۲)ام تکرار میکنیم ، و بازهم .... تا اینکه بالاخره دادهها مرتب میشوند. مثلا:
مرحله اول سه مقایسه ، مرحله دوم دو مقایسه و مرحله سوم یک مقایسه داره ، که روی هم میشوند شش مقایسه. در کل این روش n (n - ۱) / ۲ مقایسه لازم داره. اما نه همیشه. به مثال زیر توجه کنید:
همونطور که میبینید انتهای مرحله ۲ دادهها مرتب هستن. تشخیص این مساله هم کار سختی نیست: اگه به مرحلهای رسیدیم که هیچ جابجایی در اون رخ نداد نتیجه میشه که دادهها مرتب هستن (مرحله سوم). پس بعد از مرحله ۳ مطمئن میشیم که داده هامون مرتب شدن و نیازی به مراحل ۴ و ۵ نیست. پیاده سازی (مرتب سازی حبابی) در c++
مرتب سازی گزینشی (انتخابی):
(به انگلیسی: Selection Sort)
معمولاً اطلاعات و دادههای خامی که در اختیار برنامه نویس قرار داره بصورت نامرتب هستن. مواقعی پیش مییاد که لازمه این دادهها بر حسب فیلد خاصی مرتب بشن؛ مثل لیست دانش آموزان بر حسب معدل ، لیست کارمندان بر حسب شماره پرسنلی ، لیست دفترچه تلفن بر حسب نام خانوادگی و ... روشهای متعددی برای مرتب سازی وجود داره که من قصد دارم تا حد امکان شما رو با این روشها آشنا کنم. برای شروع روش مرتب سازی انتخابی (Selection Sort) رو توضیح میدم.
روش انتخابی اولین روشیه که به ذهن میرسه: بزرگترین رکورد بین رکوردهای لیست رو پیدا میکنیم و به انتهای لیست انتقال میدیم. از بقیه رکوردها بزرگترین رو انتخاب میکنیم و انتهای لیست - کنار رکورد قبلی - قرار میدیم و ... مثلا:
پیاده سازی (مرتب سازی انتخابی) در c++:
void selection_sort (int arr[] , int n)
{
register int i , j;
int max , temp;
(--for (i = n - ۱ ; i > ۰ ; i
}
max = ۰;
for (j = ۱ ; j <= i ; j++)
if (arr[ max ] < arr[ j])
max = j;
; ] temp = arr[ i
arr[ i ] = arr[ max];
arr[ max ] = temp;
}
}
مرتب سازی سریع:
(به انگلیسی: Quick Sort)
مرتب سازی سریع (Quick Sort) از جمله روشهای محبوب و با سرعت بالا برای مرتب کردن دادهها محسوب میشه. این روش هم مثل روش ادغام از تقسیم و حل (Divide and Conqure) برای مرتب کردن دادهها استفاده میکنه. به این ترتیب که دادهها رو به دو قسمت مجزا تقسیم، و با مرتب کردن اونها کل دادهها رو مرتب میکنه. برای اینکار یکی از دادهها (مثلاً داده اول) به عنوان محور انتخاب میشه. دادهها بر اساس محور طوری چینش میشن که همه دادههای کوچکتر از محور سمت چپ و دادههای بزرگتر یا مساوی اون سمت راستش قرار میگیرن. با مرتب کردن دو قسمت به دست اومده کل دادهها مرتب میشن. در این حالت مثل روش ادغام نیازی به ادغام کردن دادهها نیست. چرا که قسمت سمت راست همگی از قسمت سمت چپ کوچکتر هستن و بالعکس. مثلاً اعداد صحیح زیر رو در نظر بگیرید:
پیاده سازی مرتب سازی Quick sort در c++
تابع partition با دریافت آرایه و حد بالا و پایین تکهای که باید تقسیم بشه عملیات لازم رو انجام میده، و اندیس محل تفکیک رو (محل عدد ۵ در مثال بالا) به عنوان نتیجه بر میگردونه.
بر اساس گفتههای بالا تابع مرتب سازی به این صورت خواهد بود:
همونطور که مشاهده میکنید این تابع بصورت بازگشتی نوشته شده. در صورتی که بخواید به صورت غیر بازگشتی بنویسید باید از پشته به صورت زیر استفاده کنید:
void quick_sort (int arr[ ] ,int n)
{
stack st;
st.push(۰);
st.push(n – ۱);
int low , p , high;
while(! st.isempty())
{
high = st.pop();
low = st.pop();
p = partition(arr , low , high);
if (p > low)
{
st.push(low);
st.push(p – ۱);
}
if (p < high)
{
st.push(p + ۱);
st.push(high);
}
}
}
پر استفادهترین ترتیبها، ترتیبهای عددی و لغتنامهای هستند. مرتبسازی کارا در بهینه سازی الگوریتمهایی که به لیستهای مرتب شده نیاز دارند (مثل جستجو و ترکیب) اهمیت زیادی دارد.
از ابتدای علم کامپیوتر مسائل مرتبسازی تحقیقات فراوانی را متوجه خود ساختند، شاید به این علت که در عین ساده بودن، حل آن به صورت کارا پیچیدهاست. برای مثال مرتبسازی حبابی در سال ۱۹۵۶ به وجود آمد. در حالی که بسیاری این را یک مسئلهٔ حل شده میپندارند، الگوریتم کارآمد جدیدی همچنان ابداع میشوند (مثلاً مرتبسازی کتاب خانهای در سال ۲۰۰۴ مطرح شد).
مبحث مرتبسازی در کلاسهای معرفی علم کامپیوتر بسیار پر کاربرد است، مبحثی که در آن وجود الگوریتمهای فراوان به آشنایی با ایدههای کلی و مراحل طراحی الگوریتمهای مختلف کمک میکند؛ مانند تحلیل الگوریتم، دادهساختارها، الگوریتمهای تصادفی، تحلیل بدترین و بهترین حالت و حالت میانگین، هزینهٔ زمان و حافظه، و حد پایین.
سه تا از معروف ترین الگوریتم ها رو گذاشتم اینجا، اگه خواستین بقیه اش رو هم بخونین، برین تو ویکی پدیا ببینید
مرتب سازی حبابی:
(به انگلیسی: Bubble Sort)
فرض کنید میخواهیم n داده به صورت صعودی مرتب شوند. عنصر اول را با با عنصر دوم مقایسه کرده، و در صورتی که عنصر اول بزرگتر باشد باشد جای عنصر اول و دوم را عوض میکنیم. همین کار را با عناصر دوم و سوم انجام میدهیم و همینطور عناصر سوم و چهارم ، الی آخر. وقتی این کار تمام شد بزرگترین عنصر بین دادهها به آخر لیست میرسد . حالا یک بار دیگر از اول این کار را انجام میدهیم اما این بار تا عنصر (n -۱)ام ادامه میدهیم (عنصر nام در مرحله اول در جای خودش قرار گرفته). باز هم این کار را تا عنصر (n - ۲)ام تکرار میکنیم ، و بازهم .... تا اینکه بالاخره دادهها مرتب میشوند. مثلا:
۰ - ۰) ۵ ۶ ۴ ۲
۱ - ۱) ۵ ۶ ۴ ۲
۱ - ۲) ۵ ۴ ۶ ۲
۱ - ۳) ۵ ۴ ۲ ۶
۲ - ۱) ۴ ۵ ۲ ۶
۲ - ۲) ۴ ۲ ۵ ۶
۳ - ۱) ۲ ۴ ۵ ۶
۱ - ۱) ۵ ۶ ۴ ۲
۱ - ۲) ۵ ۴ ۶ ۲
۱ - ۳) ۵ ۴ ۲ ۶
۲ - ۱) ۴ ۵ ۲ ۶
۲ - ۲) ۴ ۲ ۵ ۶
۳ - ۱) ۲ ۴ ۵ ۶
مرحله اول سه مقایسه ، مرحله دوم دو مقایسه و مرحله سوم یک مقایسه داره ، که روی هم میشوند شش مقایسه. در کل این روش n (n - ۱) / ۲ مقایسه لازم داره. اما نه همیشه. به مثال زیر توجه کنید:
۰ - ۰) ۰ ۷ ۱ ۳ ۵ ۴
۱ - ۱) ۰ ۱ ۷ ۳ ۵ ۴
۱ - ۲) ۰ ۱ ۷ ۳ ۵ ۴
۱ - ۳) ۰ ۱ ۳ ۷ ۵ ۴
۱ - ۴) ۰ ۱ ۳ ۵ ۷ ۴
۱ - ۵) ۰ ۱ ۳ ۵ ۴ ۷
۲ - ۱) ۰ ۱ ۳ ۵ ۴ ۷
۲ - ۲) ۰ ۱ ۳ ۵ ۴ ۷
۲ - ۳) ۰ ۱ ۳ ۵ ۴ ۷
۲ - ۴) ۰ ۱ ۳ ۴ ۵ ۷
۳ - ۱) ۰ ۱ ۳ ۴ ۵ ۷
۳ - ۲) ۰ ۱ ۳ ۴ ۵ ۷
۳ - ۳) ۰ ۱ ۳ ۴ ۵ ۷
۴ - ۱) ۰ ۱ ۳ ۴ ۵ ۷
۴ - ۲) ۰ ۱ ۳ ۴ ۵ ۷
۵ - ۱) ۰ ۱ ۳ ۴ ۵ ۷
۱ - ۱) ۰ ۱ ۷ ۳ ۵ ۴
۱ - ۲) ۰ ۱ ۷ ۳ ۵ ۴
۱ - ۳) ۰ ۱ ۳ ۷ ۵ ۴
۱ - ۴) ۰ ۱ ۳ ۵ ۷ ۴
۱ - ۵) ۰ ۱ ۳ ۵ ۴ ۷
۲ - ۱) ۰ ۱ ۳ ۵ ۴ ۷
۲ - ۲) ۰ ۱ ۳ ۵ ۴ ۷
۲ - ۳) ۰ ۱ ۳ ۵ ۴ ۷
۲ - ۴) ۰ ۱ ۳ ۴ ۵ ۷
۳ - ۱) ۰ ۱ ۳ ۴ ۵ ۷
۳ - ۲) ۰ ۱ ۳ ۴ ۵ ۷
۳ - ۳) ۰ ۱ ۳ ۴ ۵ ۷
۴ - ۱) ۰ ۱ ۳ ۴ ۵ ۷
۴ - ۲) ۰ ۱ ۳ ۴ ۵ ۷
۵ - ۱) ۰ ۱ ۳ ۴ ۵ ۷
همونطور که میبینید انتهای مرحله ۲ دادهها مرتب هستن. تشخیص این مساله هم کار سختی نیست: اگه به مرحلهای رسیدیم که هیچ جابجایی در اون رخ نداد نتیجه میشه که دادهها مرتب هستن (مرحله سوم). پس بعد از مرحله ۳ مطمئن میشیم که داده هامون مرتب شدن و نیازی به مراحل ۴ و ۵ نیست. پیاده سازی (مرتب سازی حبابی) در c++
void bubble_sort (int arr [ ] , int n)
{
register int i , j , t , c;
(-- for (i = n - ۲ ; i >= ۰ ; i
{
c = ۰;
(++ for (j = ۰ ; j <= i ; j
if (arr [ j ] > arr [ j + ۱ ])
{
; ] t = arr [ j
arr [ j ] = arr [ j + ۱ ];
; arr [ j + ۱ ] = t
C++;
}
(if (c == ۰
; break
}
}
{
register int i , j , t , c;
(-- for (i = n - ۲ ; i >= ۰ ; i
{
c = ۰;
(++ for (j = ۰ ; j <= i ; j
if (arr [ j ] > arr [ j + ۱ ])
{
; ] t = arr [ j
arr [ j ] = arr [ j + ۱ ];
; arr [ j + ۱ ] = t
C++;
}
(if (c == ۰
; break
}
}
مرتب سازی گزینشی (انتخابی):
(به انگلیسی: Selection Sort)
معمولاً اطلاعات و دادههای خامی که در اختیار برنامه نویس قرار داره بصورت نامرتب هستن. مواقعی پیش مییاد که لازمه این دادهها بر حسب فیلد خاصی مرتب بشن؛ مثل لیست دانش آموزان بر حسب معدل ، لیست کارمندان بر حسب شماره پرسنلی ، لیست دفترچه تلفن بر حسب نام خانوادگی و ... روشهای متعددی برای مرتب سازی وجود داره که من قصد دارم تا حد امکان شما رو با این روشها آشنا کنم. برای شروع روش مرتب سازی انتخابی (Selection Sort) رو توضیح میدم.
روش انتخابی اولین روشیه که به ذهن میرسه: بزرگترین رکورد بین رکوردهای لیست رو پیدا میکنیم و به انتهای لیست انتقال میدیم. از بقیه رکوردها بزرگترین رو انتخاب میکنیم و انتهای لیست - کنار رکورد قبلی - قرار میدیم و ... مثلا:
۰: ۹ ۱ ۶ ۴ ۷ ۳ ۵
۱: ۵ ۱ ۶ ۴ ۷ ۳ ۹
۲: ۵ ۱ ۶ ۴ ۳ ۷ ۹
۳: ۵ ۱ ۳ ۴ ۶ ۷ ۹
۴: ۴ ۱ ۳ ۵ ۶ ۷ ۹
۵: ۳ ۱ ۴ ۵ ۶ ۷ ۹
۶: ۱ ۳ ۴ ۵ ۶ ۷ ۹
۱: ۵ ۱ ۶ ۴ ۷ ۳ ۹
۲: ۵ ۱ ۶ ۴ ۳ ۷ ۹
۳: ۵ ۱ ۳ ۴ ۶ ۷ ۹
۴: ۴ ۱ ۳ ۵ ۶ ۷ ۹
۵: ۳ ۱ ۴ ۵ ۶ ۷ ۹
۶: ۱ ۳ ۴ ۵ ۶ ۷ ۹
پیاده سازی (مرتب سازی انتخابی) در c++:
void selection_sort (int arr[] , int n)
{
register int i , j;
int max , temp;
(--for (i = n - ۱ ; i > ۰ ; i
}
max = ۰;
for (j = ۱ ; j <= i ; j++)
if (arr[ max ] < arr[ j])
max = j;
; ] temp = arr[ i
arr[ i ] = arr[ max];
arr[ max ] = temp;
}
}
مرتب سازی سریع:
(به انگلیسی: Quick Sort)
مرتب سازی سریع (Quick Sort) از جمله روشهای محبوب و با سرعت بالا برای مرتب کردن دادهها محسوب میشه. این روش هم مثل روش ادغام از تقسیم و حل (Divide and Conqure) برای مرتب کردن دادهها استفاده میکنه. به این ترتیب که دادهها رو به دو قسمت مجزا تقسیم، و با مرتب کردن اونها کل دادهها رو مرتب میکنه. برای اینکار یکی از دادهها (مثلاً داده اول) به عنوان محور انتخاب میشه. دادهها بر اساس محور طوری چینش میشن که همه دادههای کوچکتر از محور سمت چپ و دادههای بزرگتر یا مساوی اون سمت راستش قرار میگیرن. با مرتب کردن دو قسمت به دست اومده کل دادهها مرتب میشن. در این حالت مثل روش ادغام نیازی به ادغام کردن دادهها نیست. چرا که قسمت سمت راست همگی از قسمت سمت چپ کوچکتر هستن و بالعکس. مثلاً اعداد صحیح زیر رو در نظر بگیرید:
۵ ۶ ۱ ۹ -۲ ۴ ۵ ۱۵ ۳ ۱ ۴ ۱۰
عدد ۵ رو به عنوان محور در نظر میگیریم. دادهها به این صورت بازچینی میشن:۱ -۲ ۴ ۳ ۱ ۴ ۵ ۶ ۹ ۵ ۱۵ ۱۰
همونطور که مشاهده میکنید اعداد سمت چپ عدد ۵ زیر خط دار همگی از ۵ کوچیکتر و اعداد سمت راست بزرگتر یا مساوی اون هستن.پیاده سازی مرتب سازی Quick sort در c++
تابع partition با دریافت آرایه و حد بالا و پایین تکهای که باید تقسیم بشه عملیات لازم رو انجام میده، و اندیس محل تفکیک رو (محل عدد ۵ در مثال بالا) به عنوان نتیجه بر میگردونه.
int partition (int arr[ ] , int low , int high)
{
int lb = low + ۱ , rb = high , temp , pivot = arr[ low ] , p;
while (lb <= rb)
{
while (arr[ lb ] <= pivot && lb <= rb)
lb++;
while (arr[ rb ] > pivot && lb <= rb)
rb--;
if (lb < rb)
{
temp = arr[ lb];
arr[ lb ] = arr[ rb];
arr[ rb ] = temp;
}
}
(if (rb == high
p = high;
else if(rb == low)
p = low;
else
p = lb – ۱;
arr[ low ] = arr[ p];
arr[ p ] = pivot;
return p;
}
اگه این تابع رو برای مثال بالا استفاده کنیم مقدار ۶ (اندیس ۵ زیرخط دار) برگشت داده میشه. با تکرار کردن این عملیات برای دو قسمت به دست اومده (در مثال بالا از اندیس صفر تا ۵ و از اندیس ۷ تا ۱۱) دادهها به صورت کامل مرتب میشن.{
int lb = low + ۱ , rb = high , temp , pivot = arr[ low ] , p;
while (lb <= rb)
{
while (arr[ lb ] <= pivot && lb <= rb)
lb++;
while (arr[ rb ] > pivot && lb <= rb)
rb--;
if (lb < rb)
{
temp = arr[ lb];
arr[ lb ] = arr[ rb];
arr[ rb ] = temp;
}
}
(if (rb == high
p = high;
else if(rb == low)
p = low;
else
p = lb – ۱;
arr[ low ] = arr[ p];
arr[ p ] = pivot;
return p;
}
بر اساس گفتههای بالا تابع مرتب سازی به این صورت خواهد بود:
void quick_sort (int arr[ ] , int low , int high)
{
if (low < high)
{
int p = partition(arr , low , high);
quick_sort(arr , low , p – ۱);
quick_sort(arr , p + ۱ , high);
}
}
{
if (low < high)
{
int p = partition(arr , low , high);
quick_sort(arr , low , p – ۱);
quick_sort(arr , p + ۱ , high);
}
}
همونطور که مشاهده میکنید این تابع بصورت بازگشتی نوشته شده. در صورتی که بخواید به صورت غیر بازگشتی بنویسید باید از پشته به صورت زیر استفاده کنید:
void quick_sort (int arr[ ] ,int n)
{
stack st;
st.push(۰);
st.push(n – ۱);
int low , p , high;
while(! st.isempty())
{
high = st.pop();
low = st.pop();
p = partition(arr , low , high);
if (p > low)
{
st.push(low);
st.push(p – ۱);
}
if (p < high)
{
st.push(p + ۱);
st.push(high);
}
}
}