المپدیا

دانش‌نامه‌ی المپیاد کامپیوتر ایران

ابزار کاربر

ابزار سایت


آموزش:الگوریتم:دنباله‌ی گری

-

دنباله گری

دنباله گری یک سیستم عددی باینری است که در آن، هر دو عدد متوالی تنها در یک بیت اختلاف دارند. هدف از ابداع این دنباله یا به اصطلاح کد، استفاده از آن در وسایلی بود که با کلید های دو حالته کار می‌کردند.
فرض کنید دستگاهی داریم که با توجه به وضعیت سه کلید خروجی آن با یکی از هشت دستگاه موجود دیگر، ارتباط برقرار می‌کند. حال وضعیتی را در نظر بگیرید که نیاز است تا ارتباط به دستگاه شماره 001 قطع شود و ارتباط با دستگاه 110 برقرار گردد.برای این کار باید کلید های روی دستگاه تغییر وضعیت بدهند. مشخص است که تغییر وضعیت این کلید‌های مکانیکی به صورت همزمان رخ نمی‌دهد و در این بین ممکن است با دستگاه‌های دیگری ارتباط برقرار کند.
برای مثال فرض کنید در طی این تغییر، دنباله‌ی زیر به‌وجود آید.
001 –> 000 –> 010 –> 110
هر چند که زمان ماندن در وضعیت‌های میانی بسیار کم است، اما همین زمان ناچیز هم می‌تواند مشکلات جدی، بوجود آورد.

الگوریتم ساخت دنباله

یک الگوریتم بازگشتی بسیار ساده برای ساخت دنباله گری وجود دارد، که به شرح زیر است :
فرض کنید دنباله‌ی گری n-1 بیتی داریم و می‌خواهیم از روی آن دنباله‌ی n بیتی بسازیم. ابتدا دنباله‌ی n-1 بیتی را زیر هم قرار می‌دهیم و علاوه بر آن، دنباله به صورت عمودی آینه می‌کنیم. پس از آن در انتهای هر عدد باینری نیمه بالایی بیت 0 و در انتهای اعداد نیمه‌ پایینی بیت 1 قرار می‌دهیم. با یک مثال این روش روشن می‌شود.

00          00,0 --> 000
10          10,0 --> 100
11          11,0 --> 110
01          01,0 --> 010
     --->  ------
            01,1 --> 011
            11,1 --> 111
            10,1 --> 101
            00.1 --> 001

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

فرض کنید می‌خواهیم k امین عدد در دنباله n بیتی گری را بیابیم. تابع زیر این عمل را پیاده‌سازی می‌کند.

unsigned int gray (int n,int k) {
    if (n == 1 && k > 1)
        return -1;
    else if (n == 1 && k < 2)
        return k;
    else {
       if ( k < pow(2 , n-1) )
           return gray(n-1 , k)*2;
       else
           return gray(n-1 , pow(2,n)-1-k)*2+1;
    }
}

حالت پایه کد بالا همان دو شرط اولیه است. اگر n=1 که دو حالت بیشتر نداریم، یا k=0 و یا k=1 که در هرکدام ازین حالات مقدار تابع گری برابر k است. اگر n > 1 باشد آنگاه دو حالت پیش می‌آید :
حالت اول :‌ (k < 2^(n-1 که در این حالت خروجی تابع گری همان خروجی تابع گری به ازای n-1 است، با این تفاوت، که در انتهای آن یک بیت 0 اضافه شده است، که معادل با ضرب کردن در 2 است.
حالت دوم : (k >= 2^(n-1 که در این حالت باید معادل این عدد در رشته‌ی n-1 بیتی بیابیم و به انتهای آن یک بیت 1 اضافه کنیم(ضرب کردن در 2 و جمع کردن با 1)
مشخص است که این الگوریتم از (O(n است.

پیاده‌سازی دیگر

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

/*
        The purpose of this function is to convert an unsigned
        binary number to binary Gray code.
 
        The operator >> is shift right. The operator ^ is exclusive or.
*/
unsigned int binaryToGray(unsigned int num)
{
        return (num >> 1) ^ num;
}
 
/*
        The purpose of this function is to convert a binary
        Gray code number to a binary number.
*/
unsigned int grayToBinary(unsigned int num)
{
    unsigned int mask;
    for (mask = num >> 1; mask != 0; mask = mask >> 1)
    {
        num = num ^ mask;
    }
    return num;
}

ابزار صفحه