الگوریتم تقسیم و حل

از ویکی‌پدیا، دانشنامهٔ آزاد
پرش به: ناوبری، جستجو

در علوم کامپیوتر, الگوریتم تقسیم و حل (چیرگی) (Divide and conquer/D&C) الگو ی طراحی الگوریتم مهمی بر اساس بازگشت چندانشعابی می‌باشد. یک الگوریتم تقسیم و حل از طریق تفکیک یک مسئله به دو یا چند زیرمسئله از یک نوع (یا انواع وابسته به هم)، به صورت بازگشتی، کار می‌کند. این تفکیک تا زمانی ادامه می‌یابد که زیرمسئله‌های حاصله به میزان کافی ساده شده باشند تا بتوان آنها را مستقیماً حل کرد. جواب مسئلهٔ اصلی از ترکیب جواب‌های به دست آمده برای زیر مسئله‌ها به دست می‌آید.

این تکنیک مبنای الگوریتم‌های کارآمدی برای انواع مسئله‌ها می‌باشد، به عنوان مثال، مرتب‌سازی (مثلاً، مرتب‌سازی سریع و مرتب‌سازی ادغامی), ضرب اعداد بزرگ (مثلاً، کاراتسوبا), تجزیه‌کننده (مثلاً، تحلیلگر بالا به پایین)، و محاسبهٔ تبدیل فوریه گسسته (تبدیل سریع فوریه).

از سوی دیگر، توانایی درک و طراحیِ الگوریتم‌های D&C هنری است که کسب مهارت در آن زمان زیادی می‌طلبد. به هنگام اثبات یک قضیه به کمک استقرا، غالباً نیازمند آنیم که به منظور دستیابی به یک روند بازگشتی، مسئلهٔ اصلی را با یک مسئلهٔ عمومی‌تر یا پیچیده‌تر جایگزین کنیم، و این در حالی است که روش سیستماتیکی برای یافتن تعمیم مناسب وجود ندارد.

گاهی اوقات نام «تقسیم و حل» در مورد الگوریتم‌هایی که هر مسئله را تنها به یک زیرمسئله تقلیل می‌دهند نیز به کار می‌رود، مانند الگوریتم جستجوی دودویی برای یافتن یک پرونده در یک لیست مرتب شده(و یا شبیه آن در الگوریتم‌های عددی و محاسباتی؛ الگوریتم دوبخشی برای یافتن ریشه) [۱]. با وجود این تعریف جامع، هر الگوریتمی که از بازگشت و یا حلقه استفاده می‌کند، از بعضی لحاظ می‌تواند به عنوان «الگوریتم تقسیم و حل» تلقی شود. از این رو، بعضی از مؤلفان درعوض از نام «کاهش و حل» استفاده می‌کنند.[۲]. این الگوریتم‌ها می‌توانند کارآمدتر از الگوریتم‌های تقسیم و حل معمولی، پیاده‌سازی شوند. به عنوان مثال، در صورت استفاده از بازگشت دنباله‌دار، این الگوریتم‌ها می‌توانند به حلقه‌های ساده تبدیل شوند.

معمولاً صحت یک الگوریتم تقسیم و حل، به کمک استقرای ریاضی، اثبات می‌شود، و هزینهٔ محاسباتی آن نیز معمولاً از طریق حل روابط بازگشتی تعیین می‌شود.

مثال‌های قدیمی[ویرایش]

جستجوی دودویی، الگوریتم تقسیم و حلی که در آن مسئلهٔ اصلی متوالیاً به زیرمسئله‌هایی یکتا با اندازهٔ تقریبی نصف مسئلهٔ اصلی تفکیک می‌شود، بیشینهٔ دور و درازی دارد. ایدهٔ استفاده از یک لیست مرتب شده از عناصر به منظور سهولت بخشیدن در جستجو به ۲۰۰ سال پیش از میلاد ,[۳] در بابل باز می‌گردد، حال آن‌که یک توصیف واضح از الگوریتم در کامپیوترها اولین بار در سال ۱۹۴۶ در مقاله‌ای توسط جان مارچلی بیان شد.[۳] الگوریتم تقسیم و حلِ دیگر، با یک زیرمسئلهٔ منحصربه‌فرد، الگوریتم اقلیدس در محاسبهٔ بزرگ‌ترین مقسوم‌علیه مشترک دو عدد (از طریق کاهش اعداد به زیرمسئله‌های کوچک‌تر، و کوچک‌تر یا مساوی) می‌باشد، که به قرنها پیش از میلاد باز می‌گردد. یک مثال قدیمی از الگوریتم تقسیم و حل با زیرمسئله‌های چندگانه، توصیفی بود که گاوس در سال ۱۸۰۵ از چیزی که امروزه الگوریتم Cooley-Tukey fast Fourier transform یا FFT نامیده می‌شود,[۴] ارایه داد؛ اگرچه او از لحاظ کمّی، شمار عملیات این الگوریتم را تحلیل و بررسی نکرد، و FFTها شایع نشدند مگر یک قرن بعد که مجدداً کشف گردیدند.

یک الگوریتم تقسیم و حلِ دوزیرمسئله‌ایِ قدیمی که به طور ویژه برای کامپیوترها توسعه یافته، الگوریتم مرتب‌سازی ادغامی می‌باشد که توسط جان فون نویمن در سال ۱۹۵۴ ابداع گردید.[۵]

مثال قابل توجه دیگر، الگوریتمای است که توسط کاراتسوبا در سال۱۹۶۰ ابداع گردیده [۶] و می‌تواند دو عدد nرقمی را باO(n^{\log_2 3}) عمل ضرب کند. این الگوریتم، حدس اندری کولماگوراف 'که در سال 1956 بیان شد و \Omega(n^2) عمل را برای انجام ضرب مذکور لازم می‌دانست را رد کرد. به عنوان مثال دیگری از یک الگوریتم تقسیم و حل که در ابتدا کامپیوترها را شامل نمی‌شد، «ناث» متدی را ارائه داد که به طور نمونه در یک دفتر پست به منظور آدرس‌دهی نامه‌ها استفاده می‌شود: نامه‌ها در کیف‌های جداگانه برای مناطق مختلف جغرافیایی مرتب می‌شوند، در هر کدام از این کیف‌ها نیز، نامه‌ها در دسته‌هایی مربوط به نواحی کوچک‌تر مرتب شده‌اند، و به همین ترتیب، تا زمانی که نامه‌ها به مقصد برسند. [۳] این الگوریتم به یک مرتب‌سازی رقمی، وابسته‌است، که در سال ۱۹۲۹ برای ماشین‌های مرتب‌سازی کارت پانچ ارایه شد.[۳]

مزایا[ویرایش]

حل مسائل دشوار[ویرایش]

تقسیم و حل ابزاری است قدرتمند برای حل مسائل دشوار مفهومی، همانند معمای باستانی برج هانوی: همهٔ چیزی که حل این مسئله نیاز دارد، پیدا کردن راهی است برای شکستن مسئله به چند زیرمسئله، حل حالات جزیی و ترکیب زیرمسئله‌ها به مسئلهٔ اصلی.

کارآیی الگوریتم[ویرایش]

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

در تمام این مثال‌ها، راهبردِ D&C منجر به بهینه‌سازی هزینهٔ مجانبی راه حل می‌شود. به عنوان مثال، اگر حالت‌های پایه، اندازهٔ ثابت کران‌داری داشته‌باشند، عمل تفکیک مسئله و ترکیب جواب‌های جزیی به نسبت اندازهٔ مسئلهn، بوده، و یک تعداد محدود p از زیرمسئله‌ها با اندازهٔ n/p~ در هر مرحله وجود دارد، و آنگاه هزینهٔ الگوریتم تقسیم و حل( O(n log n خواهد بود.

تطابق[ویرایش]

الگوریتم‌های تقسیم و حل ذاتاً برای اجرا در ماشین‌های چندپردازنده‌ای سازگار شده‌اند، به ویژه سیستم‌های حافظه‌اشتراکی که ارتباط داده‌ها بین پردازنده‌ها به برنامه‌ریزی پیشرفته نیازی ندارد، چرا که زیرمسئله‌های متمایز قابل اجرا بر روی پردازنده‌های مختلف می‌باشند

دسترسی به حافظه[ویرایش]

الگوریتم‌های تقسیم و حل ذاتاً به کارآمد ساختن استفاده از حافظه‌های پنهانگرایش دارند. دلیل آن هم این است که، زمانی که زیرمسئله به اندازهٔ کافی کوچک باشد، آن زیر مسئله و تمام زیرمسئله‌های آن می‌توانند، به طور کلی، در داخل حافظهٔ پنهان حل شوند، بدون اینکه به حافظهٔ اصلی که کندتر می‌باشد دسترسی داشته باشند. الگوریتمی که به منظور بهره‌کشی این‌چنینی از حافظهٔ پنهان طراحی می‌شود، cache oblivious (بی‌توجه به حافظهٔ پنهان)، نامیده می‌شود، چرا که اندازهٔ حافظهٔ پنهان را به عنوان یک پارامتر آشکار، در بر ندارند.[۷]

علاوه بر این، الگوریتم‌های D&C می‌توانند برای الگوریتم‌های مهم بسیاری، همانند مرتب‌سازی، FFTها، و ضرب ماتریس‌ها، طراحی شوند، به طریقی مشابه، الگوریتم‌های بهینهٔ «بی‌توجه به حافظهٔ پنهان»، چنان که می‌توان اثبات کرد، به صورت بهینه و از دید مجانبی، صرف‌نظر از اندازهٔ حافظهٔ پنهان، از آن استفاده می‌کنند. در مقابل، راهبرد سنتیِ به‌کاربستن حافظهٔ پنهان، بلاک‌بندی می‌باشد، که در آن، مسئله صریحاً به قطعه‌هایی از اندازه‌های مقتضی تقسیم می‌شود—این الگوریتم هم‌چنین می‌تواند به طور بهینه از حافظهٔ پنهان استفاده کند، ولی فقط زمانی که الگوریتم برای اندازهٔ خاص حافظهٔ پنهان در یک ماشین ویژه مناسب‌سازی شده باشد.

مزیت مشابهی با درنظر گرفتن سیستم‌های حافظه‌ای سلسله‌مراتبی دیگر وجود دارد، همانند NUMA یا حافظهٔ مجازی، و نیز برای سطوح چندگانهٔ حافظهٔ پنهان: زمانی که یک زیرمسئله به اندازهٔ کافی کوچک باشد، می‌تواند، بدون دسترسی به سطوح بالاتر(آهسته‌تر)، در داخل سطح مفروض از سلسله‌مراتب حل شود.

انواع پیاده‌سازی[ویرایش]

بازگشتی[ویرایش]

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

حل یک نمونه سطح بالای مسئله با رفتن به جزء و بدست آوردن حل نمونه های کوچکتر حاصل می شود. هنگام پی ریزی یک الگوریتم بازگشتی ، باید:

1- راهی برای به دست آوردن حل یک نمونه از روی حل یک یا چند نمونه کوچک تر طراحی کنیم.

2- شرط(شرایط) نهایی نزدیک شدن به نمونه(های) کوچک تر را تعیین کنیم.

3-حل را در حالت شرط (شرایط)نهایی تعیین کنیم

بازگشتی اجازه بیان راه حل يک مسئله را به طور مختصر و مفيد می دهد. مسئله ای که به صورت بازگشتی حل می شود بايد بتواند به مسائل کوچک تر تقسيم بشود و حل مسائل کوچک به همان روش مسئله بزرگ قابل انجام باشد. مسئله کوچک تر به مسئله کوچک تری شکسته می شود تا سرانجام یه کوچک ترين اندازه مسئله برسد که base case ناميده می شود که می تواند بدون استفاده از بازگشتی حل شود.

يک مثال متعارف الگوريتم بازشگتی ضابطه تابع فاکتوريل f(n) است:

مقدار تابع برای f(3) به صورت زير محاسبه می شود:

* f(3) = 3 * f(3 − 1)
  • = 3 * f(2)
  • = 3 * 2 * f(2 − 1)
  • = 3 * 2 * f(1)
  • = 3 * 2 * 1 * f(1 − 1)
  • = 3 * 2 * 1 * f(0)
  • = 3 * 2 * 1 * 1
  • = 6

يک الگوريتم بازگشتی توسط تابع بازگشتی پياده سازی می شود. تابع بازگشتی (recursive function) تابعی است که خودش را فراخوانی می کند.

تابع بازگشتی مشابه توابع ديگر کار می کند. برای هر فراخوانی بازگشتی يک فريم جديد از تابع در پشته ايجاد می شود.

مثال(C). تابع بازگشتی محاسبه فاکتوريل يک عدد صحيح.

int Factorial (int x) {

 if (x<= 1)
   return 1;
   return x * Factorial (x-1);

}

همان تابع به صورت غير بازگشتی به صورت زير نوشته می شود. توجه کنيد که به د و متغير موقت نياز دارد.

int Factorial (int x) {

 int i, temp;
 for ( i=1; i<=x; i++) 
   temp*=i;
 return temp;

}

بازگشتی در مقايسه با غير بازگشتی[ویرایش]

برای اينکه بازگشتی موفق باشد مسئله نياز است يک زيرساختار بازگشتی داشته باشد. راه حل بعضی از مسائل به طور ذاتی بازگشتی است چون احتياج به نگداری حالت قبلی دارند. الگوريتم پيمايش درخت(tree traversal)، تابع اکرمن(Ackermann) و الگوريتم های تقسيم و غلبه مانند مرتب سازی سريع(Quicksort) همگی به صورت بازگشتی هستند. همه اين الگوريتم ها می توانند به صورت غيربازگشتی با کمک پشته هم پياده شوند اما نياز به پشته مزيت راه حل غير بازگشتی را از بين می برد.

تابع غير بازگشتی احتمالاً در عمل کمی سريعتر از نسخه بازگشتی آن اجرا می شود چون تابع غير بازگشتی سربار فراخوانی تابع (function-call) را به اندازه تابع بازگشتی ندارد و اين سربار در بعضی زبان ها نسبتاً بالا است.

يک دليل ديگر برای ترجيح غيربازگشتی به بازگشتی اين است که فضای پشته قابل دسترس کمتر از فضای قابل دسترس در حافظه آزاد heap است. و الگوريتم های بازگشتی تمايل به فضای پشته بيشتری نسبت به غير بازگشتی دارند.

مرتب سازی ادغامی[ویرایش]

ادغام یک فرایند مرتبط با مرتب سازی است.

ادغام دوطرفه به معنای ترکیب دو آرایه مرتب شده در یک آرایه ی مرتب است.

مرتب سازی ادغامی شامل مراحل زیر می شود:

1- تقسیم آرایه به دو زیر آرایه، هر یک با n/2 عنصر.

2- حل هر زیر آرایه با مرتب سازی آن.

3- ترکیب حل های زیر آرایه ها از طریق ادغام آن ها در یک آرایه مرتب.

پشته کردن صریح[ویرایش]

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

اندازهٔ پشته[ویرایش]

در پیاده‌سازی‌های بازگشتیِ الگوریتم‌های D&C، باید از وجود حافظهٔ تخصیص داده‌شدهٔ مورد نیاز برای پشتهٔ بازگشت اطمینان حاصل شود، درغیراین‌صورت ممکن است به دلیل سرریز پشته.، اجرا با شکست مواجه شود. خوشبختانه، الگوریتم‌های D&Cای که از لحاظ زمانی کارآمد هستند، اغلب، تا حدودی بازگشتی هستند. به عنوان مثال، الگوریتم مرتب‌سازی سریع می‌تواند طوری پیاده‌سازی شود که هرگز به بیشتر از \log_2 n فراخوانی بازگشتی تودرتو برای مرتب کردن n عنصر نیاز نداشته‌باشد.

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

انتخاب حالات پایه[ویرایش]

در هر الگوریتم بازگشتی، آزادی قابل توجهی در انتخاب حالات پایه , (زیرمسئله‌های کوچکی که به منظور پایان دادن به بازگشت، مسیقیماً حل می‌شوند) وجود دارد.

انتخاب کوچک‌ترین یا آسان‌ترین حالت پایهٔ ممکن، مطبوع‌تر است و معمولاً منجر به برنامه‌های آسان‌تر می‌شود، چرا که حالات کمتری برای رسیدگی وجود دارند که حلشان هم ساده‌تر است. به عنوان مثال، یک الگوریتم FFT زمانی می‌تواند به بازگشت پایان دهد که ورودی یک نمونهٔ یکتا باشد، و الگورتیم مرتب‌سازی لیستِ «مرتب‌سازی سریع» زمانی پایان می‌یابد که ورودی، لیست خالی باشد؛ در هر دو مثال تنها یک حالت پایه برای بررسی وجود دارد، که به هیچ پردازشی هم نیاز ندارد.

از سوی دیگر، غالباً، کارآیی، زمانی بهبود می‌یابد که بازگشت در حالات پایهٔ بزرگ مرتبط پایان یابد، که هرکدام از این حالات به صورت غیربازگشتی حل می‌شوند. این راهبرد، در مجموع، از فراخوانی‌های بازگشتی‌ای که کار اندکی انجام داده و یا اصلاً کاری انجام نمی‌دهند، اجتناب می‌ورزد، و هم‌چنین ممکن است استفاده از الگوریتم‌های غیربازگشتی خاصی که برای آن حالات پایه کارآمدتر از بازگشتِ صِرف می‌باشند را میسر سازد. از آن‌جایی که یک الگوریتم D&C، سرانجام، هر نمونه از مسئله یا زیرمسئله را به تعداد زیادی نمونهٔ پایه تقلیل می‌دهد، این نمونه‌های پایه هزینهٔ کلی الگوریتم را رقم می‌زنند، علی‌الخصوص زمانی که هزینهٔ کلیِ تقسیم و ترکیب پایین باشد. توجه داشته باشید که این ملاحظات به این‌که آیا بازگشت به واسطهٔ کامپایلر پیاده‌سازی شده‌است یا به کمک یک پشتهٔ صریح، بستگی ندارد.

بنابراین، به عنوان مثال، بسیاری از پیاده‌سازی‌های کتابخانه‌ایِ مرتب‌سازی سریع، تا زمانی که تعداد عناصری که قرار است مرتب شوند به اندازهٔ کافی کوچک شود، به یک الگوریتم مرتب‌سازی درجی سادهٔ مبتنی بر حلقه (یا چیزی شبیه آن) سوییچ می‌کنند. توجه شود که، اگر لیست خالی تنها حالت پایه بود، مرتب‌سازی یک لیست با n ورودی منجر به n+۱ فراخوانی مرتب‌سازی سریع خواهدشد که کاری انجام نداده و فوراً برمی‌گردند. افزایش حالات پایه به لیست‌هایی با اندازهٔ ۲ یا کم‌تر، بیشترِ این فراخوانی‌هایی که کاری انجام نمی‌دهند را حذف خواهد کرد، و به طور کلی به منظور تقلیل زمان مصرفی برای فراخوانی‌ها یا دستکاری‌های پشته، معمولاً از حالت پایه‌ای بزرگ‌تر از ۲ استفاده می‌شود.

هم‌چنین، می‌توان حالات پایهٔ بزرگی را به کار بست که کماکان از الگوریتم تقسیم و حل استتفاده کنند، اما پیاده‌سازی الگوریتم برای مجموعه‌های از پیش تعیین‌شده با اندازهٔ ثابت می‌تواند کاملاً به کدی بدون هیچ‌گونه بازگشت، حلقه و یا عبارات شرطی (بسته به روش ارزیابی جزئی) تبدیل شود. به عنوان مثال، این راهبرد در بعضی از پیاده‌سازی‌های کارآمد FFT که در آن‌ها حالات پایه، پیاده‌سازی‌های تبدیل‌شدهٔ الگوریتم‌های تقسیم و حل FFT برای یک مجموعه از اندازه‌های ثابت می‌باشند، مورد استفاده قرار گرفته‌است..[۸] تعداد زیادِ حالات پایهٔ جدا از همِ درخورِ پیاده‌سازیِ کارآمدِ این راهبرد، بعضی اوقات با روش‌های تولید کد منبع ایجاد می‌شوند.[۸]

به اشتراک گذاری زیرمسئله‌های تکراری[ویرایش]

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

منابع[ویرایش]

  1. Thomas H. Cormen, Charles E. Leiserson, and Ronald L. Rivest, Introduction to Algorithms (MIT Press, ۲۰۰۰).
  2. Anany V. Levitin, Introduction to the Design and Analysis of Algorithms (Addison Wesley, ۲۰۰۲).
  3. ۳٫۰ ۳٫۱ ۳٫۲ ۳٫۳ Donald E. Knuth, The Art of Computer Programming: Volume ۳, Sorting and Searching, second edition (Addison-Wesley, ۱۹۹۸).
  4. Heideman, M. T., D. H. Johnson, and C. S. Burrus, «Gauss and the history of the fast Fourier transform,» IEEE ASSP Magazine, ۱, (۴), ۱۴–۲۱ (۱۹۸۴)
  5. Knuth, ‎Donald. The Art of Computer Programming: Volume ۳ Sorting and Searching. 1998. 159. ISBN 0-201-89685-0. 
  6. A. Karatsuba and Yu. Ofman, Multiplication of Many-Digital Numbers by Automatic Computers. Doklady Akad. Nauk SSSR, Vol. ۱۴۵ (۱۹۶۲), pp. ۲۹۳–۲۹۴. Translation in Physics-Doklady, ۷ (۱۹۶۳), pp. ۵۹۵–۵۹۶.
  7. M. Frigo. Cache-oblivious algorithms. C. E. Leiserson, H. Prokop. . Proc. ۴۰th Symp. On the Foundations of Computer Science, 1999. 
  8. ۸٫۰ ۸٫۱ Frigo, M.. The design and implementation of FFTW۳. Johnson, S. G.. . Proceedings of the IEEE 93, no. 2 (February ‎2005): 216–231.  10٫1109/JPROC.2004٫840301]}}

پیوند به بیرون[ویرایش]