برزدن فیشر یتس

از testwiki
پرش به ناوبری پرش به جستجو

بر زدن فیشر یتس الگوریتمی برای ایجاد جایگشت تصادفی از یک دنباله است. الگو:سخ فرض کنید به ما آرایه‌ای داده شده‌است و می‌خواهیم جایگشتی تصادفی از اعضای آن آرایه به دست آوریم. این کار مانند بر زدن دسته‌ای ورق است و بر زدن آرایه به این معناست که هر کدام از جایگشت‌های ممکن، با احتمال مساوی بیایند و جایگشتی نااریب ایجاد شود. الگو:سخ نسخهٔ اولیه پیچیدگی زمانی O(n2) دارد اما نسخهٔ جدید این الگوریتم بهینه است و زمان اجرای آن ضریبی از تعداد عناصر و خطی می‌باشد.[۱] همچنین درجا اجرا می‌شود و نیاز به حافظهٔ اضافی ندارد.

روش اصلی بر زدن فیشر یتس

نسخهٔ اولیه بر زدن فیشر-یتس در سال ۱۹۳۸ توسط رونالد فیشر و فرنک یتس در کتاب جداول آماری برای تحقیقات زیستی، زراعتی، پزشکی[۲] منتشر شد. الگو:سخ این الگوریتم بسیار ساده است و برای استفادهٔ مستقیم انسان‌ها مناسب می‌باشد زیرا تنها به کاغذ و خودکار نیازمند است! اما به دلیل پیچیدگی زمانی بالا توسط کامپیوترها که با دنباله‌های بزرگ سر و کار دارند به کار گرفته نمی‌شود.

در این نسخه خاصیت تصادفی توسط جدولی از اعداد تصادفی ایجاد می‌شود. روش ایجاد جایگشت تصادفی اعداد ۱ تا n به شرح زیر است: الگو:سخ ۱- اعداد یک تا n را بنویسید. الگو:سخ ۲- عدد تصادفی k را بین یک و تعداد اعداد خط نخورده انتخاب کنید. (k می‌تواند یک و تعداد اعداد باقی‌مانده نیز باشد) الگو:سخ ۳- k امین عدد خط نخورده را پیدا کنید و انتهای لیستی دیگر بنویسید. سپس آن را خط بزنید. الگو:سخ ۴- مراحل ۲ و ۳ را تکرار کنید تا تمامی اعداد خط بخورند. الگو:سخ ۵- دنبالهٔ اعداد ایجاد شده در لیست، جایگشتی از دنبالهٔ اولیه است. الگو:سخ با فرض اینکه عدد تصادفی انتخاب شده در مرحلهٔ ۲ واقعاً تصادفی و نااریب باشد جایگشت ایجاد شده نیز دارای این خواص است. همچنین فیشر و یتس دربارهٔ چگونگی تولید عدد تصادفی در هر بازه‌ای توسط جداول از پیش مهیا شده توضیح دادند. این روش نااریب است.

مثال

فرض کنید می‌خواهیم جایگشتی از اعداد ۱ تا ۵ را به دست آوریم. آن‌ها را روی تکه کاغذی می‌نویسیم:

دامنه عدد تصادفی کاغذ لیست نهایی
۵ ۴ ۳ ۲ ۱

فرض کنید عدد تصادفی به دست آمده در مرحلهٔ دو ۳ باشد. با خط زدن ۳ و افزودن به لیست نهایی به نتیجهٔ زیر می‌رسیم:

دامنه عدد تصادفی کاغذ لیست نهایی
[۵ ،۱] ۳

۵ ۴ الگو:Font color ۲ ۱

۳

به همین ترتیب ادامه می‌دهیم تا تمامی اعداد خط بخورند.

دامنه عدد تصادفی کاغذ لیست نهایی
[۴ ،۱] ۱

۵ ۴ الگو:Font color ۲ الگو:Font color

۱ ۳
دامنه عدد تصادفی کاغذ لیست نهایی
[۳ ،۱] ۳

الگو:Font color ۴ الگو:Font color ۲ الگو:Font color

