صفحه اصلی

صفحه شخصی مسعود اقدسی‌فام
الگوریتمستان - آموخته‌های من از دنیای برنامه‌نویسی و طراحی الگوریتم
تعداد امتیازهای ثبت شده:  513

میانگین امتیازهای ثبت شده:  4.29 از 5.00
عبارت مورد نظر:

     

الگوریتمستان آشنایی با آرایه پویای یک بعدی و کاربردهای آن در زبان برنامه‌نویسی ++C

الگوریتمستان بررسی مفهوم و روش پیاده‌سازی لیست پیوندی و توابع مرتبط آن به زبان برنامه‌نویسی ++C

الگوریتمستان آشنایی با صف اولویتی (Priority Queue)، کاربردها و نحوه پیاده‌سازی آن

الگوریتمستان بحث در مورد ضرب زنجیره‌ای ماتریس‌ها و روش پیاده‌سازی الگوریتم پرانتزبندی بهینه آن با روش تقسیم و حل و روش برنامه‌نویسی پویا

الگوریتمستان آشنایی با الگوریتم استراسن برای محاسبه حاصلضرب ماتریس‌ها

الگوریتمستان بحث در مورد مساله کاشی‌کاری یا فرش کردن زمین با موزاییک به روش تقسیم و حل

الگوریتمستان معرفی کتاب Art of Programming Contest برای علاقه‌مندان حل سوالات الگوریتمی و شرکت‌کنندگان مسابقات برنامه‌نویسی، با قابلیت دانلود

الگوریتمستان بررسی مساله مربی ناامید، از سوالات مسابقات برنامه‌نویسی ACM

الگوریتمستان آشنایی با روش مرتب‌سازی حبابی و بحث در مورد عملکرد آن، با قطعه کد به زبان برنامه‌نویسی ++C

الگوریتمستان بررسی روش‌های مختلف محاسبه ضرایب دوجمله‌ای نیوتن یا ترکیب دو عدد با قطعه کد به زبان برنامه‌نویسی ++C

الگوریتمستان آشنایی با روش مرتب‌سازی ادغامی با قطعه کدهایی به زبان برنامه‌نویسی ++C

الگوریتمستان آشنایی با روش مرتب‌سازی هرمی (Heap Sort)


»   روش تقسیم و غلبه شنبه، 9 خرداد ماه 1388، ساعت 08:56

مطلبی که می‌خوانید، ویراست دوم مطلبی است که نسخه اولیه آن با عنوان "روش تقسیم و حل" از طریق وب‌سایت برنامه‌نویسی و طراحی الگوریتم منتشر شده بود.

یکی از روش‌های پرکاربرد و محبوب برای طراحی الگوریتم‌ها روش Divide and Conquer است که در زبان فارسی به صورت تقسیم و حل یا تقسیم و غلبه ترجمه شده است.

در این روش، داده‌ها به دو یا چند دسته تقسیم شده و حل می‌شوند. سپس با ترکیب مناسب نتایج به دست آمده از این زیرمساله‌ها، مساله اصلی حل می‌شود. در صورتی که زیرمساله خود به اندازه کافی بزرگ باشد، می‌توان از همین روش برای حل آن استفاده کرد. تقسیمات متوالی زیرمساله‌ها تا جایی ادامه پیدا می‌کند که به اندازه کافی کوچک شده باشند و بتوان آنها را با روش‌های دیگر به راحتی حل نمود.

برای آشتایی بیشتر، چند الگوریتم که با روش حل و تقسیم پیاده‌سازی شده‌اند معرفی می‌شوند.

 

1. مرتب‌سازی سریع (Quick Sort)

در روش مرتب‌سازی سریع داده‌های ورودی را بر حسب یکی از عناصر به نام محور به دو قسمت نه لزوما هم‌اندازه تقسیم کرده و هر کدام را جداگانه مرتب می‌کنیم.

 

2. مرتب‌سازی ادغامی (Merge Sort)

در این روش نیز همانند روش مرتب‌سازی سریع داده‌ها به دو قسمت تقسیم می‌شوند. اما روش تقسیم کردن داده‌ها متفاوت است. طوری که قسمت‌های به دست آمده از تقسیم تقریبا هم‌اندازه هستند. پس از مرتب کردن زیر آرایه‌ها، با ادغام آنها آرایه اصلی به صورت مرتب‌شده حاصل می‌شود.

 

3. ضرب استراسن