۵ ۱ ۳
دامنه عدد تصادفی کاغذ لیست نهایی
[۲ ،۱] ۱

الگو:Font color ۴ الگو:Font color الگو:Font color الگو:Font color

۲ ۵ ۱ ۳
دامنه عدد تصادفی کاغذ لیست نهایی
[۱ ،۱] ۱

الگو:Font color الگو:Font color الگو:Font color الگو:Font color الگو:Font color

۴ ۲ ۵ ۱ ۳

نسخهٔ جدید الگوریتم فیشر یتس

نسخهٔ جدید بر زدن فیشر یتس برای استفادهٔ کامپیوترها طراحی شده. این نسخه در سال ۱۹۶۴ توسط ریچارد داستنفلد معرفی شد[۳] و توسط دونالد کنوت در کتاب هنر برنامه‌نویسی رایانه با عنوان «الگوریتم پی»[۴] به شهرت رسید. به نظر می‌رسد آن‌ها از الگوریتم فیشر و یتس مطلع نبوده‌اند. الگو:سخ ایدهٔ نسخهٔ جدید مشابه نسخهٔ اصلی است و بر مبنای انتخاب تصادفی می‌باشد. اما تفاوت جزئی آن موجب کاهش چشم‌گیر زمان اجرا می‌شود. این الگوریتم با وجود سادگی نااریب است و از حافظهٔ اضافه استفاده نمی‌کند. الگو:سخ الگوریتم فشر یتس زمان غیرضروری‌ای را صرف پیدا کردن k امین عدد خط نخورده می‌کند (خط ۳). داستنفلد برای آن راه حلی ارائه کرد. در هر بار اجرای حلقهٔ دستورات عدد خط خورده را با جابه‌جا کردن آن با آخرین عدد خط نخورده به انتهای آرایه منتقل کنیم. این راه حل پیچیدگی زمانی بر زدن را از O(n2) به O(n) کاهش داد. الگو:سخ ۱- دنباله ایی به طول n از اعداد مورد نظر را در نظر بگیرید. الگو:سخ ۲- عددی تصادفی مانند m در بازهٔ [1,nk] انتخاب کنید. k تعداد اعدادی است که روی آن‌ها عملیات انجام شده؛ به عبارت دیگر تعداد حلقه‌های اجرا شده می‌باشد. الگو:سخ ۳- عنصر mام را با عنصر nkام جابه‌جا کنید. الگو:سخ ۴- مراحل ۲ و ۳ را n1 دفعه تکرار کنید. الگو:سخ ۵- دنبالهٔ شما به جایگشتی تصادفی از دنبالهٔ اولیه تبدیل شده‌است.

مثال

فرض کنید دنبالهٔ مورد نظر ۵عضوی باشد؛ مثلاً {A1,A2,A3,A4,A5}

دامنه عدد تصادفی دنباله پیش از تغییر دنباله پس از تغییر
[۵ ،۱] ۲ {A1,A2,A3,A4,A5} {A1,A5,A3,A4,A2}
دامنه عدد تصادفی دنباله پیش از تغییر دنباله پس از تغییر
[۴ ،۱] ۳ {A1,A5,A3,A4,A2} {A1,A5,A4,A3,A2}
دامنه عدد تصادفی دنباله پیش از تغییر دنباله پس از تغییر
[۳ ،۱] ۳ {A1,A5,A4,A3,A2} {A1,A5,A4,A3,A2}
دامنه عدد تصادفی دنباله پیش از تغییر دنباله پس از تغییر
[۲ ،۱] ۱ {A1,A5,A4,A3,A2} {A5,A1,A4,A3,A2}

نمونه کد

کد زیر به زبان پایتون نوشته شده:[۵] الگو:چپ‌چین

# Python Program to shuffle a given array
import random
# A function to generate a random permutation of arr[]
def randomize (arr, n):
 # Start from the last element and swap one by one. We don't
 # need to run for the first element that's why i > 0
 for i in range(n-1,0,-1):
 # Pick a random index from 0 to i
 j = random.randint(0,i+1)
 # Swap arr[i] with the element at random index
 arr[i],arr[j] = arr[j],arr[i]
 return arr
# Driver program to test above function.
arr = [1, 2, 3, 4, 5, 6, 7, 8]
n = len(arr)
print(randomize(arr, n))
# This code is contributed by Pratik Chhajer

الگو:پایان چپ‌چین خروجی کد: الگو:چپ‌چین

7 8 4 6 3 1 2 5

الگو:پایان چپ‌چین

برخی کاربردها

مولدهای اعداد تصادفی سخت‌افزاری

معمولاً بین بیت‌های اعداد تولیدشده توسط مولدهای اعداد تصادفی که به‌طور سخت‌افزاری پیاده‌سازی شده‌اند، همبستگی وجود دارد.[۶] الگو:سخ مهاجم‌ها با یافتن این بیت‌ها می‌توانند به ما آسیب بزنند. برزدن بیت‌های عدد تولید شده می‌تواند این مشکل را بر طرف کند زیرا هربار بیت‌های همبسته به مکان‌های متفاوتی می‌روند و مهاجم نمی‌تواند آن‌ها را شناسایی کند. البته بر زدن یکی از مشکلات عمدهٔ مولدهای اعداد تصادفی سخت‌افزاری که اریب بودن آنهاست را حل نمی‌کند. این مولدها بیت صفر را به احتمال ۰٫۵ تولید نمی‌کنند و با برزدن تعداد صفر و یک‌ها تغییر نمی‌کند و مولد همچنان اریب باقی می‌ماند.

مرتب‌سازی ساختگی

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

تولید عدد تصادفی در بازهٔ دلخواه

فرض کنید مولد اعداد تصادفی، اعداد صحیح در بازهٔ [۱۰ ،۱] تولید کند. استفاده از روش باقی‌مانده برای به دست آوردن اعداد صحیح تصادفی در بازهٔ [۴ ،۱] مناسب نمی‌باشد زیرا احتمال آمدن این اعداد یکسان نیست.

علاوه بر توجه به الگوریتم فیشر یتس باید به الگوریتم به کارگرفته‌شده برای تولید عدد تصادفی در مرحلهٔ دو نیز توجه کنیم. اریب بودن الگوریتم مذکور موجب اریب شدن جایگشت نهایی می‌شود. معمولاً مولدهای اعداد تصادفی، اعدادی در بازهٔ [ Max , ۰] تولید می‌کنند. یکی از روش‌های معمول برای پیدا کردن عدد تصادفی در بازهٔ [ k , ۱] استفاده از روش باقی‌مانده می‌باشد. ( k می‌تواند تعداد اعداد خط نخورده در روش اصلی فیشر یتس یا تعداد حلقه‌های باقی‌مانده در نسخه جدید باشد) این روش در حالت کلی مناسب نمی‌باشد و نتیجهٔ نهایی ما را اریب می‌کند. الگو:سخ فرض کنید مولد، عدد تصادفی صحیح r را در بازهٔ [ Max , ۰] تولید کند. روش باقی‌مانده 1+(r%k) را به عنوان عدد تصادفی در بازهٔ [ k , ۱] خروجی می‌دهد. ( r%k باقی‌ماندهٔ تقسیم r بر k می‌باشد) الگو:سخ به‌طور مثال فرض کنید مولد، عددی در بازهٔ [۹۹ , ۰] تولید کند و ما عددی در بازهٔ [۱۵ , ۱] بخواهیم. اگر اعداد صحیح بازهٔ [۹۹ , ۰] را بر ۱۵ تقسیم و باقی‌مانده را با یک جمع کنیم، اعداد یک تا ده، ۷ مرتبه و سایر اعداد ۶ مرتبه ظاهر می‌شوند؛ زیرا ۱۰۰ بر ۱۵ بخش‌پذیر نیست. پس توزیع اعداد تصادفی تولید شده در بازهٔ [۱۵ , ۱] یکنواخت نیست و اریب می‌باشد.

لینک‌های مرتبط

الگو:Div col

الگو:Div col end

منابع

الگو:پانویس