روش ضرب استراسن برای بهینه کردن عمل ضرب ماتریس‌ها توسط شخصی به نام استراسن معرفی شده است. در این روش هر کدام از ماتریس‌ها به چهار زیرماتریس تقسیم شده و عملیات ضرب با استفاده از آنها و رابطه‌هایی که استراسن عنوان کرده انجام می‌شود. با استفاده از این روش مرتبه اجرایی ضرب ماتریس از ( O( n3 به ( O( n2.8 کاهش پیدا می‌کند که در ماتریس‌هایی با ابعاد بزرگ منجر به افزایش سرعت چشمگیری می‌شود.

 

4. ضرب چندجمله‌ای‌ها و ضرب اعداد بسیار بزرگ

با استفاده از روش تقسیم و حل می‌توان روشی بهینه‌تر از ضرب عادی چندجمله‌ای‌ها برای آنها تعریف کرد. در این روش چند‌جمله‌ای‌ها به دو قسمت تقسیم شده و با استفاده از یک سری روابط، ضرب و جمع شده و نتیجه نهایی را می‌دهند. از همین روش با اندکی تغییر برای ضرب اعداد بسیار بزرگ هم می‌توان استفاده کرد که با اعمال آن، مرتبه ضرب از ( O( n2 به ( O( n1.58 کاهش پیدا می‌کند.

 

5. مساله کاشی‌کاری (فرش کردن صفحه شطرنجی با موزاییک)

مساله کاشی‌کاری از مسائل جالب طراحی الگوریتم است. در این مساله از شما خواسته می‌شود سطح یک قطعه زمین را که به صورت صفحه شطرنج شبکه‌بندی شده است با استفاده از کاشی‌هایی با شکل خاص بپوشانید. به طوری که خانه خاصی از این شبکه خالی بماند. می‌توان فرض کرد خانه خالی برای باغچه یا حوضچه کوچکی کنار گذاشته شده است.

 

6. مساله تنظیم جدول مسابقات (تورنمنت)

شما را مسئول تهیه جدول مسابقات تیم‌های فوتبال محله کرده‌اند! این بازی‌ها به صورت دوره‌ای بوده و هر تیمی باید با تمام تیم‌های دیگر بازی کند. در ضمن هر تیم در روز تنها می‌تواند یک بازی انجام دهد. برای تهیه جدول مسابقات به صورت بهینه - که مسابقات در کوتاهترین زمان ممکن برگزار شود - الگوریتمی ابداع شده است که از روش تقسیم و حل استفاده می‌کند.

 

7. جستجوی دودویی (Binary Search)

برای یافتن عنصری در یک آرایه نامرتب چاره‌ای نداریم جز این که از روش جستجوی خطی استفاده کنیم. در این روش از ابتدای آرایه شروع کرده و تک‌تک عناصر را بررسی می‌کنیم، تا زمانی که به عنصر دلخواه برسیم. بنابراین اگر آرایه مورد نظر n عنصر داشته باشد، مرتبه اجرایی روش جستجوی خطی ( O( n خواهد بود. اما در مورد آرایه مرتب روش دیگری نیز وجود دارد: روش جستجوی دودویی.

در جستجوی دودویی عنصر وسط آرایه را بررسی می‌کنیم. در صورتی که این عنصر همان عنصر مورد نظر باشد، جستجو تمام می‌شود. اگر نه، باید قسمت‌های راست و چپ عنصر وسط را که تقریبا به یک اندازه هستند مورد جستجو قرار دهیم. اما آیا لازم است هر دو سمت جستجو شود؟ چون آرایه مرتب شده است، عناصر کوچکتر از عنصر مرکز همگی در سمت چپ، و عناصر بزرگتر در سمت راست آن قرار دارند (آرایه را مرتب شده صعودی در نظر گرفته‌ام). با توجه به این مساله که عنصر مورد نظر ما کوچکتر از عنصر مرکزی آرایه است یا بزرگتر، تنها یکی از دو زیر آرایه را بررسی می‌کنیم. در نتیجه در هر مرحله بازه مورد جستجو نصف می‌شود.

برای یافتن مرتبه اجرایی الگوریتم به این صورت عمل می‌کنیم: فرض کنید ( T( n حداکثر تعداد مقایسه‌های لازم برای یافتن عنصر مورد نظرمان در میان n داده باشد. در روش جستجوی خطی T( n ) = n بود. در روش جستجوی دودویی ابتدا عنصر وسط را با عنصر مورد نظرمان مقایسه می‌کنیم. اگر عنصر یافت نشود، در مرحله بعد تنها یکی از دو زیر آرایه بررسی می‌شود که نصف کل عناصر را دارد. پس می‌توان نوشت:

 

T( n ) = T ( n / 2 ) + 1

 

با حل این رابطه بازگشتی به عبارت زیر می‌رسیم:

 

T( n ) = [ log2n ] + 1

 

که در آن منظور از [ ] علامت جزء صحیح است. مرتبه اجرایی این الگوریتم ( O( log n است که در مقایسه با ( O( n در جستجوی خطی بسیار کارآمد است. به عنوان نمونه، برای یافتن عنصری در یک آرایه به طول یک میلیون، در بدترین حالت با استفاده از جستجوی خطی یک میلیون مقایسه و در جستجوی دودویی تنها بیست مقایسه نیاز است.

نکته 1: ممکن است این سوال مطرح شود که هزینه مرتب کردن یک آرایه به مراتب بیشتر از هزینه جستجوی خطی است. چه لزومی به انجام این کار است؟ لیست قبول‌شدگان کنکور را در نظر بگیرید. این لیست پس از آماده شدن تنها یک بار بر اساس شماره داوطلبی مرتب شده و در سایت سازمان سنجش قرار می‌گیرد. پس از آن، طی چند روز میلیون‌ها مراجعه و جستجو در لیست برای مشاهده نتیجه صورت می‌گیرد. در این حالت مطمئنا هزینه چند میلیون جستجویی که انجام می‌شود، بسیار مهم‌تر از هزینه یک بار مرتب‌سازی آن است. بیشتر کاربردهای این روش جستجو هم در همین نوع داده‌ها است.

 

پیاده‌سازی الگوریتم‌های تقسیم و حل

در اکثر مواقع می‌توان الگوریتم‌های طراحی شده توسط روش تقسیم و حل را به صورت بازگشتی پیاده سازی کرد. چرا که هر کدام از زیرمساله‌ها یک مساله از همان نوع با پارامترهای متفاوت هستند.

در مورد جستجوی دودویی، پیاده‌سازی بازگشتی روش به زبان برنامه‌نویسی ++C به این ترتیب است:

 

int BinarySearch_1( int arr[ ], int left, int right, int x )

{

  if( left > right )

  {

    return -1;

  }

  int m = ( left + right ) / 2, result;

  if( arr[ m ] == x )

  {

    result = m;

  }

  else if( arr[ m ] > x )

  {

    result = BinarySearch_1( arr, left, m - 1, x );

  }

  else

  {

    result = BinarySearch_1( arr, m + 1, right , x );

  }

  return result;

}

 

تابع فوق چهار پارامتر arr (آرایه‌ای که جستجو در آن انجام می‌شود)، left و right (مرزهای محدوده‌ای که جستجو باید در آن انجام شود) و x (عنصری که باید پیدا کنیم) را دریافت کرده و اندیس محلی که عنصر مورد نظر یافت شده بر می‌گرداند. به عنوان مثال اگر به دنبال عدد 78 در آرایه arr به طول هزار هستیم، باید تابع را به صورت زیر فراخوانی کنیم:

 

i = BinarySearch_1( arr, 0, 999, 78 );

 

مقدار i پس از بازگشت از تابع برابر اندیس محل عنصر 78 در آرایه خواهد بود. اگر این عنصر یافت نشود مقدار 1- بازگشت داده می‌شود.

روش جستجوی دودویی پیاده‌سازی غیربازگشتی ساده‌تری هم دارد:

 

int BinarySearch_2( int arr[ ], int n, int x )

{

  int left = 0, right = n - 1, m;

  while( left <= right )

  {

    m = ( left + right ) / 2;

    if ( arr[ m ] == x )

    {

      return m;

    }

    if( arr[ m ] > x )

    {

      right = m - 1;

    }

    else

    {

      left = m + 1;

    }

  }

  return -1;

}

 

که در آن n تعداد عناصر آرایه است. مسلما سرعت اجرای این روش بیشتر از روش بازگشتی آن است. اما همیشه اینگونه نیست که پیاده‌سازی غیربازگشتی یک تابع سریعتر از پیاده‌سازی بازگشتی آن باشد.

نکته 2: در معرفی روش تقسیم و حل عنوان کردم که اگر زیرمساله به اندازه کافی کوچک باشد از این روش برای حل آن استفاده نمی‌کنیم. تعیین این اندازه - که به آن مقدار آستانه گویند - بر اساس روش طراحی الگوریتم و همینطور روش‌های دیگر موجود صورت می‌گیرد که بحث مفصلی را می‌طلبد.

نکته 3: زمانی که مساله را به چند زیرمساله تقسیم می‌کنیم، اگر تقسیم طوری باشد که هر زیرمساله خودش نزدیک به n ورودی داشته باشد، الگوریتم کارا نخواهد بود. نمونه چنین مسائلی محاسبه بازگشتی جمله nام دنباله فیبوناتچی است.

‌چاپ مطلب
نسخه قابل چاپ مشاهده نسخه قابل چاپ و ارسال به چاپگر
به اشتراک گذاری مطلب
FriendFeed       Twitter       Facebook       Cloob
آمار
تعداد امتیازهای ثبت شده:  34 ،  میانگین امتیازهای ثبت شده:  4.56 از 5.00
‌برچسب‌ها
طراحی الگوریتم‌ها ، روش تقسیم و غلبه
امتیاز مطلب
1 2 3 4 5
ارسال پیام
» 3پیده

سه‌شنبه، 19 آبان ماه 1388، ساعت 15:11
سلام ، با تشکر از مطالب جالب شما،اگر امکان دارد الگوریتم شماره 5 را قرار دهید.   با تشکر

» مسعود اقدسی‌فام

سه‌شنبه، 19 آبان ماه 1388، ساعت 15:25
سلام سپیده خانم
اگه فرصت مناسبی داشته باشم، حتما در مورد الگوریتم کاشی کاری مطلبی خواهم نوشت.

» mina

شنبه، 23 آبان ماه 1388، ساعت 22:35
استادمون ازمون خواسته واسه فرش کردن صفحه شطرنج با vbبرنامه بنویسیم(بدون اینکه توضیحی بدن!!!!)
لطفا راهنمائیم کنید .ممنون!

» شراره

پنجشنبه، 19 آذر ماه 1388، ساعت 10:46
سلام به همگی
خواهش میکنم اگه کسی طریقه ی پیدا کردن آستانه مناسب برای ماتریس استراسن رو بلده خیلی فوری برام میل کنه
مرسی
فقط سریع

» شراره

پنجشنبه، 19 آذر ماه 1388، ساعت 10:49
در حد راهنمایی باشه بسه

» آنا

دوشنبه، 21 دی ماه 1388، ساعت 12:29
سلام دوست عزیز
الگوریتم ضرب اعداد با تقسیم و غلبه را که هر عدد به 2 قسمت تقسیم و تعداد ضربها کم  میشه بلدم. یه راهنمایی کن واسه اینکه اعداد به 3 قسمت تقسیم شه و تعداد ضرب از 9تا به 6تا یا 5تا کاهش پیدا کنه.
دست گلت درد نکنه.
فقط لطف کن زود آخه شنبه امتحان الگوریتم دارم.

» آنا

سه‌شنبه، 22 دی ماه 1388، ساعت 15:35
بازم منم سلام
چرا جواب منو نمیدی؟
جان آنا من امتحان دارم نیاز دارم به جوابش

» مسعود اقدسی‌فام

سه‌شنبه، 22 دی ماه 1388، ساعت 15:53
آنا جان من تازه پیام شما رو اینجا خوندم. اجازه بده کمی روی حل مساله فکر کنم. اگه به جایی رسیدم . . .

» آنا

پنجشنبه، 24 دی ماه 1388، ساعت 16:20
آقا مسعود من فقط تا شنبه فرصت دارم. اگه بتونی کمکم کنی یه دنیا ممنونت میشم
دستت درد نکنه

» مسعود اقدسی‌فام

پنجشنبه، 24 دی ماه 1388، ساعت 21:58
آنا جان، متاسفانه به خاطر مشغله های فکری نتونستم روی حل مساله تمرکز کنم. تا عصر شنبه هم دسترسی به اینترنت نخواهم داشت.
متاسفم که نشد کمکی بکنم.

» آنا

جمعه، 25 دی ماه 1388، ساعت 16:08
سلام دوست خوبم.بالاخره جوابو پیدا کردم. دوست داشتم واست بفرستمش اگه دوست دیگه ای لازم داشت ازش استفاده کنی اما نمیدونم چه جوری.
یه فایل تصویری هست
راهنمایی کن تا واست بفرستم

» مسعود اقدسی‌فام

شنبه، 26 دی ماه 1388، ساعت 16:00
سلام آنا جان،
از منوی سمت راست روی آیکون پروفایل کلیک کن. به محلی می ری که آدرس پست الکترونیکی من هم نوشته شده. ممنون از لطفت.

» هانیه

چهارشنبه، 30 دی ماه 1388، ساعت 15:34
کسی میتونه الگوریتمی بنویسه یک عنصر تویه یک آرایه n*n پیدا کنه و مرتبه زمانیش کمتر از خطی باشه؟؟؟؟؟؟؟

» مسعود اقدسی‌فام

چهارشنبه، 30 دی ماه 1388، ساعت 15:51
ترتیب چینش عناصر در آرایه شرط خاصی نداره؟

» پژمان

سه‌شنبه، 18 اسفند ماه 1388، ساعت 20:27
با سلام. من روشي رو ابداع كردم كه ركورد استراسن رو تا 1 پايين مياره. سال 89 صداش در مياد.

» مسعود اقدسی‌فام

سه‌شنبه، 3 فروردین ماه 1389، ساعت 22:53
سال 89 شروع شده ها پژمان جان. بی صبرانه منتظر خبرش هستیم.

» ش.ف

یکشنبه، 8 فروردین ماه 1389، ساعت 20:46
سلام دوست عزیز
اگر امکان داره در مورد الگوریتمی که بتونه حداقل فاصله بین دو نقطه از میان n نقطه رو پیدا کنه (به روش تقسیم و حل) کمی راهنمایی کنید.
(فقط خواهش می کنم یه کم سریع)

» همتا

سه‌شنبه، 17 فروردین ماه 1389، ساعت 15:10
سلام دوست عزیز
میشه یک راهنمایی در مورد اینکه چطور میشه توی ضرب استراسن  طول آرایه رو بصورت بازگشتی توی هر مرحله تعیین کرد بکنی؟ یعنی دست کاربر برای تعیین n در اول برنامه باز باشه؟ آخه من هرجا این ماتریسو دیدم 2*2 یا 4*4 نوشته شده بود

» مسعود اقدسی‌فام

چهارشنبه، 18 فروردین ماه 1389، ساعت 19:38
در زبان ++C می شه تابع رو با آرگومانی از نوع آرایه بدون طول - با طول نامشخص - تعریف کرد. کافیه یه آرگومان دیگه هم تعریف کنید که طول آرایه رو نگه داره. مثل ( int func( int arr[], int n
در حالتی که آرایه دو بعدی باشه، باید تعداد سطرها مشخص باشه. در این حالت می شه یه حداکثر برای تعداد سطرهای ماتریسهامون در نظر بگیریم، و اون عدد رو به عنوان تعداد سطر ماتریس ارسالی به تابع استفاده کنیم.

» ali

جمعه، 10 اردیبهشت ماه 1389، ساعت 22:09
سلام اگه حل المسائل طراحی دارید برام ارسال کنید یا ادرس بدید تا دانلود کنم با تشکر

» امل

پنجشنبه، 15 اردیبهشت ماه 1390، ساعت 17:47
سلام
خیلی  مطالبتون به دردم خورد ازت متشکرم
میشه بیشتر در مورد حل معادلات بازگشتی اعم از همگن و نا همگن و با استفاده از متغیر مثال بگید و تو ضیح بدید ممنوناز لطفتون

» میثم

سه‌شنبه، 19 مهر ماه 1390، ساعت 21:31
سلام سری فیبوناچی و جستجوی ترتیبی را به روش تقسیم و غلبه می خواستم

» xman

جمعه، 4 آذر ماه 1390، ساعت 13:30
با سلام و خسته نباشید
درخواست برنامه مجموعه اعداد صحیح  در ++c را دارم می خواستم می نواتید این برنامه را بنویسید

» sima

یکشنبه، 27 آذر ماه 1390، ساعت 17:05
ناز نفس

» az

یکشنبه، 30 بهمن ماه 1390، ساعت 12:36
لطفا مسائل بیشتری را مورد بررسی قرار دهید ومطالب را زودتر بهن روزرسانی کنید



دوست عزیزم، لطفا قبل از ارسال پیام به موارد زیر توجه داشته باشید:

1- تا حد ممکن از حروف فارسی برای نگارش پیام خود استفاده کنید. امکان ارسال پیام لاتین و کدهای برنامه‌نویسی با چیدمان چپ به راست نیز وجود دارد.
2- به درخواست پروژه‌های آماده و موارد مشابه پاسخ داده نخواهد شد.
3- از قرار دادن هرگونه نشانی یا شماره تماس در متن پیام خودداری کنید.
4- از ارسال پیام‌های تبلیغاتی خودداری کنید.
5- از ارسال سوال و پیام غیرمرتبط با مطلب ارائه شده خودداری کنید.
6- لطفا نظر خود را در مورد مطلب ارائه شده، با ثبت امتیاز مشخص نمایید.

پیشاپیش از همکاری شما سپاسگذارم.


نام:  
پست الکترونیک
وب‌سایت:
متن پیام: