<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x645;&#x642;&#x627;&#x644;&#x627;&#x62A; &#x628;&#x631;&#x645;&#x62C;&#x629; &#x645;&#x62A;&#x642;&#x62F;&#x645;&#x629;</title><link>https://academy.hsoub.com/programming/advanced/page/2/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x645;&#x642;&#x627;&#x644;&#x627;&#x62A; &#x628;&#x631;&#x645;&#x62C;&#x629; &#x645;&#x62A;&#x642;&#x62F;&#x645;&#x629;</description><language>ar</language><item><title>&#x627;&#x644;&#x628;&#x62D;&#x62B; &#x627;&#x644;&#x62B;&#x646;&#x627;&#x626;&#x64A; Boolean search &#x648;&#x62F;&#x645;&#x62C; &#x646;&#x62A;&#x627;&#x626;&#x62C; &#x627;&#x644;&#x628;&#x62D;&#x62B; &#x648;&#x62A;&#x631;&#x62A;&#x64A;&#x628;&#x647;&#x627;</title><link>https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D8%A7%D9%84%D8%AB%D9%86%D8%A7%D8%A6%D9%8A-boolean-search-%D9%88%D8%AF%D9%85%D8%AC-%D9%86%D8%AA%D8%A7%D8%A6%D8%AC-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D9%88%D8%AA%D8%B1%D8%AA%D9%8A%D8%A8%D9%87%D8%A7-r1455/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_01/61f7b4f447e70_-------.png.9e20a88613727a4ec582268b82b4cead.png" /></p>

<p>
	سنشرح في هذه المقالة حل التمرين التالي من المقالة السابقة <a href="https://academy.hsoub.com/devops/servers/databases/redis/%D9%81%D9%87%D8%B1%D8%B3%D8%A9-%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D9%88%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84%D9%87%D8%A7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-redis-r580/" rel="">فهرسة الصفحات وتحليل زمن تشغيلها</a>، ثم ننفّذ شيفرة تدمج مجموعةً من نتائج البحث وترتِّبها بحسب مدى ارتباطها بكلمات البحث.
</p>

<h2>
	الزاحف crawler
</h2>

<p>
	لنمرّ أولًا على حل تمرين المقالة المشار إليها. كنا قد وفَّرنا الشيفرة المبدئية للصنف <code>WikiCrawler</code> وكان المطلوب منك هو إكمال التابع <code>crawl</code>. انظر الحقول المُعرَّفة في ذلك الصنف:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4849_15" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">WikiCrawler</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="com">// يشير إلى المكان الذي بدأنا منه</span><span class="pln">
    </span><span class="kwd">private</span><span class="pln"> final </span><span class="typ">String</span><span class="pln"> source</span><span class="pun">;</span><span class="pln">

    </span><span class="com">// المفهرِس الذي سنخزن فيه النتائج</span><span class="pln">
    </span><span class="kwd">private</span><span class="pln"> </span><span class="typ">JedisIndex</span><span class="pln"> index</span><span class="pun">;</span><span class="pln">

    </span><span class="com">// رتل محددات الموارد الموحدة المطلوب فهرستها</span><span class="pln">
    </span><span class="kwd">private</span><span class="pln"> </span><span class="typ">Queue</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">&gt;</span><span class="pln"> queue </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">LinkedList</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">&gt;();</span><span class="pln">

    </span><span class="com">// يُستخدَم لقراءة الصفحات من موقع ويكيبيديا</span><span class="pln">
    final </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">WikiFetcher</span><span class="pln"> wf </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">WikiFetcher</span><span class="pun">();</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	عندما نُنشِئ كائنًا من النوع <code>WikiCrawler</code>، علينا أن نُمرِّر قيمتي <code>source</code> و <code>index</code>. يحتوي المتغير <code>queue</code> مبدئيًا على عنصر واحد فقط هو <code>source</code>.
</p>

<p>
	لاحِظ أن <a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D9%85%D9%83%D8%AF%D8%B3-stack-%D9%88%D8%A7%D9%84%D8%B1%D8%AA%D9%84-queue-%D9%88%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AC%D8%B1%D8%AF%D8%A9-adt-r1396/" rel="">الرتل queue</a> مُنفَّذ باستخدام قائمةٍ من النوع <code>LinkedList</code>، وبالتالي، تستغرق عملية إضافة العناصر إلى نهايته -وحذفها من بدايته- زمنًا ثابتًا، ولأننا أسندنا قائمةً من النوع <code>LinkedList</code> إلى متغير من النوع <code>Queue</code>، أصبح استخدامنا له مقتصرًا على التوابع المُعرَّفة بالواجهة <code>Queue</code>، أي سنَستخدِم التابع <code>offer</code> لإضافة العناصر و <code>poll</code> لحذفها منه.
</p>

<p>
	انظر تنفيذنا للتابع <code>WikiCrawler.crawl</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_4849_13" style="">
<span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> crawl</span><span class="pun">(</span><span class="pln">boolean testing</span><span class="pun">)</span><span class="pln"> throws </span><span class="typ">IOException</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">queue</span><span class="pun">.</span><span class="pln">isEmpty</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="typ">String</span><span class="pln"> url </span><span class="pun">=</span><span class="pln"> queue</span><span class="pun">.</span><span class="pln">poll</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Crawling "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> url</span><span class="pun">);</span><span class="pln">

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">testing</span><span class="pun">==</span><span class="kwd">false</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> index</span><span class="pun">.</span><span class="pln">isIndexed</span><span class="pun">(</span><span class="pln">url</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Already indexed."</span><span class="pun">);</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">null</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="typ">Elements</span><span class="pln"> paragraphs</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">testing</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            paragraphs </span><span class="pun">=</span><span class="pln"> wf</span><span class="pun">.</span><span class="pln">readWikipedia</span><span class="pun">(</span><span class="pln">url</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            paragraphs </span><span class="pun">=</span><span class="pln"> wf</span><span class="pun">.</span><span class="pln">fetchWikipedia</span><span class="pun">(</span><span class="pln">url</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        index</span><span class="pun">.</span><span class="pln">indexPage</span><span class="pun">(</span><span class="pln">url</span><span class="pun">,</span><span class="pln"> paragraphs</span><span class="pun">);</span><span class="pln">
        queueInternalLinks</span><span class="pun">(</span><span class="pln">paragraphs</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> url</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	السبب وراء التعقيد الموجود في التابع السابق هو تسهيل عملية اختباره. تُوضِّح النقاط التالية المنطق المبني عليه التابع:
</p>

<ul>
<li>
		إذا كان الرتل فارغًا، يعيد التابع القيمة الفارغة <code>null</code> لكي يشير إلى أنه لم يُفهرِس أي صفحة.
	</li>
	<li>
		إذا لم يكن فارغًا، فإنه يقرأ محدد الموارد الموحد URL التالي ويَحذِفه من الرتل.
	</li>
	<li>
		إذا كان محدد الموارد قيد الاختيار مُفهرَسًا بالفعل، لا يُفهرِّسه التابع مرة أخرى إلا إذا كان في وضع الاختبار.
	</li>
	<li>
		يقرأ التابع بعد ذلك محتويات الصفحة: إذا كان التابع في وضع الاختبار، فإنه يقرؤها من ملف، وإن لم يكن كذلك، فإنه يقرؤها من شبكة الإنترنت.
	</li>
	<li>
		يُفهرِس الصفحة.
	</li>
	<li>
		يُحلِّل الصفحة ويضيف الروابط الداخلية الموجودة فيها إلى الرتل.
	</li>
	<li>
		يعيد في النهاية مُحدّد موارد الصفحة التي فهرَسها للتو.
	</li>
</ul>
<p>
	كنا قد عرضنا تنفيذًا للتابع <code>Index.indexPage</code> في نفس المقالة المشار إليها في الأعلى، أي أن التابع الوحيد الجديد هو <code>WikiCrawler.queueInternalLinks</code>.
</p>

<p>
	كتبنا نسختين من ذلك التابع بمعاملات parameters مختلفة: تَستقبِل الأولى كائنًا من النوع <code>Elements</code> يتضمَّن <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">شجرة DOM</a> واحدةً لكل فقرة، بينما تَستقبِل الثانية كائنًا من النوع <code>Element</code> يُمثِل فقرة واحدة.
</p>

<p>
	تمرّ النسخة الأولى عبر الفقرات، في حين تُنفِّذ النسخة الثانية العمل الفعلي.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4849_23" style="">
<span class="pln">    </span><span class="kwd">void</span><span class="pln"> queueInternalLinks</span><span class="pun">(</span><span class="typ">Elements</span><span class="pln"> paragraphs</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Element</span><span class="pln"> paragraph</span><span class="pun">:</span><span class="pln"> paragraphs</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            queueInternalLinks</span><span class="pun">(</span><span class="pln">paragraph</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> queueInternalLinks</span><span class="pun">(</span><span class="typ">Element</span><span class="pln"> paragraph</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Elements</span><span class="pln"> elts </span><span class="pun">=</span><span class="pln"> paragraph</span><span class="pun">.</span><span class="pln">select</span><span class="pun">(</span><span class="str">"a[href]"</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Element</span><span class="pln"> elt</span><span class="pun">:</span><span class="pln"> elts</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">String</span><span class="pln"> relURL </span><span class="pun">=</span><span class="pln"> elt</span><span class="pun">.</span><span class="pln">attr</span><span class="pun">(</span><span class="str">"href"</span><span class="pun">);</span><span class="pln">

            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">relURL</span><span class="pun">.</span><span class="pln">startsWith</span><span class="pun">(</span><span class="str">"/wiki/"</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">String</span><span class="pln"> absURL </span><span class="pun">=</span><span class="pln"> elt</span><span class="pun">.</span><span class="pln">attr</span><span class="pun">(</span><span class="str">"abs:href"</span><span class="pun">);</span><span class="pln">
                </span><span class="typ">queue</span><span class="pun">.</span><span class="pln">offer</span><span class="pun">(</span><span class="pln">absURL</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	لكي نُحدِّد ما إذا كان مُحدّد موارد موحد معين هو مُحدّد داخلي، فإننا نفحص ما إذا كان يبدأ بكلمة "/wiki/". قد يتضمَّن ذلك بعض الصفحات التي لا نرغب في فهرستها مثل بعض الصفحات الوصفية لموقع ويكيبيديا، كما قد يستثني ذلك بعض الصفحات التي نريدها مثل روابط الصفحات المكتوبة بلغات أخرى غير الإنجليزية، ومع ذلك، تُعدّ تلك الطريقة جيدة بالقدر الكافي كبداية.
</p>

<p>
	لا يتضمَّن هذا التمرين الكثير، فهو فرصة فقط لتجميع الأجزاء الصغيرة معًا.
</p>

<h2>
	استرجاع البيانات
</h2>

<p>
	سننتقل الآن إلى المرحلة التالية من المشروع، وهي تنفيذ أداة بحث تتكوّن مما يلي:
</p>

<ol>
<li>
		واجهة تُمكِّن المُستخدمين من إدخال كلمات البحث ومشاهدة النتائج.
	</li>
	<li>
		طريقة لاستقبال كلمات البحث وإعادة الصفحات التي تتضمَّنها.
	</li>
	<li>
		طريقة لدمج نتائج البحث العائدة من عدة كلمات بحث.
	</li>
	<li>
		خوارزمية تُصنِّف نتائج البحث وتُرتِّبها.
	</li>
</ol>
<p>
	يُطلَق على تلك العمليات وما يشابهها اسم <a href="https://ar.wikipedia.org/wiki/%D8%A7%D8%B3%D8%AA%D8%B1%D8%AC%D8%A7%D8%B9_%D8%A7%D9%84%D9%85%D8%B9%D9%84%D9%88%D9%85%D8%A7%D8%AA" rel="external nofollow">استرجاع المعلومات</a> Information retrieval.
</p>

<p>
	أنشأنا بالفعل نسخةً بسيطةً من الخطوة رقم 2، وسنُركِّز في هذا التمرين على الخطوتين 3 و 4. قد ترغب بالعمل أيضًا على الخطوة رقم 1 إذا كنت مهتمًا ببناء تطبيقات الويب.
</p>

<h2>
	البحث المنطقي/الثنائي Boolean search
</h2>

<p>
	تستطيع معظم محركات البحث أن تُنفِّذ بحثًا منطقيًا، بمعنى أن بإمكانها دمج نتائج البحث الخاصة بعدة كلمات باستخدام المنطق الثنائي، ولنأخذ أمثلةً على ذلك:
</p>

<ul>
<li>
		تعيد عملية البحث عن "java AND programming" الصفحات التي تحتوي على الكلمتين "java" و "programming" فقط.
	</li>
	<li>
		تعيد عملية البحث عن "java OR programming" الصفحات التي تحتوي على إحدى الكلمتين وليس بالضرورة كلتيهما.
	</li>
	<li>
		تعيد عملية البحث عن "java -indonesia" الصفحات التي تحتوي على كلمة "java" ولا تحتوي على كلمة "indonesia".
	</li>
</ul>
<p>
	يُطلَق على تلك التعبيرات، أي تلك التي تحتوي على كلمات بحث وعمليات، اسم "استعلامات queries".
</p>

<p>
	عندما تُطبَّق تلك العمليات على نتائج البحث، فإن الكلمات "AND" و "OR" و "-" تقابل في الرياضياتِ عمليات "التقاطع" و "الاتحاد" و "الفرق" على الترتيب. لنفترض مثلًا أن:
</p>

<ul>
<li>
		<code>s1</code> يمثل مجموعة الصفحات التي تحتوي على كلمة "java"،
	</li>
	<li>
		<code>s2</code> يمثل مجموعة الصفحات التي تحتوي على كلمة "programming"،
	</li>
	<li>
		<code>s3</code> يمثل مجموعة الصفحات التي تحتوي على كلمة "indonesia"،
	</li>
</ul>
<p>
	في تلك الحالة:
</p>

<ul>
<li>
		يُمثِل التقاطع بين <code>s1</code> و <code>s2</code> مجموعة الصفحات التي تحتوي على الكلمتين "java" و "programming" معًا.
	</li>
	<li>
		يُمثِل الاتحاد بين <code>s1</code> و <code>s2</code> مجموعة الصفحات التي تحتوي على كلمة "java" أو كلمة "programming".
	</li>
	<li>
		يُمثِل الفرق بين <code>s1</code> و <code>s3</code> مجموعة الصفحات التي تحتوي على كلمة "java" ولا تحتوي على كلمة "indonesia".
	</li>
</ul>
<p>
	ستكتب في القسم التالي تابعًا يُنفِّذ تلك العمليات.
</p>

<h2>
	تمرين 13
</h2>

<p>
	ستجد ملفات شيفرة هذا التمرين في <a href="https://github.com/AllenDowney/ThinkDataStructures" rel="external nofollow">مستودع الكتاب</a>:
</p>

<ul>
<li>
		<a href="https://github.com/AllenDowney/ThinkDataStructures/blob/cc10971a1904eda5f5b818a3d70ee1a836fd8799/solutions/src/com/allendowney/thinkdast/WikiSearch.java" rel="external nofollow">WikiSearch.java</a>: يُعرِّف كائنًا يحتوي على نتائج البحث ويُطبِّق العمليات عليها.
	</li>
	<li>
		<a href="https://github.com/AllenDowney/ThinkDataStructures/blob/cc10971a1904eda5f5b818a3d70ee1a836fd8799/solutions/src/com/allendowney/thinkdast/WikiSearchTest.java" rel="external nofollow">WikiSearchTest.java</a>: يحتوي على شيفرة اختبار للصنف<code>WikiSearch</code>.
	</li>
	<li>
		<a href="https://github.com/AllenDowney/ThinkDataStructures/blob/cc10971a1904eda5f5b818a3d70ee1a836fd8799/solutions/src/com/allendowney/thinkdast/Card.java" rel="external nofollow">Card.java</a>: يُوضِّح طريقة استخدام التابع <code>sort</code> المُعرَّف بالنوع <code>java.util.Collections</code>.
	</li>
</ul>
<p>
	ستجد أيضًا بعض الأصناف المساعدة التي استخدَمناها من قبل في <a href="https://academy.hsoub.com/tags/%D9%87%D9%8A%D8%A7%D9%83%D9%84%20%D8%A7%D9%84%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA%20101/" rel="">هذه السلسلة</a>.
</p>

<p>
	انظر بداية تعريف الصنف <code>WikiSearch</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4849_26" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">WikiSearch</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">// يربط مُحدّدات الموارد التي تحتوي على الكلمة بدرجة الارتباط</span><span class="pln">
    </span><span class="kwd">private</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Integer</span><span class="pun">&gt;</span><span class="pln"> </span><span class="typ">map</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">WikiSearch</span><span class="pun">(</span><span class="typ">Map</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Integer</span><span class="pun">&gt;</span><span class="pln"> </span><span class="typ">map</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="typ">map</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Integer</span><span class="pln"> getRelevance</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> url</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Integer</span><span class="pln"> relevance </span><span class="pun">=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">url</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> relevance</span><span class="pun">==</span><span class="pln">null </span><span class="pun">?</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln"> relevance</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يحتوي كائن النوع <code>WikiSearch</code> على <a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-maps-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1430/" rel="">خريطة map</a> تربط مُحدّدات الموارد الموحدة URLs بدرجة الارتباط relevance score، والتي تُمثِل -ضمن سياق استرجاع البيانات- عددًا يشير إلى المدى الذي يستوفي به مُحدِّد الموارد الاستعلام الذي يدخله المُستخدِم. تتوفّر الكثير من الطرائق لحساب درجة الارتباط، ولكنها تعتمد في الغالب على "تردد الكلمة" أي عدد مرات ظهورها في الصفحة. يُعدّ TF-IDF واحدًا من أكثر درجات الارتباط شيوعًا، وتُمثِل الأحرف اختصارًا لعبارة <a href="https://ar.wikipedia.org/wiki/%D8%AA%D9%8A_%D8%A7%D9%81-%D8%A7%D9%8A_%D8%AF%D9%8A_%D8%AF%D9%81" rel="external nofollow">تردد المصطلح term frequency - معكوس تردد المستند inverse document frequency</a>.
</p>

<ul>
<li>
		إذا احتوى الاستعلام على كلمة بحث واحدة، فإن درجة الارتباط لصفحة معينة تساوي تردّد الكلمة، أي عدد مرات ظهورها في تلك الصفحة.
	</li>
	<li>
		بالنسبة للاستعلامات التي تحتوي على عدة كلمات، تكون درجة الارتباط لصفحة معينة هي حاصل مجموع تردد الكلمات، أي عدد مرات ظهور أي كلمة منها.
	</li>
</ul>
<p>
	والآن وقد أصبحت مستعدًا لبدء التمرين، نفِّذ الأمر <code>ant build</code> لتصريف ملفات الشيفرة، ثم نفِّذ الأمر <code>ant WikiSearchTest</code>. ستفشل الاختبارات كالعادة لأن ما يزال عليك إكمال بعض العمل.
</p>

<p>
	أكمل متن كلٍّ من التوابع <code>and</code> و <code>or</code> و <code>minus</code> في الملف <a href="https://github.com/AllenDowney/ThinkDataStructures/blob/cc10971a1904eda5f5b818a3d70ee1a836fd8799/solutions/src/com/allendowney/thinkdast/WikiSearch.java" rel="external nofollow">WikiSearch.java</a> لكي تتمكّن من اجتياز الاختبارات المرتبطة بتلك التوابع. لا تقلق بشأن التابع <code>testSort</code>، فسنعود إليه لاحقًا.
</p>

<p>
	يُمكِنك أن تُنفِّذ <code>WikiSearchTest</code> بدون اِستخدَام Jedis لأنه لا يعتمد على فهرس قاعدة بيانات Redis الخاصة بك، ولكن، إذا أردت أن تَستخِدم الفهرس للاستعلام query، فلا بُدّ أن توفِّر بيانات الخادم في ملف، كما أوضحنا في مقالة "استخدام قاعدة بيانات Redis لتحقيق استمرارية البيانات".
</p>

<p>
	نفِّذ الأمر <code>ant JedisMaker</code> لكي تتأكّد من قدرته على الاتصال بخادم Redis، ثم نفِّذ <code>WikiSearch</code> الذي يَطبَع نتائج الاستعلامات الثلاثة التالية:
</p>

<ul>
<li>
		"java"
	</li>
	<li>
		"programming"
	</li>
	<li>
		"java AND programming"
	</li>
</ul>
<p>
	لن تكون النتائج مُرتَّبة في البداية لأن التابع <code>WikiSearch.sort</code> ما يزال غير مكتمل.
</p>

<p>
	أكمل متن التابع <code>sort</code> لكي تُصبِح النتائج مُرتَّبة تصاعديًا بحسب درجة الارتباط. يُمكِنك الاستعانة بالتابع <code>sort</code> المُعرَّف بالنوع <code>java.util.Collections</code> حيث يُمكِنه ترتيب أي نوع قائمة <code>List</code>. يُمِكنك الاطلاع على <a href="https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html" rel="external nofollow">توثيق النوع List</a>.
</p>

<p>
	تتوفَّر نسختان من التابع <code>sort</code>:
</p>

<ul>
<li>
		نسخة أحادية المعامل تَستقبِل قائمةً وتُرتِّب عناصرها باستخدام التابع <code>compareTo</code>، ولذلك ينبغي أن تكون العناصر من النوع <code>Comparable</code>.
	</li>
	<li>
		نسخة ثنائية المعامل تَستقبِل قائمةً من أي نوع وكائنًا من النوع <code>Comparator</code>، ويُستخدَم التابع <code>compare</code> المُعرَّف ضمن الكائن لموازنة العناصر.
	</li>
</ul>
<p>
	سنتحدث عن الواجهتين <code>Comparable</code> و <code>Comparator</code> في القسم التالي إن لم تكن على معرفة بهما.
</p>

<h2>
	الواجهتان <code>Comparable</code> و <code>Comparator</code>
</h2>

<p>
	يتضمَّن <a href="https://github.com/AllenDowney/ThinkDataStructures" rel="external nofollow">مستودع الكتاب</a> الصنف <a href="https://github.com/AllenDowney/ThinkDataStructures/blob/cc10971a1904eda5f5b818a3d70ee1a836fd8799/solutions/src/com/allendowney/thinkdast/Card.java" rel="external nofollow"><code>Card</code></a> الذي يحتوي على طريقتين لترتيب قائمة كائنات من النوع <code>Card</code>. انظر إلى بداية تعريف الصنف:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4849_30" style="">
<span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Card</span><span class="pln"> implements </span><span class="typ">Comparable</span><span class="pun">&lt;</span><span class="typ">Card</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">private</span><span class="pln"> final </span><span class="typ">int</span><span class="pln"> rank</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">private</span><span class="pln"> final </span><span class="typ">int</span><span class="pln"> suit</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Card</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> rank</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> suit</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rank </span><span class="pun">=</span><span class="pln"> rank</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">suit </span><span class="pun">=</span><span class="pln"> suit</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	تحتوي كائنات الصنف <code>Card</code> على الحقلين <code>rank</code> و <code>suit</code> من النوع العددي الصحيح. يُنفِّذ الصنف <code>Card</code> الواجهة <code>Comparable&lt;Card&gt;‎</code> مما يَعنِي أنه بالضرورة يُوفِّر تنفيذًا للتابع <code>compareTo</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4849_33" style="">
<span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> compareTo</span><span class="pun">(</span><span class="typ">Card</span><span class="pln"> that</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">suit </span><span class="pun">&lt;</span><span class="pln"> that</span><span class="pun">.</span><span class="pln">suit</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">suit </span><span class="pun">&gt;</span><span class="pln"> that</span><span class="pun">.</span><span class="pln">suit</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rank </span><span class="pun">&lt;</span><span class="pln"> that</span><span class="pun">.</span><span class="pln">rank</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">rank </span><span class="pun">&gt;</span><span class="pln"> that</span><span class="pun">.</span><span class="pln">rank</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	تشير بصمة التابع <code>compareTo</code> إلى أن عليه أن يعيد عددًا سالبًا إذا كان <code>this</code> أقل من <code>that</code>، وعددًا موجبًا إذا كان أكبر منه، وصفرًا إذا كانا متساويين.
</p>

<p>
	إذا استخدمت نسخة التابع <code>Collections.sort</code> أحادية المعامل، فإنها بدورها تَستدعِي التابع <code>compareTo</code> المُعرَّف ضمن العناصر لكي تتمكّن من ترتيبها. على سبيل المثال، تُنشِئ الشيفرة التالية قائمة تحتوي على 52 بطاقة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4849_35" style="">
<span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">List</span><span class="pun">&lt;</span><span class="typ">Card</span><span class="pun">&gt;</span><span class="pln"> makeDeck</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">List</span><span class="pun">&lt;</span><span class="typ">Card</span><span class="pun">&gt;</span><span class="pln"> cards </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">ArrayList</span><span class="pun">&lt;</span><span class="typ">Card</span><span class="pun">&gt;();</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> suit </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> suit </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln"> suit</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> rank </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> rank </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">13</span><span class="pun">;</span><span class="pln"> rank</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">Card</span><span class="pln"> card </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Card</span><span class="pun">(</span><span class="pln">rank</span><span class="pun">,</span><span class="pln"> suit</span><span class="pun">);</span><span class="pln">
                cards</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">card</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> cards</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	ثم تُرتِّبها كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4849_37" style="">
<span class="pln">        </span><span class="typ">Collections</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="pln">cards</span><span class="pun">);</span></pre>

<p>
	تُرتِّب تلك النسخة من التابع <code>sort</code> العناصر وفقًا لما يُطلَق عليه "الترتيب الطبيعي" لأن الترتيب مُحدّد بواسطة العناصر نفسها.
</p>

<p>
	في المقابل، يُمكِننا أيضًا أن نستعين بكائن من النوع <code>Comparator</code> لكي نَفرِض نوعًا مختلفًا من الترتيب. على سبيل المثال، تحتل بطاقات الأص المَرتَبَة الأقلَّ بحسب الترتيب الطبيعي للصنف <code>Card</code>، ومع ذلك، فإنها أحيانًا تحتل المرتبة الأكبر في بعض ألعاب البطاقات، ولذلك، سنُعرِّف كائنًا من النوع <code>Comparator</code> يُعامِل الأصّ على أنّها البطاقة الأكبر ضمن مجموعة بطاقات اللعب. انظر إلى شيفرة ذلك النوع:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4849_39" style="">
<span class="pln">        </span><span class="typ">Comparator</span><span class="pun">&lt;</span><span class="typ">Card</span><span class="pun">&gt;</span><span class="pln"> comparator </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Comparator</span><span class="pun">&lt;</span><span class="typ">Card</span><span class="pun">&gt;()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="lit">@Override</span><span class="pln">
            </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> compare</span><span class="pun">(</span><span class="typ">Card</span><span class="pln"> card1</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Card</span><span class="pln"> card2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">card1</span><span class="pun">.</span><span class="pln">getSuit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> card2</span><span class="pun">.</span><span class="pln">getSuit</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">card1</span><span class="pun">.</span><span class="pln">getSuit</span><span class="pun">()</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> card2</span><span class="pun">.</span><span class="pln">getSuit</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
                </span><span class="typ">int</span><span class="pln"> rank1 </span><span class="pun">=</span><span class="pln"> getRankAceHigh</span><span class="pun">(</span><span class="pln">card1</span><span class="pun">);</span><span class="pln">
                </span><span class="typ">int</span><span class="pln"> rank2 </span><span class="pun">=</span><span class="pln"> getRankAceHigh</span><span class="pun">(</span><span class="pln">card2</span><span class="pun">);</span><span class="pln">

                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">rank1 </span><span class="pun">&lt;</span><span class="pln"> rank2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">rank1 </span><span class="pun">&gt;</span><span class="pln"> rank2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
                </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

            </span><span class="kwd">private</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> getRankAceHigh</span><span class="pun">(</span><span class="typ">Card</span><span class="pln"> card</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">int</span><span class="pln"> rank </span><span class="pun">=</span><span class="pln"> card</span><span class="pun">.</span><span class="pln">getRank</span><span class="pun">();</span><span class="pln">
                </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">rank </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">14</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="kwd">return</span><span class="pln"> rank</span><span class="pun">;</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">};</span></pre>

<p>
	تُعرِّف تلك الشيفرة صنفًا مجهول الاسم anonymous يُنفِّذ التابع <code>compare</code> على النحو المطلوب، ثم تُنشِئ نسخةً منه. يُمكِنك القراءة عن الأصناف مجهولة الاسم <a href="https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html" rel="external nofollow">Anonymous Classes</a> في لغة جافا إذا لم تكن على معرفة بها.
</p>

<p>
	يُمكِننا الآن أن نُمرِّر ذلك الكائن المنتمي للنوع <code>Comparator</code> إلى التابع <code>sort</code>، كما هو مبين في الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_4849_41" style="">
<span class="pln">        </span><span class="typ">Collections</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="pln">cards</span><span class="pun">,</span><span class="pln"> comparator</span><span class="pun">);</span></pre>

<p>
	يُعد الأص البستوني وفقًا لهذا الترتيب البطاقة الأكبر ضمن مجموعة بطاقات اللعب، بينما يُعدّ الثنائي السباتي البطاقة الأصغر.
</p>

<p>
	ستجد شيفرة هذا القسم في الملف <code>Card.java</code> إن كنت تريد تجريبه. قد ترغب أيضًا في كتابة كائن آخر من النوع <code>Comparator</code> يُرتِّب العناصر بناءً على قيمة <code>rank</code> أولًا ثم قيمة <code>suit</code>، وبالتالي، تصبح جميع بطاقات الأصّ معًا وجميع البطاقات الثنائية معًا، وهكذا.
</p>

<h2>
	ملحقات
</h2>

<p>
	إذا تمكَّنت من كتابة الكائن الذي أشرنا إليه في الأعلى، هاك بعض الأفكار الأخرى التي يُمكِنك أن تحاول القيام بها:
</p>

<ul>
<li>
		اقرأ عن درجة الارتباط <a href="https://ar.wikipedia.org/wiki/%D8%AA%D9%8A_%D8%A7%D9%81-%D8%A7%D9%8A_%D8%AF%D9%8A_%D8%AF%D9%81" rel="external nofollow">TF-IDF</a> ونفِّذها. قد تحتاج إلى تعديل الصنف <code>JavaIndex</code> لكي تجعله يَحسِب قيمة ترددات المستند أي عدد مرات ظهور كل كلمة في جميع الصفحات الموجودة بالفهرس.
	</li>
	<li>
		بالنسبة للاستعلامات المكوَّنة من أكثر من كلمةٍ واحدة، يُمكِنك أن تَحسِب درجة الارتباط الإجمالية لكل صفحة بحساب مجموع درجة الارتباط لجميع الكلمات. فكر متى يُمكِن لهذه النسخة المبسطة أن تَفشَل وجرِّب بدائل أخرى.
	</li>
	<li>
		أنشِئ واجهة مُستخدِم تَسمَح للمُستخدِمين بإدخال استعلامات تحتوي على عوامل operators منطقية. حلِّل الاستعلامات المُدْخَلة، وولِّد النتائج، ثم رتِّبها بحسب درجة الارتباط، واعرض مُحدِّدات الموارد التي أحرزت أعلى درجات. حاول أيضًا أن تُولِّد مقطع شيفرة يَعرِض مكان ظهور كلمات البحث في الصفحة. إذا أردت أن تُنشِئ تطبيق ويب لواجهة المُستخدِم التي أنشأتها، فإن <a href="https://academy.hsoub.com/devops/deployment/%D9%86%D8%B4%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82-reactjs-%D8%B9%D9%84%D9%89-%D9%85%D9%86%D8%B5%D8%A9-heroku-r513/" rel="">منصة Heroku</a> تُعدّ خيارًا بسيطًا لتطوير تطبيقات الويب ونشرها باستخدام <a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D9%84%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-java-r599/" rel="">جافا</a>.
	</li>
</ul>
<p>
	ترجمة -بتصرّف- للفصل <a href="https://greenteapress.com/thinkdast/html/thinkdast017.html" rel="external nofollow">Chapter 16: Boolean search</a> من كتاب <a href="https://greenteapress.com/thinkdast/html/index.html" rel="external nofollow">Think Data Structures: Algorithms and Information Retrieval in Java</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/advanced/%D9%86%D8%B8%D8%B1%D8%A9-%D8%B3%D8%B1%D9%8A%D8%B9%D8%A9-%D8%B9%D9%84%D9%89-%D8%A8%D8%B9%D8%B6-%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%B1%D8%AA%D9%8A%D8%A8-r1456/" rel="">نظرة سريعة على بعض خوارزميات الترتيب</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/devops/servers/databases/redis/%D9%81%D9%87%D8%B1%D8%B3%D8%A9-%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D9%88%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84%D9%87%D8%A7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%82%D8%A7%D8%B9%D8%AF%D8%A9-%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA-redis-r580/" rel="">فهرسة الصفحات وتحليل زمن تشغيلها باستخدام قاعدة بيانات Redis</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/java/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A3%D8%B4%D8%AC%D8%A7%D8%B1-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D8%A7%D9%84%D8%AB%D9%86%D8%A7%D8%A6%D9%8A%D8%A9-%D9%88%D8%A7%D9%84%D8%A3%D8%B4%D8%AC%D8%A7%D8%B1-%D8%A7%D9%84%D9%85%D8%AA%D8%B2%D9%86%D8%A9-balanced-trees-%D9%84%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A7%D9%84%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-r1454/" rel="">استخدام أشجار البحث الثنائية والأشجار المتزنة balanced trees لتنفيذ الخرائط</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/java/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B4%D8%AC%D8%B1%D8%A9-%D8%A8%D8%AD%D8%AB-%D8%AB%D9%86%D8%A7%D8%A6%D9%8A%D8%A9-treemap-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1453/" rel="">تحليل زمن تشغيل الخرائط المنفذة باستخدام شجرة بحث ثنائية TreeMap في جافا</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1455</guid><pubDate>Wed, 09 Mar 2022 16:04:00 +0000</pubDate></item><item><title>&#x645;&#x641;&#x647;&#x648;&#x645; &#x62F;&#x648;&#x627;&#x644; &#x627;&#x644;&#x62A;&#x642;&#x637;&#x64A;&#x639; Hash Functions &#x641;&#x64A; &#x627;&#x644;&#x62E;&#x648;&#x627;&#x631;&#x632;&#x645;&#x64A;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/advanced/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%AF%D9%88%D8%A7%D9%84-%D8%A7%D9%84%D8%AA%D9%82%D8%B7%D9%8A%D8%B9-hash-functions-%D9%81%D9%8A-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1428/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_01/61dd1cd09fc6d_HashFunctions-01.jpg.4a6b557d91da7e2c789849f4291ca2e7.jpg" /></p>

<p>
	تكون دالةُ <code>‎h()‎</code> <a href="https://wiki.hsoub.com/Algorithms/hashing" rel="external">دالةَ تقطيع</a> Hash Functions إذا كانت تأخذ عنصرًا <code>‎x ∈ X‎</code> من أيّ حجم، وتعيد قيمة <code>‎y ∈ Y‎</code> من حجمٍ ثابت <code>‎</code>y‎ = h (x)‎‎.
</p>

<p>
	تتميز دوّال التقطيع النموذجية بالخصائص التالية:
</p>

<ul>
<li>
		تتصرف مثل <a href="https://ar.wikipedia.org/wiki/%D8%AA%D9%88%D8%B2%D9%8A%D8%B9_%D9%85%D9%86%D8%AA%D8%B8%D9%85" rel="external nofollow">توزِيعات منتظمة</a> uniform distribution
	</li>
	<li>
		دوال التقطيع حتمية deterministic، حيث ينبغي أن تعيد الدالة <code>‎h(x)‎</code> القيمة نفسها دائمًا لعنصر <code>‎x‎</code> محدد.
	</li>
	<li>
		ينبغي أن تكون سريعة الحساب (ذات تعقيد زمني O (1)‎‎).
	</li>
</ul>
<p>
	حجم قيمة التقطيع عمومًا أصغر من حجم البيانات المُدخلة: <code>‎|y| &lt; |x|‎</code>، علاوة على أنّ دوال التقطيع غير قابلة للعكس، لأنه يجوز أن تكون لقيمتين مختلفتين قيمة التقطيع نفسها، أو بتعبير رياضي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_1219_6" style="">
<span class="pun">∃</span><span class="pln"> x1</span><span class="pun">,</span><span class="pln"> x2 </span><span class="pun">∈</span><span class="pln"> X</span><span class="pun">,</span><span class="pln"> x1 </span><span class="pun">≠</span><span class="pln"> x2</span><span class="pun">:</span><span class="pln"> h</span><span class="pun">(</span><span class="pln">x1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> h</span><span class="pun">(</span><span class="pln">x2</span><span class="pun">)</span></pre>

<p>
	قد تكون المجموعة <code>X</code> منتهية أو غير منتهية، أما <code>‎Y‎</code> فهي دائمًا مجموعة منتهية. وتُستخدم دوال التقطيع في الكثير من مجالات الحوسبة مثل هندسة البرمجيات والتشفير وقواعد البيانات والشبكات وتعلُُّم الآلة ونحو ذك، وهناك العديد من أنواع دوال التقطيع، ولكل منها خصائص مميزة.
</p>

<p>
	تكون قيمة التقطيع عددًا صحيحًا في الغالب، ومعظم لغات البرمجة لديها توابع ودوال خاصة لحساب قيم التقطيع، مثل الدالة <code>GetHashCode()‎</code> في لغة C#‎‎ التي تعيد قيمة من النوع <code>‎Int32‎</code> (عدد صحيح من 32 بتة) لكل الأنواع. وكذلك في لغة جافا هناك تابع <code>‎hashCode()‎</code> يحسب قيمة التقطيع -من النوع int- لكل صنف من أصناف جافا.
</p>

<h2>
	طرق تعريف دوال التقطيع Hash methods
</h2>

<p>
	هناك عدة طرق لتعريف دوال التقطيع، يمكننا أن نفترض دون الإخلال بالعمومية، أنّ المجموعة <code>X</code> تساوي مجموعة الأعداد الصحيحة الموجبة، و<code>x</code> عنصر منها: أي <code>‎x ∈ X = {z ∈ ℤ: z ≥‎ 0}‎‎</code>. وليكن m عددًا، ويُفضّل أن يكون أوليًا (شرط أن لا تكون قيمته قريبة جدًا من أي قوّة للعدد 2).
</p>

<p>
	فيما يلي طريقتان لحساب قيم التقطيع الخاصة بعناصر <code>X</code>:
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
<thead><tr>
<th>
				الطريقة
			</th>
			<th>
				دالة التقطيع
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				طريقة القسمة
			</td>
			<td>
				<code>h(x) = x mod m</code>
			</td>
		</tr>
<tr>
<td>
				طريقة الضرب
			</td>
			<td>
				<code>h(x) = ⌊m (xA mod 1)⌋, A ∈ {z ∈ ℝ: 0 &lt; z &lt; 1}</code>
			</td>
		</tr>
</tbody>
</table>
<h2>
	جداول التقطيع
</h2>

<p>
	تُستخدم دوال التقطيع مع <a href="https://wiki.hsoub.com/Algorithms/hashing#.D8.AC.D8.AF.D9.88.D9.84_.D8.A7.D9.84.D8.AA.D9.82.D8.B7.D9.8A.D8.B9" rel="external">جداول التقطيع</a> hash tables لحساب الفهارس في مصفوفة من الحجرات array of slots، وجدول التقطيع هي هيكلية بيانات لتنفيذ <strong>القواميس</strong> dictionaries وهي بيانات من نوع مفتاح-قيمة.
</p>

<p>
	التعقيد الزمني لتطبيقات لجداول التقطيع يساوي في العادة O (1)‎‎ للعمليات التالية:
</p>

<ul>
<li>
		إدراج البيانات بحسب قيمة المفتاح.
	</li>
	<li>
		حذف البيانات بحسب قيمة المفتاح.
	</li>
</ul>
<p>
	يمكن أن يكون لعدة مفاتيح نفس التقطيع (الحجرة)، وعندئذ فهناك طريقتان لحل هذه المشكلة:
</p>

<ul>
<li>
		<strong>السلسلة Chaining</strong>: تُستخدم <a href="https://wiki.hsoub.com/Algorithms/linked_lists" rel="external">القوائم المترابطة</a> لتخزين العناصر التي لها نفس قيمة التقطيع في الحجرة.
	</li>
	<li>
		<strong>العنونة المفتوحة Open addressing</strong>: يُخزّن عنصر واحد على الأكثر في كل حجرة.
	</li>
</ul>
<p>
	تُستخدم الطرق التالية لحساب <a href="https://wiki.hsoub.com/Algorithms/hashing#.D8.B7.D8.B1.D9.82_.D8.AA.D9.86.D9.81.D9.8A.D8.B0_.D8.A7.D9.84.D8.B9.D9.86.D9.88.D9.86.D8.A9_.D8.A7.D9.84.D9.85.D9.81.D8.AA.D9.88.D8.AD.D8.A9" rel="external">تسلسلات المسبار</a> probe sequences المطلوبة في العنونة المفتوحة:
</p>

<table>
<thead><tr>
<th>
				الطريقة
			</th>
			<th>
				الصيغة
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				السبر الخطي
			</td>
			<td>
				<code>h(x, i) = (h”(x) + i) mod m</code>
			</td>
		</tr>
<tr>
<td>
				السبر التربيعي
			</td>
			<td>
				<code>h(x, i) = (h”(x) + c1*i + c2*i^2) mod m</code>
			</td>
		</tr>
<tr>
<td>
				السبر المضاعف
			</td>
			<td>
				<code>h(x, i) = (h1(x) + i*h2(x)) mod m</code>
			</td>
		</tr>
</tbody>
</table>
<p>
	الدوال <code>h"(x)‎‎</code> و <code>h1(x)‎‎</code> و <code>h2(x)‎‎</code> هي دوال مساعدة، و<code>i</code> ينتمي إلى المجموعة <code>{0, 1, ..., m-1}</code>، و<code>c1</code> و <code>c2</code> ثابتتان موجبتان.
</p>

<p>
	يمكنك معرفة المزيد من التفاصيل عن هذه الطرق الثلاث وغيرها من المفاهيم المتعلقة بدوال التقطيع من <a href="https://wiki.hsoub.com/Algorithms/hashing#.D8.B7.D8.B1.D9.82_.D8.AA.D9.86.D9.81.D9.8A.D8.B0_.D8.A7.D9.84.D8.B9.D9.86.D9.88.D9.86.D8.A9_.D8.A7.D9.84.D9.85.D9.81.D8.AA.D9.88.D8.AD.D8.A9" rel="external">موسوعة حسوب</a>.
</p>

<p>
	لنأخذ المثال التالي، ليكن <code>‎x ∈ U{1, 1000}‎‎ و h = x mod m‎</code>. يوضح الجدول التالي قيم التقطيع في حالة كان العدد <code>m</code> أوليا أو غير أولي، تشير النصوص الغليظة إلى قيم التقطيع المتساوية.
</p>

<table>
<thead><tr>
<th>
				x
			</th>
			<th>
				m = 100 - غير أولي
			</th>
			<th>
				m = 101 - أولي
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				723
			</td>
			<td>
				23
			</td>
			<td>
				16
			</td>
		</tr>
<tr>
<td>
				103
			</td>
			<td>
				3
			</td>
			<td>
				2
			</td>
		</tr>
<tr>
<td>
				738
			</td>
			<td>
				38
			</td>
			<td>
				31
			</td>
		</tr>
<tr>
<td>
				292
			</td>
			<td>
				92
			</td>
			<td>
				90
			</td>
		</tr>
<tr>
<td>
				61
			</td>
			<td>
				61
			</td>
			<td>
				61
			</td>
		</tr>
<tr>
<td>
				87
			</td>
			<td>
				87
			</td>
			<td>
				87
			</td>
		</tr>
<tr>
<td>
				995
			</td>
			<td>
				95
			</td>
			<td>
				86
			</td>
		</tr>
<tr>
<td>
				549
			</td>
			<td>
				49
			</td>
			<td>
				44
			</td>
		</tr>
<tr>
<td>
				991
			</td>
			<td>
				91
			</td>
			<td>
				82
			</td>
		</tr>
<tr>
<td>
				757
			</td>
			<td>
				<strong>57</strong>
			</td>
			<td>
				50
			</td>
		</tr>
<tr>
<td>
				920
			</td>
			<td>
				20
			</td>
			<td>
				11
			</td>
		</tr>
<tr>
<td>
				626
			</td>
			<td>
				26
			</td>
			<td>
				20
			</td>
		</tr>
<tr>
<td>
				557
			</td>
			<td>
				<strong>57</strong>
			</td>
			<td>
				52
			</td>
		</tr>
<tr>
<td>
				931
			</td>
			<td>
				31
			</td>
			<td>
				23
			</td>
		</tr>
<tr>
<td>
				619
			</td>
			<td>
				19
			</td>
			<td>
				13
			</td>
		</tr>
</tbody>
</table>
<h2>
	قيم التقطيع للأنواع الشائعة في C#‎‎
</h2>

<p>
	سنستعرض في هذه الفقرة قيم التقطيع hash codes التي ينتجها التابع <code>‎GetHashCode()‎</code> لأنواع C#‎‎المضمّنة في فضاء الاسم <code>‎System‎</code>. يمكنك الاطلاع على توثيقات هذه الأنواع من <a href="https://github.com/dotnet/coreclr/tree/release/1.1.0/src/mscorlib/src/System" rel="external nofollow">github</a>.
</p>

<h3>
	القيم المنطقية Boolean
</h3>

<p>
	1 إذا كانت القيمة صحيحة true، أو 0 خلاف ذلك.
</p>

<h3>
	الأنواع Byte و UInt16 و Int32 و UInt32 و Single
</h3>

<p>
	قيمة العنصر (تُحوّل عند الضرورة إلى النوع Int32).
</p>

<h3>
	النوع SByte
</h3>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1219_8" style="">
<span class="pun">((</span><span class="pln">int</span><span class="pun">)</span><span class="pln">m_value </span><span class="pun">^</span><span class="pln"> </span><span class="pun">(</span><span class="pln">int</span><span class="pun">)</span><span class="pln">m_value </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="lit">8</span><span class="pun">);</span></pre>

<h3>
	النوع Char
</h3>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1219_10" style="">
<span class="pun">(</span><span class="pln">int</span><span class="pun">)</span><span class="pln">m_value </span><span class="pun">^</span><span class="pln"> </span><span class="pun">((</span><span class="pln">int</span><span class="pun">)</span><span class="pln">m_value </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="lit">16</span><span class="pun">);</span></pre>

<h3>
	النوع Int16
</h3>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1219_12" style="">
<span class="pun">((</span><span class="pln">int</span><span class="pun">)((</span><span class="pln">ushort</span><span class="pun">)</span><span class="pln">m_value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">^</span><span class="pln"> </span><span class="pun">(((</span><span class="pln">int</span><span class="pun">)</span><span class="pln">m_value</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="lit">16</span><span class="pun">));</span></pre>

<h3>
	النوعان Int64 و Double
</h3>

<p>
	تطبيق المعامل Xor بين أدنى 32 بتّة وأعلى 32 بتة في العدد المؤلف من 64 بتة.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1219_14" style="">
<span class="pun">(</span><span class="pln">unchecked</span><span class="pun">((</span><span class="pln">int</span><span class="pun">)((</span><span class="pln">long</span><span class="pun">)</span><span class="pln">m_value</span><span class="pun">))</span><span class="pln"> </span><span class="pun">^</span><span class="pln"> </span><span class="pun">(</span><span class="pln">int</span><span class="pun">)(</span><span class="pln">m_value </span><span class="pun">&gt;&gt;</span><span class="pln"> </span><span class="lit">32</span><span class="pun">));</span></pre>

<h3>
	الأنواع UInt64 و DateTime و TimeSpan
</h3>

<pre class="ipsCode">
((int)m_value) ^ (int)(m_value &gt;&gt; 32);
</pre>

<h3>
	النوع Decimal
</h3>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1219_16" style="">
<span class="pun">((((</span><span class="pln">int </span><span class="pun">*)&amp;</span><span class="pln">dbl</span><span class="pun">)[</span><span class="lit">0</span><span class="pun">])</span><span class="pln"> </span><span class="pun">&amp;</span><span class="pln"> </span><span class="lit">0xFFFFFFF0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">^</span><span class="pln"> </span><span class="pun">((</span><span class="pln">int </span><span class="pun">*)&amp;</span><span class="pln">dbl</span><span class="pun">)[</span><span class="lit">1</span><span class="pun">];</span></pre>

<h3>
	Object
</h3>

<p>
	النوع <a href="https://github.com/dotnet/coreclr/blob/release/1.1.0/src/mscorlib/src/System/Object.cs#L92" rel="external nofollow">Object</a> هو الصنف الجذري الذي تنحدر منه جميع الكائنات.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1219_18" style="">
<span class="typ">RuntimeHelpers</span><span class="pun">.</span><span class="typ">GetHashCode</span><span class="pun">(</span><span class="pln">this</span><span class="pun">);</span></pre>

<p>
	استخدمنا التطبيق الافتراضي <a href="https://github.com/dotnet/coreclr/blob/release/1.1.0/src/classlibnative/bcltype/objectnative.cpp#L103" rel="external nofollow">فهرس كتلة المزامنة</a> sync block index.
</p>

<h3>
	السلاسل النصية String
</h3>

<p>
	يعتمد حساب قيمة التقطيع على نوع <a href="https://academy.hsoub.com/files/24-%D8%A3%D9%86%D8%B8%D9%85%D8%A9-%D8%A7%D9%84%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D9%84%D9%84%D9%85%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D9%86/" rel="">نظام التشغيل</a> (Win32 أو Win64)، وإمكانية استخدام تقطيع السلاسل النصية العشوائية randomized string hashing، إضافة إلى الإصدار ووضعية المنقّح.
</p>

<p>
	في حالة المنصة Win64:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1219_20" style="">
<span class="pln">int hash1 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">5381</span><span class="pun">;</span><span class="pln">
int hash2 </span><span class="pun">=</span><span class="pln"> hash1</span><span class="pun">;</span><span class="pln">
int c</span><span class="pun">;</span><span class="pln">
char </span><span class="pun">*</span><span class="pln">s </span><span class="pun">=</span><span class="pln"> src</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="pun">((</span><span class="pln">c </span><span class="pun">=</span><span class="pln"> s</span><span class="pun">[</span><span class="lit">0</span><span class="pun">])</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   hash1 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">((</span><span class="pln">hash1 </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> hash1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">^</span><span class="pln"> c</span><span class="pun">;</span><span class="pln">
   c </span><span class="pun">=</span><span class="pln"> s</span><span class="pun">[</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">c </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   hash2 </span><span class="pun">=</span><span class="pln"> </span><span class="pun">((</span><span class="pln">hash2 </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> hash2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">^</span><span class="pln"> c</span><span class="pun">;</span><span class="pln">
   s </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> hash1 </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="pln">hash2 </span><span class="pun">*</span><span class="pln"> </span><span class="lit">1566083941</span><span class="pun">);</span></pre>

<h3>
	ValueType
</h3>

<p>
	يتم البحث عن أول حقل غير ساكن non-static ﬁeld، وتُحسب قيمة التقطيع خاصته، إذا لم يكن للنوع أيّ حقل غير ساكن، تُعاد قيمة التقطيع الخاصة بذلك النوع. لا يمكن الاعتماد على قيمة التقطيع الخاصة بمتغير عضو ساكن static member، لأنه قد تنتجُ حلقة أبدية إذا كان نوع ذلك العضو يساوي النوع الأصلي.
</p>

<h3>
	النوع Nullable<t>‎‎</t>
</h3>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1219_22" style="">
<span class="kwd">return</span><span class="pln"> hasValue </span><span class="pun">?</span><span class="pln"> value</span><span class="pun">.</span><span class="typ">GetHashCode</span><span class="pun">()</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span></pre>

<h3>
	المصفوفات Array
</h3>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_1219_24" style="">
<span class="pln">int ret </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">int i </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Length</span><span class="pln"> </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="typ">Length</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">Length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
    ret </span><span class="pun">=</span><span class="pln"> </span><span class="pun">((</span><span class="pln">ret </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> ret</span><span class="pun">)</span><span class="pln"> </span><span class="pun">^</span><span class="pln"> comparer</span><span class="pun">.</span><span class="typ">GetHashCode</span><span class="pun">(</span><span class="typ">GetValue</span><span class="pun">(</span><span class="pln">i</span><span class="pun">));</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ترجمة -بتصرّف- للفصل 43 من كتاب <a href="https://goalkicker.com/AlgorithmsBook/" rel="external nofollow">Algorithms Notes for Professionals</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/advanced/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%84%D9%89-%D8%A3%D8%B4%D9%87%D8%B1-%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AE%D8%B7%D8%B7%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%A3%D8%B4%D8%AC%D8%A7%D8%B1-r1427/" rel="">أمثلة على أشهر خوارزميات المخططات والأشجار</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1282/" rel="">مدخل إلى الخوارزميات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%86-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1410/" rel="">أمثلة عن أنواع الخوارزميات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D8%B9%D9%82%D9%8A%D8%AF-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-algorithms-complexity-r1284/" rel="">تعقيد الخوارزميات Algorithms Complexity</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1428</guid><pubDate>Sun, 09 Jan 2022 16:00:00 +0000</pubDate></item><item><title>&#x623;&#x645;&#x62B;&#x644;&#x629; &#x639;&#x644;&#x649; &#x623;&#x634;&#x647;&#x631; &#x62E;&#x648;&#x627;&#x631;&#x632;&#x645;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x645;&#x62E;&#x637;&#x637;&#x627;&#x62A; &#x648;&#x627;&#x644;&#x623;&#x634;&#x62C;&#x627;&#x631;</title><link>https://academy.hsoub.com/programming/advanced/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%84%D9%89-%D8%A3%D8%B4%D9%87%D8%B1-%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D8%AE%D8%B7%D8%B7%D8%A7%D8%AA-%D9%88%D8%A7%D9%84%D8%A3%D8%B4%D8%AC%D8%A7%D8%B1-r1427/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2022_01/61dc8bb671a6d_-01.jpg.2cc06e9fa7454da6a8392d0b0f89f5cb.jpg" /></p>

<p>
	تستعرض هذه المقالة أربعةً من خوارزميات الأشجار والمخططات، وهي خوارزمية البحث بالعرض أولا BFS، وخوارزمية البحث بالعمق أولا DFS، والبائع المتجول، وخوارزمية كثيرة الحدود للعثور على أصغر غطاء رأسي في مخطط ما.
</p>

<h2>
	البحث بالعرض أولا Breadth-First Search
</h2>

<p>
	سنحاول استعمال هذه <a href="https://academy.hsoub.com/programming/advanced/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1282/" rel="">الخوارزمية</a> في عدة تطبيقات عمليات بحث.
</p>

<h3>
	البحث عن أقصر مسار من المصدر إلى العقد الأخرى
</h3>

<p>
	خوارزمية البحث بالعرض أولا BFS هي خوارزمية لتسلق مخطط أو البحث فيها. تبدأ الخوارزمية من جذر الشجرة (أو أيّ عقدة من المخطط، ويُشار إليها أحيانًا باسم "مفتاح البحث" - search key)، ثمّ تستكشف العقد المجاورة أولاً قبل الانتقال إلى المستوى التالي من العقد.
</p>

<p>
	اكتُشفت خوارزمية BFS في أواخر الخمسينيات من قبل إدوارد فورست مور Edward Forrest Moore، الذي استخدمها للعثور على أقصر مسار للخروج من متاهة، وقد اكتُشفت أيضًا بشكل مستقل من قبل CY Lee الذي استخدمها في مجال التوجيه السلكي في عام 1961.
</p>

<p>
	تفترض خوارزمية BFS الأمور التالية:
</p>

<ol>
<li>
		لن نجتاز أي عقدة أكثر من مرة.
	</li>
	<li>
		تقع العقدة المصدرية (أي العقدة التي نبدأ منها) في المستوى 0.
	</li>
	<li>
		العقد التي يمكننا الوصول إليها مباشرة من العقدة المصدرية ستكون في المستوى 1، والعقد التي يمكننا الوصول إليها مباشرة من عقد المستوى 1 ستكون في المستوى 2 وهكذا دواليك.
	</li>
	<li>
		يشير مستوى عقدة ما إلى أقصر مسار يصل إلى تلك العقدة انطلاقًا من المصدر.
	</li>
</ol>
<p>
	انظر المثال التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="88632" href="https://academy.hsoub.com/uploads/monthly_2022_01/LrC21.png.0e6ef0d437072655ba587507dc9e4285.png" rel=""><img alt="LrC21.png" class="ipsImage ipsImage_thumbnailed" data-fileid="88632" data-unique="xnze8cuah" src="https://academy.hsoub.com/uploads/monthly_2022_01/LrC21.png.0e6ef0d437072655ba587507dc9e4285.png" style="width: 400px; height: auto;"></a>
</p>

<p>
	لنفترض أنّ هذا المخطط يمثل طرقا بين عدة مدن حيث تمثل كل عقدة مدينة واحدة، فيما يشير كل ضلع بين عقدتين إلى طريق يربط بينهما، ونحن نريد الانتقال من <strong>العقدة 1</strong> إلى <strong>العقدة 10</strong>. ستكون <strong>العقدة 1</strong> هي المصدر، وهذا يجعلها في <strong>المستوى 0</strong>. نحدد (نلوّن) <strong>العقدة 1</strong> لنشير إلى أننا زرناها.<br>
	يمكننا الذهاب إلى <strong>العقدة 2</strong> أو <strong>العقدة 3</strong> أو <strong>العقدة 4</strong> من <strong>العقدة المصدر</strong>، أي <strong>العقدة 1</strong>، لذلك ستكون هناك 3 عقد من المستوى 1. نحدد هذه العقد لنبيّن أنّها مُزارة، ثمّ نعمل عليها.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="88637" href="https://academy.hsoub.com/uploads/monthly_2022_01/Wwcte.png.95192a6d2643c718efb081b6fc17a4dd.png" rel=""><img alt="Wwcte.png" class="ipsImage ipsImage_thumbnailed" data-fileid="88637" data-unique="cqug3o4p2" src="https://academy.hsoub.com/uploads/monthly_2022_01/Wwcte.png.95192a6d2643c718efb081b6fc17a4dd.png" style="width: 400px; height: auto;"></a>
</p>

<p>
	نلوّن العقد المُزارة، حيث نلوّن العقد التي نعمل عليها حاليًا باللون الوردي، تذكّر أنّنا لن نزور العقدة نفسها مرتين. يمكننا الذهاب إلى العقد <strong>6</strong> و <strong>7</strong> و <strong>8</strong> عبر كل من <strong>العقدة 2</strong> و<strong>العقدة 3</strong> و<strong>العقدة 4</strong>، وسنحددهذه العقد لنبيّن أنّها مُزارة. مستوى هذه العقد سيساوي (1 +1) = 2.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="88634" href="https://academy.hsoub.com/uploads/monthly_2022_01/Ns886.png.3441ad2df1ca855dddd282e84d1c6850.png" rel=""><img alt="Ns886.png" class="ipsImage ipsImage_thumbnailed" data-fileid="88634" data-unique="07m6zuzhw" src="https://academy.hsoub.com/uploads/monthly_2022_01/Ns886.png.3441ad2df1ca855dddd282e84d1c6850.png" style="width: 400px; height: auto;"></a>
</p>

<p>
	يشير مستوى العقد إلى أقصر مسافة بينها وبين المصدر. على سبيل المثال: بما أن <strong>العقدة 8</strong> موجودة في <strong>المستوى 2</strong>، فهذا يعني أنّ المسافة من <strong>المصدر</strong> إلى <strong>العقدة 8</strong> هي 2.
</p>

<p>
	لم نصل بعدُ إلى العقدة المستهدفة وهي <strong>العقدة 10</strong>، لذا ننتقل إلى العقد التالية. نستطيع الانطلاق من أيّ من عقد <strong>المستوى 2</strong>، وهي <strong>العقدة 6</strong> و<strong>العقدة 7</strong> و<strong>العقدة 8</strong>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="88638" href="https://academy.hsoub.com/uploads/monthly_2022_01/XdE7c.png.4c11030c8b5559fae0455d3a2ae99031.png" rel=""><img alt="XdE7c.png" class="ipsImage ipsImage_thumbnailed" data-fileid="88638" data-unique="yhjdq6abp" src="https://academy.hsoub.com/uploads/monthly_2022_01/XdE7c.png.4c11030c8b5559fae0455d3a2ae99031.png" style="width: 400px; height: auto;"></a>
</p>

<p>
	ها قد وجدنا <strong>العقدة 10</strong> عند <strong>المستوى 3</strong>، هذا يعني أنّ أقصر مسار من <strong>المصدر</strong> إلى <strong>العقدة 10</strong> هو 3، وقد بحثنا في كل مستوى من مستويات المخطط إلى أن وجدنا أقصر مسار، وإذ ذاك سنمسح الأضلاع التي لم نستخدمها:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="88627" href="https://academy.hsoub.com/uploads/monthly_2022_01/AaVRF.png.72503f2f6f8348dcadab1ef59848cbc5.png" rel=""><img alt="AaVRF.png" class="ipsImage ipsImage_thumbnailed" data-fileid="88627" data-unique="ti90zslwn" src="https://academy.hsoub.com/uploads/monthly_2022_01/AaVRF.png.72503f2f6f8348dcadab1ef59848cbc5.png" style="width: 400px; height: auto;"></a>
</p>

<p>
	بعد إزالة تلك الأضلاع التي لم نستخدمها نحصل على شجرة تُسمى <strong>شجرة البحث بالعرض أولًا BFS</strong>. تُظهر هذه الشجرة أقصر مسار من المصدر إلى جميع العقد الأخرى.
</p>

<p>
	مهمتنا الآن هي الانتقال من <strong>العقدة المصدر</strong> إلى العقد الموجودة في <strong>المستوى 1</strong>، ثم من عقد <strong>المستوى 1</strong> إلى عقد <strong>المستوى 2</strong>، وهكذا حتى نصل إلى وجهتنا. يمكننا استخدام <a href="https://wiki.hsoub.com/Algorithms/queues" rel="external">الطوابير Queues</a> لتخزين العقد التي سنعالجها. لكل عقدة نعمل عليها فإننا ندفع (نضيف) إلى الطابور جميع العُقد الأخرى التي من الممكن اجتيَازها مباشرة لكنّنا لم نفعل بعد.
</p>

<p>
	هذه محاكاة للمثال:
</p>

<p>
	أولاً، ندفع العقدة المصدر إلى الطابور، فيبدو هكذا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_590_17" style="">
<span class="pln"> front
</span><span class="pun">+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">    </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-----+</span></pre>

<p>
	مستوى العقدة 1 يساوي 0، أي <code>level[1] = 0</code>، نبدأ الآن البحث بالعرض أولا BFS.
</p>

<p>
	في البداية، ننزع عقدة من الطابور فنحصل على <strong>العقدة 1</strong>، يمكننا -انطلاقًا من هذه العقدة- أن نذهب إلى العقدة <strong>4</strong> أو <strong>3</strong> أو <strong>2</strong>، لهذا فهذه العقد الثلاث من المستوى الأول، أي <code>level[4] = level[3] = level[2] = level[1] + 1 = 1</code>. سنحددالآن هذه العقد لنبيّن أنّها مُزارَة، ثمّ ندفعها إلى الطابور.
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_590_19" style="">
<span class="pln">                          front
</span><span class="pun">+-----+</span><span class="pln">  </span><span class="pun">+-----+</span><span class="pln">  </span><span class="pun">+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">4</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-----+</span><span class="pln">  </span><span class="pun">+-----+</span><span class="pln">  </span><span class="pun">+-----+</span></pre>

<p>
	ننزع الآن <strong>العقدة 4</strong> من الطابور ونعالجها، نستطيع الذهاب منها إلى <strong>العقدة 7</strong>، لهذا يكون لدينا: <code>level[7] = level[4] + 1 = 2</code>. والآن نحددالعقدة 7، ثمّ ندفعها إلى الطابور.
</p>

<pre class="ipsCode">
                          front
+-----+  +-----+  +-----+
|    7  |   |  2   |   |   3  |
+-----+  +-----+  +-----+
</pre>

<p>
	من <strong>العقدة 3</strong>، يمكننا الذهاب إلى <strong>العقدة 7</strong> أو <strong>العقدة 8</strong>، وبما أن <strong>العقدة 7</strong> محددة من قبل (أي مُزارة سابقًا)، فإننا نحدد <strong>العقدة 8</strong>، ونضع <code>level[8] = level[3] + 1 = 2</code>. والآن ندفع <strong>العقدة 8</strong> إلى الطابور.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_590_21" style="">
<span class="pln">                         front
</span><span class="pun">+-----+</span><span class="pln">  </span><span class="pun">+-----+</span><span class="pln">  </span><span class="pun">+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">   </span><span class="lit">6</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">7</span><span class="pln">   </span><span class="pun">|</span><span class="pln">  </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-----+</span><span class="pln">  </span><span class="pun">+-----+</span><span class="pln">  </span><span class="pun">+-----+</span></pre>

<p>
	ستستمر هذه العملية حتى نصل إلى وجهتنا أو نُفرِغ الطابور، وتزوّدنا مصفوفة المستويات <strong>level</strong> بطول أقصر مسار من <strong>المصدر</strong>. نستطيع تهيئة عناصر <strong>مصفوفة المستويات</strong> بقيمة اللانهاية، كناية إلى أنّ العقد لم تُزر بعد.
</p>

<p>
	انظر المثال التوضيحي لهذا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_23" style="">
<span class="typ">Procedure</span><span class="pln"> BFS</span><span class="pun">(</span><span class="typ">Graph</span><span class="pun">,</span><span class="pln"> source</span><span class="pun">):</span><span class="pln">
Q </span><span class="pun">=</span><span class="pln"> queue</span><span class="pun">();</span><span class="pln">
level</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> infinity
level</span><span class="pun">[</span><span class="pln">source</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
Q</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">source</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> Q </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> empty
   u </span><span class="pun">-&gt;</span><span class="pln"> Q</span><span class="pun">.</span><span class="pln">pop</span><span class="pun">()</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> all edges </span><span class="kwd">from</span><span class="pln"> u to v </span><span class="kwd">in</span><span class="pln"> </span><span class="typ">Adjacency</span><span class="pln"> list
       </span><span class="kwd">if</span><span class="pln"> level</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> infinity
           level</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> level</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
           Q</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">v</span><span class="pun">)</span><span class="pln">
       end </span><span class="kwd">if</span><span class="pln">
   end </span><span class="kwd">for</span><span class="pln">
end </span><span class="kwd">while</span><span class="pln">
</span><span class="typ">Return</span><span class="pln"> level</span></pre>

<p>
	يمكننا معرفة المسافة التي تفصل كل عقدة عن المصدر من خلال التكرار عبر <strong>مصفوفة المستويات</strong>، على سبيل المثال: المسافة إلى <strong>العقدة 10</strong> من <strong>المصدر</strong> مخزّنة في <strong>level[10]‎‎</strong>.
</p>

<p>
	قد نريد أحيانًا أن نعرف المسارات الأخرى التي يمكن أن تُوصلنا إلى العقدة انطلاقًا من <strong>المصدر</strong>، وذلك إلى جانب المسار الأقصر. لفعل هذا نحتاج إلى مصفوفة جديدة نسميها <strong>parent</strong>، قيمة <strong>parent[source]‎‎</strong> ‏(source هنا تعني العقدة المصدر‏) ستكون معدومة ‎‎<code>NULL</code>‎‎. نضيف التعليمة <code>‎parent[v] := u‎</code> إلى المثال الوهمي عند كل تحديث لمصفوفة المستويات <code>level</code> في حلقة for.
</p>

<p>
	لكي تعثر على المسار بعد انتهاء خوارزمية البحث العرضي أولًا، يكفي أن تجتاز المصفوفة <strong>parent</strong> خلفيًا إلى أن تصل إلى <strong>المصدر</strong>، والذي يحمل القيمة <code>NULL</code> في هذه المصفوفة.
</p>

<p>
	هذا مثال توضيحي يستخدم العودية recursion:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_29" style="">
<span class="typ">Procedure</span><span class="pln"> </span><span class="typ">PrintPath</span><span class="pun">(</span><span class="pln">u</span><span class="pun">):</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> parent</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> equal to null    
   </span><span class="typ">PrintPath</span><span class="pun">(</span><span class="pln">parent</span><span class="pun">[</span><span class="pln">u</span><span class="pun">])</span><span class="pln">                  
end </span><span class="kwd">if</span><span class="pln">                                
</span><span class="kwd">print</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> u                           </span></pre>

<p>
	وهذا مثال لا يستخدمها وإنما يستخدم التكرارية فقط iteration:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_31" style="">
<span class="typ">Procedure</span><span class="pln"> </span><span class="typ">PrintPath</span><span class="pun">(</span><span class="pln">u</span><span class="pun">):</span><span class="pln">
S </span><span class="pun">=</span><span class="pln">  </span><span class="typ">Stack</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> parent</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> equal to null
     S</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">u</span><span class="pun">)</span><span class="pln">
     u </span><span class="pun">:=</span><span class="pln"> parent</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln">
end </span><span class="kwd">while</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> S </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> empty
     </span><span class="kwd">print</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> S</span><span class="pun">.</span><span class="pln">pop
end </span><span class="kwd">while</span></pre>

<p>
	<strong>تعقيد الخوارزمية</strong>: سوف نزور كل عقدة وكل ضلع مرّة واحدة بالضبط، لذا سيكون تعقيد الخوارزمية الزمني <code>O (V + E)‎‎</code>، حيث يمثل V عدد العقد، ويمثّل E عدد الأضلاع.
</p>

<h3>
	البحث عن أقصر مسار ينطلق من المصدر في مخطط ثنائية الأبعاد
</h3>

<p>
	قد نحتاج أحيانًا إلى العثور على أقصر مسار من مصدر معيّن إلى جميع العقد الأخرى، أو إلى عقدة محدّدة في مخطط ثنائية الأبعاد.
</p>

<p>
	على سبيل المثال: نريد أن نعرف عدد التحركات المطلوبة للفارس للوصول إلى مربع معين في رقعة الشطرنج، وهذه حالة خاصة من مشكلة أكبر، حيث تكون لدينا رقعة بعض مربعاتها محظورة (الفارس لا يمكنه الانتقال لبعض المربعات على الرقعة)، وعلينا العثور على أقصر مسار من مربع إلى آخر لا يمر عبر المربعات المحظورة.
</p>

<p>
	في مثل هذه الحالات، يمكننا تحويل المربعات أو الخلايا إلى عقد، ونحل هذه المشكلة بسهولة باستخدام خوارزمية البحث بالعرض أولًا BFS. ستكون المصفوفات <code>visited</code> و <code>parent</code> و <code>level</code> جميعها مصفوفات ثنائية الأبعاد.
</p>

<p>
	نأخذ جميع التحركات الممكنة لكل عقدة، ونحسب المسافة إلى العقد الأخرى عبر تحليل مسارات التحرك، ثم نضيف مصفوفة أخرى نسميها <code>direction</code>، والتي ستخزّن جميع التركيبات الممكنة للاتجاهات التي يمكننا الذهاب إليها. مثلا، هذه مصفوفة الاتجاهات الخاصة بالتحركات الأفقية والعمودية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_33" style="">
<span class="pun">+----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> dx  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">   </span><span class="pun">|</span><span class="pln">  </span><span class="pun">-</span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">   </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> dy  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">   </span><span class="pun">|</span><span class="pln">  </span><span class="pun">-</span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----+-----+-----+-----+-----+</span></pre>

<p>
	تمثل <code>dx</code> الحركة على المحور الأفقي <code>x</code> بينما تمثل <code>dy</code> الحركة على المحور العمودي <code>y</code>، ولا شك أن هناك طرق أخرى لتمثيل اتجاهات الحركة لكن يُفضل استخدام مصفوفة الاتجاهات لأنها أسهل وأبسط. كذلك هناك الكثير من التركيبات الممكنة للحركة، إذ يمكن أن تكون التحركات قُطرية أو قد تكون أكثر تعقيدًا مثل تحركات الحصان على رقعة الشطرنج.
</p>

<p>
	وينبغي أن نضع في حسباننا الأمور التالية:
</p>

<ul>
<li>
		إذا كانت أيّ من الخلايا محظورة فسيكون علينا أن نتحقق في كل حركة محتملة مما إذا كانت الخلية الحالية محظورة أم لا.
	</li>
	<li>
		علينا أن نتحقق أيضًا ممّا إذا كنا قد تجاوزنا الحدودَ، أي حدودَ المصفوفة.
	</li>
	<li>
		سنُعطى عدد الصفوف والأعمدة.
	</li>
</ul>
<p>
	انظر المثال التوضيحي التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_35" style="">
<span class="typ">Procedure</span><span class="pln"> BFS2D</span><span class="pun">(</span><span class="typ">Graph</span><span class="pun">,</span><span class="pln"> blocksign</span><span class="pun">,</span><span class="pln"> row</span><span class="pun">,</span><span class="pln"> column</span><span class="pun">):</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i </span><span class="kwd">from</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to row
   </span><span class="kwd">for</span><span class="pln"> j </span><span class="kwd">from</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to column
       visited</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> false
   end </span><span class="kwd">for</span><span class="pln">
end </span><span class="kwd">for</span><span class="pln">
visited</span><span class="pun">[</span><span class="pln">source</span><span class="pun">.</span><span class="pln">x</span><span class="pun">][</span><span class="pln">source</span><span class="pun">.</span><span class="pln">y</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> true
level</span><span class="pun">[</span><span class="pln">source</span><span class="pun">.</span><span class="pln">x</span><span class="pun">][</span><span class="pln">source</span><span class="pun">.</span><span class="pln">y</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
Q </span><span class="pun">=</span><span class="pln"> queue</span><span class="pun">()</span><span class="pln">
Q</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">source</span><span class="pun">)</span><span class="pln">
m </span><span class="pun">:=</span><span class="pln"> dx</span><span class="pun">.</span><span class="pln">size
</span><span class="kwd">while</span><span class="pln"> Q </span><span class="kwd">is</span><span class="pln"> </span><span class="kwd">not</span><span class="pln"> empty
   top </span><span class="pun">:=</span><span class="pln"> Q</span><span class="pun">.</span><span class="pln">pop
   </span><span class="kwd">for</span><span class="pln"> i </span><span class="kwd">from</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to m
       temp</span><span class="pun">.</span><span class="pln">x </span><span class="pun">:=</span><span class="pln"> top</span><span class="pun">.</span><span class="pln">x </span><span class="pun">+</span><span class="pln"> dx</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
       temp</span><span class="pun">.</span><span class="pln">y </span><span class="pun">:=</span><span class="pln"> top</span><span class="pun">.</span><span class="pln">y </span><span class="pun">+</span><span class="pln"> dy</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> temp </span><span class="kwd">is</span><span class="pln"> inside the row </span><span class="kwd">and</span><span class="pln"> column </span><span class="kwd">and</span><span class="pln"> top doesn</span><span class="str">'t equal to blocksign
           visited[temp.x][temp.y] := true
           level[temp.x][temp.y] := level[top.x][top.y] + 1
           Q.push(temp)
       end if
   end for
end while
Return level</span></pre>

<p>
	ناقشنا سابقًا أن <a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D9%88%D8%A2%D9%84%D9%8A%D8%A9-%D8%B9%D9%85%D9%84%D9%87%D8%A7-r1414/" rel="">خوارزمية البحث</a> بالعرض أولا BFS لا تصلح إلا للمخططات غير الموزونة unweighted graphs، أما بالنسبة للمخططات الموزونة فسنحتاج إلى <a href="https://wiki.hsoub.com/Algorithms/Dijkstra" rel="external">خوارزمية ديكسترا</a>. وبالنسبة لدورات الأضلاع السلبية negative edge cycles فسنحتاج إلى <a href="https://wiki.hsoub.com/Algorithms/Bellman_Ford" rel="external">خوارزمية بِِلمان - فورد</a>. هناك مسألة أخرى ينبغي الانتباه إليها، وهي أنّ هذه الخوارزمية مخصّصة لإيجاد أقصر مسار من مصدر واحد، فإذا أردت العثور على المسافة من كل عقدة إلى جميع العقد الأخرى ستحتاج إلى استخدام خوارزمية بِلمان - فورد كذلك.
</p>

<h3>
	البحث عن المكونات المتصلة لمخطط غير موجهة باستخدام خوارزمية BFS
</h3>

<p>
	يمكن استخدام خوارزمية BFS للعثور على المكونات المتصلة connected components في مخطط غير موجه، ويمكن استخدامها أيضًا للتحقق مما إذا كان المخطط متصلًا أم لا، وسنفترض فيما يلي أنّنا نتعامل مع مخططات غير موجهة.
</p>

<p>
	<strong>تعريف</strong>: يكون المخطط متصلًا connected إذا كان هناك مسار بين كل زوج من الحروف في المخطط. هذا مثال على مخطط متصل:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="88625" href="https://academy.hsoub.com/uploads/monthly_2022_01/10.png.13f52a8798bf4906e47f615d15919e3e.png" rel=""><img alt="10.png" class="ipsImage ipsImage_thumbnailed" data-fileid="88625" data-unique="fh4g7cxe4" src="https://academy.hsoub.com/uploads/monthly_2022_01/10.png.13f52a8798bf4906e47f615d15919e3e.png" style="width: 300px; height: auto;"></a>
</p>

<p>
	المخطط التالي غير متصل، ولكن يحتوي على مكوّنتين متصلتين:
</p>

<ol>
<li>
		المكونة المتصل الأولى: {a، b، c، d، e} .
	</li>
	<li>
		المكون المتصلة الثانية: {f}
	</li>
</ol>
<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="88630" href="https://academy.hsoub.com/uploads/monthly_2022_01/gbTR8.png.5c60e816c45851ba9e60366d63afb2c3.png" rel=""><img alt="gbTR8.png" class="ipsImage ipsImage_thumbnailed" data-fileid="88630" data-unique="sh98275lf" src="https://academy.hsoub.com/uploads/monthly_2022_01/gbTR8.png.5c60e816c45851ba9e60366d63afb2c3.png" style="width: 300px; height: auto;"></a>
</p>

<p>
	خوارزمية BFS هي خوارزمية لاجتياز المخططات، لذا إن بدأت الخوارزمية من عقدة مصدرية ما وانتقلت من عقدة إلى أخرى، ولم تترك عقدة إلا زارتها قبل انتهائها، فيكون المخطط في هذه الحالة متصلًا، أما إن بقيت بعض بعض العقد غير مُزارة، فسيكون المخطط غير متصل. انظر المثال التوضيحي التالي للخوارزمية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_39" style="">
<span class="pln">boolean isConnected</span><span class="pun">(</span><span class="typ">Graph</span><span class="pln"> g</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln"> 
 BFS</span><span class="pun">(</span><span class="pln">v</span><span class="pun">)</span><span class="pln"> </span><span class="pun">//</span><span class="pln"> </span><span class="pun">هي</span><span class="pln"> </span><span class="pun">عقدة</span><span class="pln"> </span><span class="pun">مصدرية</span><span class="pln"> v 
   </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">allVisited</span><span class="pun">(</span><span class="pln">g</span><span class="pun">))</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> true</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> false</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وهذا تطبيق بلغة C للتحقق مما إذا كان مخططًا متصلًأ غير موجّه أم لا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_41" style="">
<span class="com">#include&lt;stdio.h&gt;</span><span class="pln">
</span><span class="com">#include&lt;stdlib.h&gt;</span><span class="pln">
</span><span class="com">#define MAXVERTICES 100   </span><span class="pln">
void enqueue</span><span class="pun">(</span><span class="pln">int</span><span class="pun">);</span><span class="pln">
int deque</span><span class="pun">();</span><span class="pln">
int isConnected</span><span class="pun">(</span><span class="pln">char </span><span class="pun">**</span><span class="pln">graph</span><span class="pun">,</span><span class="pln">int noOfVertices</span><span class="pun">);</span><span class="pln">
void BFS</span><span class="pun">(</span><span class="pln">char </span><span class="pun">**</span><span class="pln">graph</span><span class="pun">,</span><span class="pln">int vertex</span><span class="pun">,</span><span class="pln">int noOfVertices</span><span class="pun">);</span><span class="pln">   
int count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
struct node
</span><span class="pun">{</span><span class="pln">
   int v</span><span class="pun">;</span><span class="pln">
   struct node </span><span class="pun">*</span><span class="pln">next</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
typedef struct node </span><span class="typ">Node</span><span class="pun">;</span><span class="pln">
typedef struct node </span><span class="pun">*</span><span class="typ">Nodeptr</span><span class="pun">;</span><span class="pln">
</span><span class="typ">Nodeptr</span><span class="pln"> </span><span class="typ">Qfront</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> NULL</span><span class="pun">;</span><span class="pln">
</span><span class="typ">Nodeptr</span><span class="pln"> </span><span class="typ">Qrear</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> NULL</span><span class="pun">;</span><span class="pln">
char </span><span class="pun">*</span><span class="pln">visited</span><span class="pun">;//</span><span class="pln"> </span><span class="pun">مصفوفة</span><span class="pln"> </span><span class="pun">لتتبع</span><span class="pln"> </span><span class="pun">العقد</span><span class="pln"> </span><span class="pun">المُزارة</span><span class="pln">
int main</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   int n</span><span class="pun">,</span><span class="pln">e</span><span class="pun">;//</span><span class="pln"> </span><span class="pun">‫</span><span class="pln"> </span><span class="pun">يمثل</span><span class="pln"> n </span><span class="pun">عدد</span><span class="pln"> </span><span class="pun">الحروف،</span><span class="pln"> </span><span class="pun">ويمثل</span><span class="pln"> e </span><span class="pun">عدد</span><span class="pln"> </span><span class="pun">الأضلاع</span><span class="pln">
   int i</span><span class="pun">,</span><span class="pln">j</span><span class="pun">;</span><span class="pln">
   char </span><span class="pun">**</span><span class="pln">graph</span><span class="pun">;//</span><span class="pln">adjacency matrix
   printf</span><span class="pun">(</span><span class="str">"Enter number of vertices:"</span><span class="pun">);</span><span class="pln">
   scanf</span><span class="pun">(</span><span class="str">"%d"</span><span class="pun">,&amp;</span><span class="pln">n</span><span class="pun">);</span><span class="pln">
   </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">n </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> n </span><span class="pun">&gt;</span><span class="pln"> MAXVERTICES</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
    fprintf</span><span class="pun">(</span><span class="pln">stderr</span><span class="pun">,</span><span class="pln"> </span><span class="str">"Please enter a valid positive integer from 1 to %d"</span><span class="pun">,</span><span class="pln">MAXVERTICES</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   graph </span><span class="pun">=</span><span class="pln"> malloc</span><span class="pun">(</span><span class="pln">n </span><span class="pun">*</span><span class="pln"> sizeof</span><span class="pun">(</span><span class="pln">char </span><span class="pun">*));</span><span class="pln">
   visited </span><span class="pun">=</span><span class="pln"> malloc</span><span class="pun">(</span><span class="pln">n</span><span class="pun">*</span><span class="pln">sizeof</span><span class="pun">(</span><span class="pln">char</span><span class="pun">));</span><span class="pln">
   </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> n</span><span class="pun">;++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       graph</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> malloc</span><span class="pun">(</span><span class="pln">n</span><span class="pun">*</span><span class="pln">sizeof</span><span class="pun">(</span><span class="pln">int</span><span class="pun">));</span><span class="pln">
       visited</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'N'</span><span class="pun">;//</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> </span><span class="pun">البداية،</span><span class="pln"> </span><span class="pun">تكون</span><span class="pln"> </span><span class="pun">جميع</span><span class="pln"> </span><span class="pun">العقد</span><span class="pln"> </span><span class="pun">غير</span><span class="pln"> </span><span class="pun">مزارة</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">j </span><span class="pun">&lt;</span><span class="pln"> n</span><span class="pun">;++</span><span class="pln">j</span><span class="pun">)</span><span class="pln">
           graph</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   printf</span><span class="pun">(</span><span class="str">"enter number of edges and then enter them in pairs:"</span><span class="pun">);</span><span class="pln">
   scanf</span><span class="pun">(</span><span class="str">"%d"</span><span class="pun">,&amp;</span><span class="pln">e</span><span class="pun">);</span><span class="pln">
   </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> e</span><span class="pun">;++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       int u</span><span class="pun">,</span><span class="pln">v</span><span class="pun">;</span><span class="pln">
       scanf</span><span class="pun">(</span><span class="str">"%d%d"</span><span class="pun">,&amp;</span><span class="pln">u</span><span class="pun">,&amp;</span><span class="pln">v</span><span class="pun">);</span><span class="pln">
       graph</span><span class="pun">[</span><span class="pln">u</span><span class="pun">-</span><span class="lit">1</span><span class="pun">][</span><span class="pln">v</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
       graph</span><span class="pun">[</span><span class="pln">v</span><span class="pun">-</span><span class="lit">1</span><span class="pun">][</span><span class="pln">u</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">   

   </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">isConnected</span><span class="pun">(</span><span class="pln">graph</span><span class="pun">,</span><span class="pln">n</span><span class="pun">))</span><span class="pln">
       printf</span><span class="pun">(</span><span class="str">"The graph is connected"</span><span class="pun">);</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln"> printf</span><span class="pun">(</span><span class="str">"The graph is NOT connected\n"</span><span class="pun">);</span><span class="pln">     
</span><span class="pun">}</span><span class="pln">
void enqueue</span><span class="pun">(</span><span class="pln">int vertex</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">if</span><span class="pun">(</span><span class="typ">Qfront</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> NULL</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">Qfront</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> malloc</span><span class="pun">(</span><span class="pln">sizeof</span><span class="pun">(</span><span class="typ">Node</span><span class="pun">));</span><span class="pln">
       </span><span class="typ">Qfront</span><span class="pun">-&gt;</span><span class="pln">v </span><span class="pun">=</span><span class="pln"> vertex</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">Qfront</span><span class="pun">-&gt;</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> NULL</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">Qrear</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Qfront</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">Nodeptr</span><span class="pln"> newNode </span><span class="pun">=</span><span class="pln"> malloc</span><span class="pun">(</span><span class="pln">sizeof</span><span class="pun">(</span><span class="typ">Node</span><span class="pun">));</span><span class="pln">
       newNode</span><span class="pun">-&gt;</span><span class="pln">v </span><span class="pun">=</span><span class="pln"> vertex</span><span class="pun">;</span><span class="pln">
       newNode</span><span class="pun">-&gt;</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> NULL</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">Qrear</span><span class="pun">-&gt;</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> newNode</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">Qrear</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> newNode</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
int deque</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">if</span><span class="pun">(</span><span class="typ">Qfront</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> NULL</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       printf</span><span class="pun">(</span><span class="str">"Q is empty , returning -1\n"</span><span class="pun">);</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       int v </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Qfront</span><span class="pun">-&gt;</span><span class="pln">v</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">Nodeptr</span><span class="pln"> temp</span><span class="pun">=</span><span class="pln"> </span><span class="typ">Qfront</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">if</span><span class="pun">(</span><span class="typ">Qfront</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="typ">Qrear</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="typ">Qfront</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Qfront</span><span class="pun">-&gt;</span><span class="pln">next</span><span class="pun">;</span><span class="pln">
           </span><span class="typ">Qrear</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> NULL</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">else</span><span class="pln">
           </span><span class="typ">Qfront</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Qfront</span><span class="pun">-&gt;</span><span class="pln">next</span><span class="pun">;</span><span class="pln">
       free</span><span class="pun">(</span><span class="pln">temp</span><span class="pun">);</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> v</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
int isConnected</span><span class="pun">(</span><span class="pln">char </span><span class="pun">**</span><span class="pln">graph</span><span class="pun">,</span><span class="pln">int noOfVertices</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   int i</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">//</span><span class="pln"> </span><span class="pun">نختار</span><span class="pln"> </span><span class="pun">العقدة</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">لتكون</span><span class="pln"> </span><span class="pun">عقدة</span><span class="pln"> </span><span class="pun">مصدرية</span><span class="pln">
   BFS</span><span class="pun">(</span><span class="pln">graph</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="pln">noOfVertices</span><span class="pun">);</span><span class="pln">
   </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> noOfVertices</span><span class="pun">;++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">visited</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'N'</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;//</span><span class="lit">0</span><span class="pln"> implies false</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;//</span><span class="lit">1</span><span class="pln"> implies true</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
void BFS</span><span class="pun">(</span><span class="pln">char </span><span class="pun">**</span><span class="pln">graph</span><span class="pun">,</span><span class="pln">int v</span><span class="pun">,</span><span class="pln">int noOfVertices</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">       
   int i</span><span class="pun">,</span><span class="pln">vertex</span><span class="pun">;</span><span class="pln">
   visited</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Y'</span><span class="pun">;</span><span class="pln">
   enqueue</span><span class="pun">(</span><span class="pln">v</span><span class="pun">);</span><span class="pln">   
   </span><span class="kwd">while</span><span class="pun">((</span><span class="pln">vertex </span><span class="pun">=</span><span class="pln"> deque</span><span class="pun">())</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">           
       </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> noOfVertices</span><span class="pun">;++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">graph</span><span class="pun">[</span><span class="pln">vertex</span><span class="pun">][</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> visited</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'N'</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               enqueue</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln">
               visited</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">'Y'</span><span class="pun">;</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	للعثور على جميع المكونات المتصلة لمخطط غير موجه، يكفي أن نضيف سطرين إلى شيفرة الدالة BFS. الفكرة هي أن نستدعي الدالة BFS إلى أن تُزار جميع الحروف.
</p>

<p>
	هذا هو السطر الأول، المتغير <code>count</code> هو متغير عام مهيء على القيمة 0، وهذا السطر يوضع في بداية دالة BFS:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_43" style="">
<span class="pln">printf</span><span class="pun">(</span><span class="str">"\nConnected component %d\n"</span><span class="pun">,++</span><span class="pln">count</span><span class="pun">);</span><span class="pln"> </span></pre>

<p>
	وهذا هو السطر الثاني، اجعله في بداية حلقة <code>while</code> في دالة <code>BFS</code>:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_45" style="">
<span class="pln">printf</span><span class="pun">(</span><span class="str">"%d "</span><span class="pun">,</span><span class="pln">vertex</span><span class="pun">+</span><span class="lit">1</span><span class="pun">);</span><span class="pln"> </span></pre>

<p>
	نعرّف الآن الدالة التالية:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_47" style="">
<span class="pln">void listConnectedComponents</span><span class="pun">(</span><span class="pln">char </span><span class="pun">**</span><span class="pln">graph</span><span class="pun">,</span><span class="pln">int noOfVertices</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   int i</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> noOfVertices</span><span class="pun">;++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">visited</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="str">'N'</span><span class="pun">)</span><span class="pln">
           BFS</span><span class="pun">(</span><span class="pln">graph</span><span class="pun">,</span><span class="pln">i</span><span class="pun">,</span><span class="pln">noOfVertices</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	خوارزمية البحث بالعمق أولا Depth First Search
</h2>

<p>
	خوارزمية البحث بالعمق أولًا DFS هي خوارزمية لتسلق مخطط أو البحث فيها، وتبدأ من الجذر وتستكشف العقد على طول كل فرع وتتعمق فيه إلى آخر حدّ قبل أن ترتد backtrack، وقد استُخدِمت نسخة أولية من هذه الخوارزمية من قبل عالم الرياضيات الفرنسي تشارلز بيير Tr‎é‎maux في القرن التاسع عشر لإيجاد حلول للمتاهات.
</p>

<p>
	البحث بالعمق أولًا هي طريقة تحاول العثور على جميع العقد التي يمكن الوصول إليها من العقدة المصدر، وتجتاز خوارزمية DFS عقد مُكوّنة متصلة connected component ما من مخطط خوارزمية البحث بالعرض أولًا، ثم تعرّف شجرة ممتدة spanning tree. كذلك تستكشف خوارزمية البحث بالعمق أولا كل الأضلاع بطريقة منهجية. إذ تبدأ من العقدة المصدرية، وبمجرد الوصول إلى عقدة من المخطط تبدأ خوارزمية DFS في الاستكشاف انطلاقًا منها (على عكس خوارزمية BFS، التي تضعها في طابور لأجل استكشافها لاحقًا).
</p>

<p>
	انظر المثال التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="88631" href="https://academy.hsoub.com/uploads/monthly_2022_01/JJkTC.png.3aec495945aca56c89db51099cbaf4d0.png" rel=""><img alt="JJkTC.png" class="ipsImage ipsImage_thumbnailed" data-fileid="88631" data-unique="2bbbmf4gf" src="https://academy.hsoub.com/uploads/monthly_2022_01/JJkTC.png.3aec495945aca56c89db51099cbaf4d0.png" style="width: 300px; height: auto;"></a>
</p>

<p>
	نجتاز المخطط باستخدام القواعد التالية:
</p>

<ul>
<li>
		نبدأ من المصدر.
	</li>
	<li>
		لن نزور أيّ عقدة مرتين.
	</li>
	<li>
		نلوّن العقد التي لم نزرها بعد باللون الأبيض.
	</li>
	<li>
		نلوّن بالرمادي العقد التي زرناها ولكن لم نزر بعد جميع العقد المتفرّعة منها.
	</li>
	<li>
		نلوّن بالأسود العقد التي اجتزناها بالكامل هي والعقد المتفرعة منها.
	</li>
</ul>
<p>
	تبيّن الرسوم التالية هذه الخطوات:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="88628" href="https://academy.hsoub.com/uploads/monthly_2022_01/AI6W0.png.9bb3cc838e579884d7167c56c3b11121.png" rel=""><img alt="AI6W0.png" class="ipsImage ipsImage_thumbnailed" data-fileid="88628" data-unique="713yzbtvx" src="https://academy.hsoub.com/uploads/monthly_2022_01/AI6W0.png.9bb3cc838e579884d7167c56c3b11121.png" style="width: 500px; height: auto;"></a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="88629" href="https://academy.hsoub.com/uploads/monthly_2022_01/f3T4C.png.56bbce548652e034f9aec5ebc5959cbe.png" rel=""><img alt="f3T4C.png" class="ipsImage ipsImage_thumbnailed" data-fileid="88629" data-unique="wo8sr8dgk" src="https://academy.hsoub.com/uploads/monthly_2022_01/f3T4C.png.56bbce548652e034f9aec5ebc5959cbe.png" style="width: 500px; height: auto;"></a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="88633" href="https://academy.hsoub.com/uploads/monthly_2022_01/MXRDH.png.f2956456574f6ba813757753e5303698.png" rel=""><img alt="MXRDH.png" class="ipsImage ipsImage_thumbnailed" data-fileid="88633" data-unique="qsr2uuiay" src="https://academy.hsoub.com/uploads/monthly_2022_01/MXRDH.png.f2956456574f6ba813757753e5303698.png" style="width: 500px; height: auto;"></a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="88635" href="https://academy.hsoub.com/uploads/monthly_2022_01/Piasa.png.be0bb64468b76c292a9e96ddf7cf9b91.png" rel=""><img alt="Piasa.png" class="ipsImage ipsImage_thumbnailed" data-fileid="88635" data-unique="mjvrrxzoa" src="https://academy.hsoub.com/uploads/monthly_2022_01/Piasa.png.be0bb64468b76c292a9e96ddf7cf9b91.png" style="width: 500px; height: auto;"></a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="88636" href="https://academy.hsoub.com/uploads/monthly_2022_01/RJ76g.png.bcbc4baa65a2e22b71477ab178ba7693.png" rel=""><img alt="RJ76g.png" class="ipsImage ipsImage_thumbnailed" data-fileid="88636" data-unique="0d3h2k54h" src="https://academy.hsoub.com/uploads/monthly_2022_01/RJ76g.png.bcbc4baa65a2e22b71477ab178ba7693.png" style="width: 500px; height: auto;"></a>
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="88626" href="https://academy.hsoub.com/uploads/monthly_2022_01/4W5Bz.png.d28e2ac28d9b9d7a0dda233bd27426b4.png" rel=""><img alt="4W5Bz.png" class="ipsImage ipsImage_thumbnailed" data-fileid="88626" data-unique="w0urm2ypk" src="https://academy.hsoub.com/uploads/monthly_2022_01/4W5Bz.png.d28e2ac28d9b9d7a0dda233bd27426b4.png" style="width: 300px; height: auto;"></a>
</p>

<p>
	الكلمة المفتاحية التي تهمنا والتي نراها فيما سبق هي الضلع الخلفي backedge، فالضلع 5-1 هو ضلع خلفي backedge، لأننا لم ننته بعد من العقدة 1، فالعودة إلى العقدة المصدرية 1 يعني وجود دورة في المخطط. إذا كنا نستطيع الانتقال من عقدة رمادية إلى أخرى في خوارزمية البحث بالعمق أولا، فذلك دليل على أنّ المخطط يحتوي على دورة، وهذه إحدى طرق رصد الدورات في المخططات.
</p>

<p>
	يمكننا أن نجعل أيّ ضلع في الدورة كضلع خلفي اعتمادًا على العقدة المصدرية، وترتيب زيارة العقد. على سبيل المثال: لو انتقلنا إلى العقد 5 من العقدة 1 أولا، لوجدنا أنّ الضلع 2-1 أصبح ضلعًا خلفيًا.
</p>

<p>
	تسمى الأضلاع التي تنتقل من عقدة رمادية إلى عقدة بيضاء أضلاع الشجرة أو أضلاعًا شجرية tree edge، وإذا أبقينا على أضلاع الشجرة وحذفنا الأضلاع الأخرى، فسوف نحصل على <strong>شجرة البحث بالعمق أولا DFS</strong>.
</p>

<p>
	إذا استطعنا زيارة عقدة مزارة سابقًا في مخطط غير موجه فذلك يعني وجود ضلع خلفي، أمّا بالنسبة للمخططات الموجّهة فسيكون علينا أن نتحقق من الألوان، حيث يكون الضلع خلفيًا فقط إذا كان بمقدورنا الانتقال من عقدة رمادية إلى عقدة رمادية أخرى.
</p>

<p>
	أيضًا، في خوارزمية البحث بالعمق أولا، نستطيع تخزين علامات زمنية timestamps لكل عقدة، تخزن هذه العلامات الزمنية معلومات عما حدث للعقد أثناء المعالجة، ونخزّنها في مصفوفتين، مصفوفة f لتخزين أوقات الانتهاء، ومصفوفة d لتخزين أوقات استكشاف العقد:
</p>

<ol>
<li>
		عندما يتغيّر لون العقدة v من الأبيض إلى الرمادي نسجّل الوقت في الموضع <strong>d[v]‎‎</strong>.
	</li>
	<li>
		عند يتغيّر لون عقدة v من الرمادي إلى الأسود، نسجّل الوقت في <strong>f [v]‎‎</strong>.
	</li>
</ol>
<p>
	سيبدو المثال التوضيحي لتخزين العلامات الزمنية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_56" style="">
<span class="typ">Procedure</span><span class="pln"> DFS</span><span class="pun">(</span><span class="pln">G</span><span class="pun">):</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> each node u </span><span class="kwd">in</span><span class="pln"> V</span><span class="pun">[</span><span class="pln">G</span><span class="pun">]</span><span class="pln">
   color</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> white
   parent</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> NULL
end </span><span class="kwd">for</span><span class="pln">
time </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> each node u </span><span class="kwd">in</span><span class="pln"> V</span><span class="pun">[</span><span class="pln">G</span><span class="pun">]</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> color</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> white
       DFS</span><span class="pun">-</span><span class="typ">Visit</span><span class="pun">(</span><span class="pln">u</span><span class="pun">)</span><span class="pln">
   end </span><span class="kwd">if</span><span class="pln">
end </span><span class="kwd">for</span><span class="pln">
</span><span class="typ">Procedure</span><span class="pln"> DFS</span><span class="pun">-</span><span class="typ">Visit</span><span class="pun">(</span><span class="pln">u</span><span class="pun">):</span><span class="pln">
color</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> gray
time </span><span class="pun">:=</span><span class="pln"> time </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
d</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> time
</span><span class="kwd">for</span><span class="pln"> each node v adjacent to u
   </span><span class="kwd">if</span><span class="pln"> color</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> white
       parent</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> u
       DFS</span><span class="pun">-</span><span class="typ">Visit</span><span class="pun">(</span><span class="pln">v</span><span class="pun">)</span><span class="pln">
   end </span><span class="kwd">if</span><span class="pln">
end </span><span class="kwd">for</span><span class="pln">
color</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> black
time </span><span class="pun">:=</span><span class="pln"> time </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
f</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> time</span></pre>

<p>
	<strong>التعقيد</strong>: تُزار كل عقدة وكل ضلع مرة واحدة، لذا فإن تعقيد خوارزمية DFS هو O (V + E)‎‎، حيث يمثّل V عدد العقد في المخطط، ويمثل E عدد الأضلاع.
</p>

<p>
	التطبيقات على خوارزمية البحث بالعمق أولًا كثيرة، منها على سبيل المثال لا الحصر:
</p>

<ul>
<li>
		العثور على أقصر مسار بين كل زوج من العقد في مخطط غير موجه.
	</li>
	<li>
		رصد الدورات في المخططات.
	</li>
	<li>
		العثور على المسارات.
	</li>
	<li>
		الترتيب التخطيطي (الطوبولوجي).
	</li>
	<li>
		التحقق ممّا إذا كان المخطط <a href="https://ar.wikipedia.org/wiki/%D9%85%D8%AE%D8%B7%D8%B7_%D8%AB%D9%86%D8%A7%D8%A6%D9%8A" rel="external nofollow">ثنائي التجزئة</a>.
	</li>
	<li>
		العثور على المكونات شديدة الاتصال Strongly Connected Component.
	</li>
	<li>
		حل الألغاز التي لها حل واحد.
	</li>
</ul>
<h2>
	خوارزمية البائع المتجول
</h2>

<p>
	إن إنشاء مسار يمر عبر كل رأس من رؤوس المخطط مرة واحدة يكافئ ترتيبًا يرتّب حروف ذلك المخطط، ويمكننا استغلال هذه الخاصية لحساب التكلفة الدنيا لعبور كل رأس مرة واحدة بالضبط عبر تجريب كل التبديلات لمجموعة الأعداد من <code>‎1‎</code> إلى <code>‎N‎</code>، وعددها <code>‎N!‎</code>. انظر الشيفرة العامة لهذا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_58" style="">
<span class="pln">minimum </span><span class="pun">=</span><span class="pln"> INF
</span><span class="kwd">for</span><span class="pln"> all permutations P   </span><span class="pun">//</span><span class="pln"> </span><span class="pun">كل</span><span class="pln"> </span><span class="pun">التبديلات</span><span class="pln">
   current </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">                               
   </span><span class="kwd">for</span><span class="pln"> i </span><span class="kwd">from</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> to N</span><span class="pun">-</span><span class="lit">2</span><span class="pln">
       </span><span class="pun">//</span><span class="pln"> </span><span class="pun">أضف</span><span class="pln"> </span><span class="pun">تكلفة</span><span class="pln"> </span><span class="pun">الانتقال</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">عقدة</span><span class="pln"> </span><span class="pun">إلى</span><span class="pln"> </span><span class="pun">إلى</span><span class="pln"> </span><span class="pun">أخرى</span><span class="pln">
       current </span><span class="pun">=</span><span class="pln"> current </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">P</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]][</span><span class="pln">P</span><span class="pun">[</span><span class="pln">i</span><span class="pun">+</span><span class="lit">1</span><span class="pun">]]</span><span class="pln">  

   </span><span class="pun">//</span><span class="pln"> </span><span class="pun">أضف</span><span class="pln"> </span><span class="pun">تكلفة</span><span class="pln"> </span><span class="pun">الانتقال</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">العقدة</span><span class="pln"> </span><span class="pun">الأخيرة</span><span class="pln"> </span><span class="pun">إلى</span><span class="pln"> </span><span class="pun">إلى</span><span class="pln"> </span><span class="pun">العقدة</span><span class="pln"> </span><span class="pun">الأولى</span><span class="pln">
   current </span><span class="pun">=</span><span class="pln"> current </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">P</span><span class="pun">[</span><span class="pln">N</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]][</span><span class="pln">P</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]]</span><span class="pln">      

   </span><span class="kwd">if</span><span class="pln"> current </span><span class="pun">&lt;</span><span class="pln"> minimum                       </span><span class="pun">//</span><span class="pln"> </span><span class="pun">إن</span><span class="pln"> </span><span class="pun">كان</span><span class="pln"> </span><span class="pun">ذلك</span><span class="pln"> </span><span class="pun">ضروريا</span><span class="pln"> minimum  </span><span class="pun">حدِّث</span><span class="pln">
       minimum </span><span class="pun">=</span><span class="pln"> current

output minimum</span></pre>

<p>
	<strong>التعقيد الزمني</strong>: هناك <code>‎N!‎</code> تبديلة ينبغي معالجتها، وحساب تكلفة كل مسار تستغرق <code>‎O(N)‎</code>، من ثم فإنّ هذه الخوارزمية تستغرق مدة <code>O ‎(‎N ‎*‎ N!)‎</code>.
</p>

<h3>
	استخدام البرمجة الديناميكية
</h3>

<p>
	انظر المسار:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_61" style="">
<span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">3</span><span class="pun">,</span><span class="lit">4</span><span class="pun">,</span><span class="lit">6</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">5</span><span class="pun">,</span><span class="lit">7</span><span class="pun">)</span></pre>

<p>
	والمسار
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_63" style="">
<span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">3</span><span class="pun">,</span><span class="lit">5</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">6</span><span class="pun">,</span><span class="lit">7</span><span class="pun">,</span><span class="lit">4</span><span class="pun">)</span></pre>

<p>
	تبقى تكلفة الانتقال من العقدة <code>‎1‎</code> إلى العقدة <code>‎2‎</code> ثمّ إلى العقدة <code>‎3‎</code> كما هي، لذا ليس علينا إعادة حسابها، إذ يمكن أن نحفظ هذه النتيجة لاستخدامها لاحقًا.
</p>

<p>
	لنفترض أنّ <code>‎dp[bitmask][vertex]‎</code> تمثل الحد الأدنى لتكلفة المسارات التي تعبر جميع الحروف التي قيمة البتّات المقابلة لها فيها <code>‎bitmask‎</code> تساوي <code>‎1‎</code>، والتي تنتهي عند الحرف <code>‎vertex‎</code>. على سبيل المثال:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_65" style="">
<span class="pln">dp</span><span class="pun">[</span><span class="lit">12</span><span class="pun">][</span><span class="lit">2</span><span class="pun">]</span><span class="pln">

   </span><span class="lit">12</span><span class="pln">   </span><span class="pun">=</span><span class="pln">   </span><span class="lit">1</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
               </span><span class="pun">^</span><span class="pln"> </span><span class="pun">^</span><span class="pln">
vertices</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">0</span></pre>

<p>
	نظرًا لأنّ <code>‎1100‎</code> هي التمثيل الثنائي لـ <code>12</code>، فإنّ <code>‎dp[12][2]‎</code> تمثل الانتقال عبر الحرفين <code>‎2‎</code> و <code>‎3‎</code> في المخطط عبر مسار ينتهي عند الحرف 2.
</p>

<p>
	هذا تطبيق على الخوارزمية بلغة C++‎:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_67" style="">
<span class="pln">int cost</span><span class="pun">[</span><span class="pln">N</span><span class="pun">][</span><span class="pln">N</span><span class="pun">];</span><span class="pln">                        </span><span class="pun">//</span><span class="pln"> </span><span class="pun">إن</span><span class="pln"> </span><span class="pun">كان</span><span class="pln"> </span><span class="pun">ذلك</span><span class="pln"> </span><span class="pun">ضروريا</span><span class="pln"> N </span><span class="pun">تعديل</span><span class="pln"> </span><span class="pun">قيمة</span><span class="pln">
int memo</span><span class="pun">[</span><span class="lit">1</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> N</span><span class="pun">][</span><span class="pln">N</span><span class="pun">];</span><span class="pln">                   </span><span class="pun">//</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">تهيئة</span><span class="pln"> </span><span class="pun">كل</span><span class="pln"> </span><span class="pun">العناصر</span><span class="pln"> </span><span class="pun">بالقيمة</span><span class="pln">
int TSP</span><span class="pun">(</span><span class="pln">int bitmask</span><span class="pun">,</span><span class="pln"> int pos</span><span class="pun">){</span><span class="pln">
   int cost </span><span class="pun">=</span><span class="pln"> INF</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">bitmask </span><span class="pun">==</span><span class="pln"> </span><span class="pun">((</span><span class="lit">1</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> N</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)){</span><span class="pln">      </span><span class="pun">//</span><span class="pln"> </span><span class="pun">استكشاف</span><span class="pln"> </span><span class="pun">كل</span><span class="pln"> </span><span class="pun">العقد</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">pos</span><span class="pun">][</span><span class="lit">0</span><span class="pun">];</span><span class="pln">             </span><span class="pun">//</span><span class="pln"> </span><span class="pun">تكلفة</span><span class="pln"> </span><span class="pun">الرجوع</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">memo</span><span class="pun">[</span><span class="pln">bitmask</span><span class="pun">][</span><span class="pln">pos</span><span class="pun">]</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">){</span><span class="pln">       </span><span class="pun">//</span><span class="pln"> </span><span class="pun">إن</span><span class="pln"> </span><span class="pun">كنا</span><span class="pln"> </span><span class="pun">قد</span><span class="pln"> </span><span class="pun">حسبنا</span><span class="pln"> </span><span class="pun">هذه</span><span class="pln"> </span><span class="pun">القيمة</span><span class="pln"> </span><span class="pun">سابقا</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> memo</span><span class="pun">[</span><span class="pln">bitmask</span><span class="pun">][</span><span class="pln">pos</span><span class="pun">];</span><span class="pln">       </span><span class="pun">//</span><span class="pln"> </span><span class="pun">فسنعيد</span><span class="pln"> </span><span class="pun">القيمة</span><span class="pln"> </span><span class="pun">السابقة،</span><span class="pln"> </span><span class="pun">فلا</span><span class="pln"> </span><span class="pun">داعي</span><span class="pln"> </span><span class="pun">لإعادة</span><span class="pln"> </span><span class="pun">حسابها</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">int i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> N</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">){</span><span class="pln">     
       </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">((</span><span class="pln">bitmask </span><span class="pun">&amp;</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> i</span><span class="pun">))</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">){</span><span class="pln">  </span><span class="pun">//إن</span><span class="pln"> </span><span class="pun">لم</span><span class="pln"> </span><span class="pun">تُكن</span><span class="pln"> </span><span class="pun">العقدة</span><span class="pln"> </span><span class="pun">مُزارة</span><span class="pln"> </span><span class="pun">بعد</span><span class="pln">
           cost </span><span class="pun">=</span><span class="pln"> min</span><span class="pun">(</span><span class="pln">cost</span><span class="pun">,</span><span class="pln">TSP</span><span class="pun">(</span><span class="pln">bitmask </span><span class="pun">|</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">,</span><span class="pln"> i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">pos</span><span class="pun">][</span><span class="pln">i</span><span class="pun">]);</span><span class="pln">   </span><span class="pun">//</span><span class="pln"> </span><span class="pun">زيارة</span><span class="pln"> </span><span class="pun">العقدة</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   memo</span><span class="pun">[</span><span class="pln">bitmask</span><span class="pun">][</span><span class="pln">pos</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> cost</span><span class="pun">;</span><span class="pln">           </span><span class="pun">//</span><span class="pln"> </span><span class="pun">حفظ</span><span class="pln"> </span><span class="pun">النتيجة</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> cost</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">//</span><span class="typ">Call</span><span class="pln"> TSP</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">0</span><span class="pun">)</span></pre>

<p>
	قد يكون هذا السطر مبهمًا، لذا سنفصِّله من أجل التوضيح:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_69" style="">
<span class="pln">cost </span><span class="pun">=</span><span class="pln"> min</span><span class="pun">(</span><span class="pln">cost</span><span class="pun">,</span><span class="pln">TSP</span><span class="pun">(</span><span class="pln">bitmask </span><span class="pun">|</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">,</span><span class="pln"> i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">pos</span><span class="pun">][</span><span class="pln">i</span><span class="pun">]);</span></pre>

<p>
	هنا، تعيّن العبارة <code>‎bitmask | (1 &lt;&lt; i)‎</code> البتة رقم <code>i</code> في <code>‎bitmask‎</code> وتعطيها القيمة 1 دلالة على أنّ الحرف رقم <code>i</code> قد تمت زيارته.
</p>

<p>
	تمثّل <code>i</code> الموضوعة بعد الفاصلة قيمة الموضع <code>pos</code> الجديد في هذا الاستدعاء، والذي يمثل الحرف الأخير الجديد. وتضيف العبارة‎<code>cost[pos][i‎]‎</code> تكلفة الانتقال من الحرف الموجود في الموضع <code>pos</code> إلى الحرف <code>i</code>.
</p>

<p>
	يُحدّث هذا السطر قيمة <code>‎cost‎</code>، ويعطيها أدنى قيمة ممكنة للمرور عبر كل الحروف الأخرى التي لم تُزر بعد.
</p>

<p>
	<strong>التعقيد الزمني</strong>: هناك <code>‎2^N‎</code> قيمة ممكنة لـ <code>‎bitmask‎</code> و <code>‎N‎</code> قيمة ممكنة لـ <code>‎pos‎</code> في الدالة <code>‎TSP(bitmask,pos)‎</code>. ويستغرق تنفيذ كل دالة <code>‎O(N)‎</code> (الحلقة <code>for</code>). وبالتالي يستغرق هذا التطبيق إجمالا مدة <code>‎O(N^2 * 2^N)‎</code> لإيجاد الحل النهائي.
</p>

<h2>
	خوارزمية كثيرة الحدود ومقيدة زمنيًا للعثور على أصغر غطاء رأسي
</h2>

<p>
	<strong>تعريف</strong>: ليكن <strong>G</strong> مخطط، و <strong>C</strong> مجموعة من حروفها، فنقول أنّ <strong>C</strong> غطاء رأسي للمخطط <strong>G</strong> إن كانت تحتوي طرفًا واحدًا على الأقل من كل ضلع من أضلاع المخطط. وفي هذه الفقرة نستعرض خوارزمية كثيرة الحدود للحصول على أصغر <a href="https://en.wikipedia.org/wiki/Vertex_cover" rel="external nofollow">غطاء رأسي</a> vertex cover لمخطط متصل غير موجّه.
</p>

<p>
	التعقيد الزمني لهذه الخوارزمية يساوي O (n2)‎‎.
</p>

<p>
	هذا مثال توضيحي لخوارزمية أصغر غطاء رأسي، إذ نُدخل إليها مخططًا متصلًا <strong>G</strong> لتعيد لنا مجموعة <strong>C</strong> تمثّل أصغر غطاء رأسي لهذا المخطط.
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_590_71" style="">
<span class="typ">Set</span><span class="pln"> C </span><span class="pun">&lt;-</span><span class="pln"> new </span><span class="typ">Set</span><span class="pun">&lt;</span><span class="typ">Vertex</span><span class="pun">&gt;()</span><span class="pln">
</span><span class="typ">Set</span><span class="pln"> X </span><span class="pun">&lt;-</span><span class="pln"> new </span><span class="typ">Set</span><span class="pun">&lt;</span><span class="typ">Vertex</span><span class="pun">&gt;()</span><span class="pln">
X </span><span class="pun">&lt;-</span><span class="pln"> G</span><span class="pun">.</span><span class="pln">getAllVerticiesArrangedDescendinglyByDegree</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> v </span><span class="kwd">in</span><span class="pln"> X </span><span class="kwd">do</span><span class="pln">
   </span><span class="typ">List</span><span class="pun">&lt;</span><span class="typ">Vertex</span><span class="pun">&gt;</span><span class="pln"> adjacentVertices1 </span><span class="pun">&lt;-</span><span class="pln"> G</span><span class="pun">.</span><span class="pln">getAdjacent</span><span class="pun">(</span><span class="pln">v</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">!</span><span class="pln">C contains any of adjacentVertices1 then

       C</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">v</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> vertex </span><span class="kwd">in</span><span class="pln"> C </span><span class="kwd">do</span><span class="pln">
   </span><span class="typ">List</span><span class="pun">&lt;</span><span class="pln">vertex</span><span class="pun">&gt;</span><span class="pln"> adjacentVertices2 </span><span class="pun">&lt;-</span><span class="pln"> G</span><span class="pun">.</span><span class="pln">adjacentVertecies</span><span class="pun">(</span><span class="pln">vertex</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> C contains any of adjacentVertices2 then

       C</span><span class="pun">.</span><span class="pln">remove</span><span class="pun">(</span><span class="pln">vertex</span><span class="pun">)</span><span class="pln">

</span><span class="kwd">return</span><span class="pln"> C</span></pre>

<p>
	يمكنك استخدام <a href="https://wiki.hsoub.com/Algorithms/bucket_sort" rel="external">ترتيب الدلو</a> لترتيب الحروف بحسب درجاتها، وبما أن القيمة القصوى للدرجات تساوي (n-1)، حيث يمثّل n عدد الحروف، فستستغرق عمليات الترتيب <code>O(n)‎‎</code>.
</p>

<p>
	ترجمة -بتصرّف- للفصول 41 و 42 و 44 و 53 من كتاب <a href="https://goalkicker.com/AlgorithmsBook/" rel="external nofollow">Algorithms Notes for Professionals</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D9%81%D9%8A-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-r1415/" rel="">خوارزميات البحث في النصوص</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D9%87%D8%A9-r1372/" rel="">تطبيقات الخوارزميات الشرهة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-%D8%AF%D9%8A%D9%83%D8%B3%D8%AA%D8%B1%D8%A7-dijkstra%E2%80%99s-algorithm-r1336/" rel="">خوارزمية ديكسترا Dijkstra’s Algorithm</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1427</guid><pubDate>Wed, 05 Jan 2022 16:00:00 +0000</pubDate></item><item><title>&#x62E;&#x648;&#x627;&#x631;&#x632;&#x645;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x628;&#x62D;&#x62B; &#x641;&#x64A; &#x627;&#x644;&#x646;&#x635;&#x648;&#x635;</title><link>https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D9%81%D9%8A-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-r1415/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_12/61cc1be186ed4_-01.jpg.178a2805afb4d970207d5f03bb304a8e.jpg" /></p>

<p>
	هذه المقالة تتمة للمقالة السابقة <a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D9%88%D8%A2%D9%84%D9%8A%D8%A9-%D8%B9%D9%85%D9%84%D9%87%D8%A7-r1414/" rel="">خوارزميات البحث وآلية عملها</a>، إذ نستعرض فيها بعض خوارزميات البحث، لكننا سنركز هذه المرة على البحث داخل النصوص، وسنستعرض اثنتين من أشهر خوارزميات البحث في النصوص، وهما خوارزمية رابين-كارب وخوارزمية KMP.
</p>

<h2>
	خوارزمية KMP
</h2>

<p>
	لنفترض أن لدينا نصًّا ونمطًا (سلسلة نصية)، ونريد أن نعرف ما إذا كان النمط موجودًا في النص أم لا. انظر المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_5954_8" style="">
<span class="pun">+-------+----+----+----+----+----+----+----+----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Index</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">5</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">6</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">7</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-------+----+----+----+----+----+----+----+----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="typ">Text</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> a  </span><span class="pun">|</span><span class="pln">  b  </span><span class="pun">|</span><span class="pln">  c  </span><span class="pun">|</span><span class="pln">  b  </span><span class="pun">|</span><span class="pln">  c  </span><span class="pun">|</span><span class="pln">  g  </span><span class="pun">|</span><span class="pln">  l    </span><span class="pun">|</span><span class="pln">  x  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-------+----+----+----+----+----+----+----+----+</span><span class="pln">

</span><span class="pun">+----------+----+----+----+----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Index</span><span class="pln">    </span><span class="pun">|</span><span class="pln"> </span><span class="lit">0</span><span class="pln">   </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> 
</span><span class="pun">+----------+----+----+----+----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Pattern</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> b   </span><span class="pun">|</span><span class="pln"> c   </span><span class="pun">|</span><span class="pln"> g   </span><span class="pun">|</span><span class="pln">  l   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----------+----+----+----+----+</span></pre>

<p>
	هذا النمط Pattern موجود فعلًا في النص Text، لذا يجب أن تعيد خوارزمية البحث العدد 3، وهو فهرس الموضع الذي يبدأ منه هذا النمط داخل النص.
</p>

<p>
	الطريقة البدهية هي أن نبدأ من الفهرس 0 في النص والفهرس 0 في النمط، ونوازن <code>Text[0]‎‎</code> و<code>Pattern[0]‎‎</code>. وبما أنهما غير متساويين، سننتقل إلى الفهرس التالي في النص، ونوازن <code>Text[1]‎‎</code> و<code>Pattern[0]‎‎</code>. وبما أنهما متطابقين، فإنّنا نزيد قيمة الفهرس في النمط والنص معًا.
</p>

<p>
	بعد ذلك نوازن <code>Text[2]‎‎</code> و<code>Pattern[1]‎‎</code> فنجد أنّهما متطابقين، ثم نتابع ونوازن الآن <code>Text[3]‎‎</code> و<code>Pattern[2]‎‎</code>، واللذين نجد أنّهما غير متطابقين، فنبدأ الآن من الموضع حيث بدأ التطابق بين النص والنمط، أي الفهرس 2 في النص، ونوازن بين كل من <code>Text[2]‎‎</code> و<code>Pattern[0]‎‎</code>، وبما أنهما لا يتطابقان، فسنزيد الفهرس النصي، ونوازن بين كل من <code>Text[3]‎‎</code> و<code>Pattern[0]‎‎</code>. واللذان نجد أنهما متطابقان، كما يتطابق كل من:
</p>

<ul>
<li>
		<code>Text[4]‎‎.</code>
	</li>
	<li>
		<code>Pattern[1]‎‎.</code>
	</li>
	<li>
		<code>Text[5]‎‎.</code>
	</li>
	<li>
		<code>Pattern[2].</code>
	</li>
	<li>
		<code>Text[6]‎‎.</code>
	</li>
	<li>
		<code>Pattern[3]‎‎</code>.
	</li>
</ul>
<p>
	لقد استنفدنا حروف النمط، وهذا يعني أنه موجود في النص. نعيد الآن الفهرس الذي بدأ التطابق عنده، وهو 3.
</p>

<p>
	إن لم يكن النمط موجودًا في النص (مثلا إن كان يساوي <code>‎bcgll‎</code>)، فنتوقّع أن يُرفع اعتراض exception أو يُعاد -1 أو أيّ قيمة أخرى محدّدة مسبقًا.
</p>

<p>
	تستغرق الخوارزمية في أسوأ الحالات <code>‎O(mn)‎</code>، حيث يمثّل m طول النص، و n طول النمط. السؤال الآن هو: هل هناك خوارزمية أسرع؟ نعم، وهي <a href="https://wiki.hsoub.com/Algorithms/KMP" rel="external">خوارزمية KMP</a>.
</p>

<p>
	تبحث خوارزمية نوث-موريس-برات Knuth-Morris-Pratt أو KMP اختصارًا، عن ظهور نمط معيّن داخل سلسلة نصّية، وتستغل هذه الخوارزمية حقيقة أنّه عند حدوث عدم التطابق فإنّ الكلمة نفسها تقدّم معلومات كافية لتقدير المكان التالي الذي يمكن أن يبدأ التطابق عنده، وبالتالي تجاوز بعض الحروف التي تحقّقنا منها سابقًا.
</p>

<p>
	صُمِّمت هذه الخوارزمية سنة 1970 على يد دونالد نوث Donuld Knuth وفوهان برات Vaughan Pratt، وبشكل مستقل على يد جيمس مورِس James H. Morris، وقد نَشر هذا الثلاثي بحثًا مشتركًا عنها سنة 1977.
</p>

<p>
	لنوسّع مثالنا السابق كي نفهمه أكثر:
</p>

<pre class="ipsCode prettyprint lang-lua prettyprinted" id="ips_uid_5954_10" style="">
<span class="pun">+-------+---+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Index</span><span class="pln"> </span><span class="pun">|</span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="lit">6</span><span class="pln"> </span><span class="pun">|</span><span class="lit">7</span><span class="pln"> </span><span class="pun">|</span><span class="lit">8</span><span class="pln"> </span><span class="pun">|</span><span class="lit">9</span><span class="pln"> </span><span class="pun">|</span><span class="lit">10</span><span class="pun">|</span><span class="lit">11</span><span class="pun">|</span><span class="lit">12</span><span class="pun">|</span><span class="lit">13</span><span class="pun">|</span><span class="lit">14</span><span class="pun">|</span><span class="lit">15</span><span class="pun">|</span><span class="lit">16</span><span class="pun">|</span><span class="lit">17</span><span class="pun">|</span><span class="lit">18</span><span class="pun">|</span><span class="lit">19</span><span class="pun">|</span><span class="lit">20</span><span class="pun">|</span><span class="lit">21</span><span class="pun">|</span><span class="lit">22</span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="typ">Text</span><span class="pln">  </span><span class="pun">|</span><span class="pln">a  </span><span class="pun">|</span><span class="pln">b </span><span class="pun">|</span><span class="pln">c </span><span class="pun">|</span><span class="pln">x </span><span class="pun">|</span><span class="pln">a </span><span class="pun">|</span><span class="pln">b </span><span class="pun">|</span><span class="pln">c </span><span class="pun">|</span><span class="pln">d  </span><span class="pun">|</span><span class="pln">a </span><span class="pun">|</span><span class="pln">b </span><span class="pun">|</span><span class="pln"> x </span><span class="pun">|</span><span class="pln"> a </span><span class="pun">|</span><span class="pln"> b </span><span class="pun">|</span><span class="pln"> c </span><span class="pun">|</span><span class="pln">d  </span><span class="pun">|</span><span class="pln"> a </span><span class="pun">|</span><span class="pln"> b </span><span class="pun">|</span><span class="pln"> c </span><span class="pun">|</span><span class="pln"> d </span><span class="pun">|</span><span class="pln"> a </span><span class="pun">|</span><span class="pln"> b </span><span class="pun">|</span><span class="pln"> c </span><span class="pun">|</span><span class="pln"> y </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+</span><span class="pln">

</span><span class="pun">+----------+---+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="typ">Index</span><span class="pln">   </span><span class="pun">|</span><span class="pln"> </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">7</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----------+---+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Pattern</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> a  </span><span class="pun">|</span><span class="pln"> b </span><span class="pun">|</span><span class="pln"> c  </span><span class="pun">|</span><span class="pln"> d  </span><span class="pun">|</span><span class="pln"> a  </span><span class="pun">|</span><span class="pln"> b  </span><span class="pun">|</span><span class="pln"> c </span><span class="pun">|</span><span class="pln"> y  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---------+---+---+---+---+---+---+---+---+</span></pre>

<p>
	في البداية، يتطابق النص والنمط حتى الفهرسَ 2، ثمّ ينهار التطابق عند الفهرس 3، إذ لا تتطابق <code>Text[3]‎‎</code> و<code>Pattern[3]‎‎</code>. ونحن نهدف إلى عدم الرجوع للخلف في النص، إذ لا نريد أن نبدأ المطابقة مرةً أخرى من الموضع الذي بدأنا المطابقة عنده سابقًا في حالة عدم التطابق. ولتحقيق ذلك، نبحث عن لاحقةٍ suﬃx في الجزء الحالي من النمط قبل انهيار التطابق والتي تكون أيضًا سابقةً في النمط (السلسلة النصية الجزئية abc). على سبيل المثال، بما أنّ جميع الحروف فريدة غير مكرّرة، فلن يكون هناك أيّ سلسلة نصية تكون لاحقة وسابقة في الوقت نفسه في السلسلة النصية الجزئية التي طَابقناها للتو، هذا يعني أنّ الموازنة التالية ستبدأ من الفهرس 0.
</p>

<p>
	سنوازن الآن بين كل من <code>Text[3]‎‎</code> و<code>Pattern[0]‎‎</code>، إلا أنّهما لا يتطابقان. بعد ذلك نجد تطابقًا ابتداءً من الفهرس 4 وحتى الفهرس 9 في النص، ومن الفهرس 0 إلى 5 في النمط. غير أنّ التطابق ينهار بعد ذلك في <code>Text[10]‎‎</code> و<code>Pattern[6]‎‎</code>. نأخذ الآن السلسلة النصية الجزئية المُطابِقة من النمط قبل نقطة الانهيار (أي abcdabc)، ونبحث عن لاحقة فيها تكون أيضًا سابقة للنمط. تستطيع ملاحظة أنّ ab هي لاحقة لهذه السلسلة النصية الجزئية وسابقة لها في الوقت نفسه. وبما أنّ المطابقة السابقة استمرت حتى <code>Text[10]‎‎</code>، فإنّ الحرفين اللذين يسبقان موضع عدم التطابق هما ab.
</p>

<p>
	هنا نستنتج أنّه لما كانت ab أيضًا سابقة للسلسلة النصية الجزئية التي أخذناها، فلن يكون علينا التحقق من ab مرة أخرى، ويمكن أن يبدأ الفحص التالي من <code>Text[10]‎‎</code> و<code>Pattern[2]‎‎</code>، كذلك ليس علينا أن نعود حيث كنا إذ يمكننا أن نبدأ مباشرة من موضع انهيار التطابق.
</p>

<p>
	علينا الآن التحقق من <code>Text[10]‎‎</code> و<code>Pattern[2]‎‎</code>، بما أنّهما غير متطابقتين وليس للجزء المطابَق من النمط أي لاحقة هي نفسها سابقة للنمط، فسيكون علينا أن نتحقق من <code>Text[10]‎‎</code> و<code>Pattern[0]‎‎</code>، ولكنّها لا يتطابقان أيضًا. بعد ذلك نجد تطابقًا ابتداءً من الفهرس 11 وحتى الفهرس 17 في النص، ومن الفهرس 0 إلى 6. لكن ينهار التطابق مجددًا في <code>Text[18]‎‎</code> و<code>Pattern[7]‎‎</code>.
</p>

<p>
	مرّة أخرى علينا التحقق من السلسلة النصية الجزئية قبل انهيار التطابق (أي abcdabc) لنجد أنّ abc هي لاحقة وسابقة في الوقت نفسه، لذا ينبغي أن تكون abc قبل <code>Text[18]‎‎</code> بما أنّ التطابق السابق استمر حتى الموضع <code>Pattern[7]‎‎</code>، وهذا يعني أننا لسنا بحاجة إلى الموازنة حتى الموضع <code>Text[18]‎‎</code>، إذ ستبدأ الموازنة من <code>Text[18]‎‎</code> و<code>Pattern[3]‎‎</code>. سنجد الآن تطابقًا، ونعيد 15، وهو الفهرس الذي يبدأ عنده التطابق. هذه هي طريقة عمل خوارزمية KMP.
</p>

<p>
	والآن، كيف نتحقّق مما إذا كانت اللاحقة تساوي السابقة، وعند أي نقطة نبدأ التحقق مما إذا كان هناك عدم تطابق للحروف بين النص والنمط؟
</p>

<p>
	لنلق نظرة على المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_14" style="">
<span class="pun">+-------+----+----+----+----+----+----+----+----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Index</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">5</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">6</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">7</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-------+----+----+----+----+----+----+----+----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="typ">Text</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> a  </span><span class="pun">|</span><span class="pln">  b  </span><span class="pun">|</span><span class="pln">  c  </span><span class="pun">|</span><span class="pln">  d  </span><span class="pun">|</span><span class="pln">  a  </span><span class="pun">|</span><span class="pln">  b  </span><span class="pun">|</span><span class="pln">  c    </span><span class="pun">|</span><span class="pln">  a  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-------+----+----+----+----+----+----+----+----+</span></pre>

<p>
	سننشئ مصفوفةً تحتوي المعلومات الضرورية وسنسميها المصفوفة S، حجم هذه المصفوفة يساوي طول النمط، ولا يمكن أن يكون الحرف الأول من النمط لاحقة لأيّ سابقة، لذا نضع S[0] = 0.
</p>

<p>
	نأخذ i = 1 و j = 0 في البداية، نوازن في كل خطوة بين <code>‎Pattern[i‎]‎‎‎</code> و<code>Pattern[j]‎‎</code> ونزيد قيمة i بواحد، فإذا كان هناك تطابق نضع S[i‎] = j + 1 ونزيد قيمة j، وإن لم يكن فنتحقق من قيمة الموضع السابق لـ j -إن وُجد- ونضع j = S [j-1]‎‎ -إذا كانت j تخالف 0-، ونستمر في هذا إلى أن يحدث عدم تطابق بين S[i‎] [j]‎‎ و S ‎‎، أو تخالف j القيمة 0. في الحالة الأخيرة نضع S[i‎] = 0.
</p>

<p>
	نعود إلى المثال السابق:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_16" style="">
<span class="pln">              j      i
</span><span class="pun">+-------+----+----+----+----+----+----+----+----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Index</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">5</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">6</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">7</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-------+----+----+----+----+----+----+----+----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="typ">Text</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> a  </span><span class="pun">|</span><span class="pln">  b  </span><span class="pun">|</span><span class="pln">  c  </span><span class="pun">|</span><span class="pln">  d  </span><span class="pun">|</span><span class="pln">  a  </span><span class="pun">|</span><span class="pln">  b  </span><span class="pun">|</span><span class="pln">  c    </span><span class="pun">|</span><span class="pln">  a  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-------+----+----+----+----+----+----+----+----+</span></pre>

<p>
	لا يتطابق <code>‎Pattern[i‎]‎</code> و<code>Pattern[j]‎‎</code>، لذا نزيد قيمة i بواحد، وبما أنّ j تساوي 0، فلن نتحقق من القيمة السابقة، وسنضع <code>‎Pattern[i‎] = 0‎</code>. سنحصل على تطابق عند الموضع i = 4 إذا واصلنا زيادة i، لذلك نضع [i‎] = S[4] = j + 1 = 0 + 1 = 1 ثمّ نزيد قيمتي j و i. ستبدو المصفوفة هكذا:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_5954_18" style="">
<span class="pln">                     j                           i
</span><span class="pun">+-------+----+----+----+----+----+----+----+----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Index</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">5</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">6</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">7</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-------+----+----+----+----+----+----+----+----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="typ">Text</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> a  </span><span class="pun">|</span><span class="pln">  b  </span><span class="pun">|</span><span class="pln">  c  </span><span class="pun">|</span><span class="pln">  d  </span><span class="pun">|</span><span class="pln">  a  </span><span class="pun">|</span><span class="pln">  b  </span><span class="pun">|</span><span class="pln">  c    </span><span class="pun">|</span><span class="pln">  a  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-------+----+----+----+----+----+----+----+----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">    S    </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">   </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">      </span><span class="pun">|</span><span class="pln">       </span><span class="pun">|</span><span class="pln">      </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-------+----+----+----+----+----+----+----+----+</span></pre>

<p>
	بما أن <code>‎Pattern[5]‎</code> و<code>Pattern[1]‎‎</code> متطابقتين، فإننا نضع S[i‎] = S [5] = j + 1 = 1 + 1 = 2. إذا تابعنا سنجد عدم تطابق في الموضعين j = 3 و i = 7. وبما أنّ j لا تساوي 0، فإننا نضع j = S [j-1]‎‎ ونوازن الحرفين الموجودين عند الموضعين i و j، ولأنها متماثلان فإننا نضع S[i‎] = j + 1. ستبدو المصفوفة النهائية كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_22" style="">
<span class="pun">+---------+---+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">    S      </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---------+---+---+---+---+---+---+---+---+</span></pre>

<p>
	هذه هي المصفوفة المطلوبة. إن كانت S[i‎]‎‎ تخالف الصفر فذلك يعني أنّ هناك سلسلة نصية طولها S[i‎]‎‎ هي لاحقة وسابقة في الوقت نفسه للسلسلة النصية الجزئية من النمط التي تبدأ من 0 وتنتهي عند i. نبدأ الموازنة التالية من الموضع S[i‎] + 1 في النمط.
</p>

<p>
	هذه شيفرة عامة لخوارزمية توليد المصفوفة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_24" style="">
<span class="typ">Procedure</span><span class="pln"> </span><span class="typ">GenerateSuffixArray</span><span class="pun">(</span><span class="typ">Pattern</span><span class="pun">):</span><span class="pln">
i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
j </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
n </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">Pattern</span><span class="pun">.</span><span class="pln">length
</span><span class="kwd">while</span><span class="pln"> i is less than n
   </span><span class="kwd">if</span><span class="pln"> </span><span class="typ">Pattern</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> is equal to </span><span class="typ">Pattern</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln">
       S</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> j </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
       j </span><span class="pun">:=</span><span class="pln"> j </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
       i </span><span class="pun">:=</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> j is not equal to </span><span class="lit">0</span><span class="pln">
           j </span><span class="pun">:=</span><span class="pln"> S</span><span class="pun">[</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
       </span><span class="kwd">else</span><span class="pln">
           S</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
           i </span><span class="pun">:=</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
       end </span><span class="kwd">if</span><span class="pln">
   end </span><span class="kwd">if</span><span class="pln">
end </span><span class="kwd">while</span></pre>

<p>
	التعقيد الزمني لعملية بناء المصفوفة هو <code>‎O(n)‎</code>، والتعقيد المساحي يساوي أيضًا <code>‎O(n)‎</code>. للتأكد من أنك قد فهمت الخوارزمية، حاول إنشاء مصفوفة للنمط <code>‎aabaabaa‎</code>، وتحقق مما إذا كانت النتيجة التي حصلت عليها تتطابق مع <a href="https://i.stack.imgur.com/4aqZk.jpg" rel="external nofollow">هذه النتيجة</a>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_26" style="">
<span class="pun">+---------+---+---+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">    S      </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---------+---+---+---+---+---+---+---+---+---+</span></pre>

<p>
	انظر إلى المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_32" style="">
<span class="pun">+---------+---+---+---+---+---+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="typ">Index</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">6</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">7</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">9</span><span class="pln"> </span><span class="pun">|</span><span class="lit">10</span><span class="pln"> </span><span class="pun">|</span><span class="lit">11</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> 
</span><span class="pun">+---------+---+---+---+---+---+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">   </span><span class="typ">Text</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  a </span><span class="pun">|</span><span class="pln">  b </span><span class="pun">|</span><span class="pln">  x </span><span class="pun">|</span><span class="pln">  a </span><span class="pun">|</span><span class="pln">  b </span><span class="pun">|</span><span class="pln">  c </span><span class="pun">|</span><span class="pln">  a </span><span class="pun">|</span><span class="pln">  b </span><span class="pun">|</span><span class="pln">  c </span><span class="pun">|</span><span class="pln">  a </span><span class="pun">|</span><span class="pln">  b </span><span class="pun">|</span><span class="pln">  y </span><span class="pun">|</span><span class="pln"> 
</span><span class="pun">+---------+---+---+---+---+---+---+---+---+---+---+---+---+</span><span class="pln">

</span><span class="pun">+---------+---+---+---+---+---+----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="typ">Index</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> 
</span><span class="pun">+---------+---+---+---+---+---+----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Pattern</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  a </span><span class="pun">|</span><span class="pln">  b </span><span class="pun">|</span><span class="pln">  c </span><span class="pun">|</span><span class="pln">  a </span><span class="pun">|</span><span class="pln">  b </span><span class="pun">|</span><span class="pln">  y </span><span class="pun">|</span><span class="pln"> 
</span><span class="pun">+---------+---+---+---+---+---+----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">    S      </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> 
</span><span class="pun">+---------+---+---+---+---+---+----+</span></pre>

<p>
	لدينا سلسلة نصية ونمط ومصفوفة S محسوبة قبليًا باستخدام الطريقة التي شرحناها سابقًا. سوف نوازن <code>‎Text[0]‎</code> و<code>Pattern[0]‎‎</code> وهما متطابقان، كما أنّ <code>‎Text[1]‎</code> و<code>Pattern[1]‎‎</code> متطابقان كذلك؛ أمّا <code>‎Text[2]‎</code> و<code>Pattern[2]‎‎</code>، فهما غير متطابقين.
</p>

<p>
	نتحقق من القيمة الموجودة عند الموضع الذي يسبق موضع عدم التطابق. ولمّا كانت ‎‎S [1] ‎‎ تساوي 0، فذلك يعني أنّه لا توجد لاحقة تطابق سابقة في السلسلة النصية الجزئية الحالية، لذا تبدأ الموازنة عند الموضع S [1]‎‎، وهو 0. وهكذا نجد أنّ <code>‎Text[2]‎</code> و<code>Pattern[0]‎‎</code> غير متطابقتين، لذا نستمر لنجد أنّ <code>‎Text[3]‎</code> و<code>Pattern[0]‎‎</code> متطابقتان، ويستمر التطابق حتى <code>‎Text[8]‎</code> و<code>Pattern[5]‎‎</code>.
</p>

<p>
	نعود الآن خطوةً واحدةً إلى الوراء في المصفوفة S لنجد القيمة 2، هذا يعني أنّ هناك سابقة طولها 2 وهي أيضًا لاحقة في السلسلة النصية الجزئية الحالية abcab، وهي ab. هذا يعني أنّ السلسلة النصية ab موجودة قبل <code>‎Text[8]‎</code>.<br>
	وعلى ذلك نستطيع تجاهل<code>Pattern[1]‎‎</code> و<code>Pattern[0]‎‎</code> وبدء الموازنة التالية من الموضعين <code>‎Text[8]‎</code> و<code>Pattern[2]‎‎</code>.
</p>

<p>
	إذا تابعنا بذلك النسق فسنجد النمط داخل النص، وستبدو الشيفرة لتلك الإجراءات كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_34" style="">
<span class="typ">Procedure</span><span class="pln"> KMP</span><span class="pun">(</span><span class="typ">Text</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Pattern</span><span class="pun">)</span><span class="pln">
</span><span class="typ">GenerateSuffixArray</span><span class="pun">(</span><span class="typ">Pattern</span><span class="pun">)</span><span class="pln">
m </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">Text</span><span class="pun">.</span><span class="typ">Length</span><span class="pln">
n </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">Pattern</span><span class="pun">.</span><span class="typ">Length</span><span class="pln">
i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
j </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> i is less than m
   </span><span class="kwd">if</span><span class="pln"> </span><span class="typ">Pattern</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> is equal to </span><span class="typ">Text</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
       j </span><span class="pun">:=</span><span class="pln"> j </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
       i </span><span class="pun">:=</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> j is equal to n
       </span><span class="typ">Return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">j</span><span class="pun">-</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> m and </span><span class="typ">Pattern</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> is not equal t </span><span class="typ">Text</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> j is not equal to </span><span class="lit">0</span><span class="pln">
           j </span><span class="pun">=</span><span class="pln"> S</span><span class="pun">[</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
       </span><span class="kwd">else</span><span class="pln">
           i </span><span class="pun">:=</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
       end </span><span class="kwd">if</span><span class="pln">
   end </span><span class="kwd">if</span><span class="pln">
end </span><span class="kwd">while</span><span class="pln">
</span><span class="typ">Return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span></pre>

<p>
	التعقيد الزمني لهذه الخوارزمية -بصرف النظر عن العمليات الحسابية المتعلقة بحساب مصفوفة اللاحقات- هو <code>‎O(m)‎</code>، وبما أنّ دالة <code>GenerateSuﬃxArray</code> تستغرق وقتًا قدره <code>O ‎(n)‎</code>، فإن التعقيد الزمني الإجمالي لخوارزمية KMP هو: <code>O ‎(m+n)‎</code>.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		<strong>ملاحظة</strong>: إذا أردت العثور على كل مواضع ظهور نمط معيّن في النص، يمكنك أن تطبعها أو تحفظها وتعيّن <code>‎j := S[j-1]‎</code>، وذلك بدلًا من أن إعادة القيمة. كذللك يجب أن تحفظ رايةً ‎flag‎ لتعرف ما إذا كنت قد وجدت أيّ ظهور سابق للنمط أم لا.
	</p>
</blockquote>

<h2>
	خوارزمية رابين كارب Rabin-Karp
</h2>

<p>
	<a href="https://wiki.hsoub.com/Algorithms/Rabin_Karp" rel="external">خوارزمية رابين-كارب</a>‏ Rabin-Karp هي خوارزمية بحث في السلاسل النصية أُنشِئت على يد ريتشارد كارب Richard M. Karp ومايكل رابِن Michael Rabin، وتستخدم هذه الخوارزمية <a href="https://academy.hsoub.com/programming/c-sharp/dotnet/%D8%A7%D9%84%D8%AA%D8%B4%D9%81%D9%8A%D8%B1-encryption-%D9%88%D8%A7%D9%84%D8%AA%D8%B9%D9%85%D9%8A%D8%A9-hashing-%D9%81%D9%8A-dot-net-r997/" rel="">دالة التعمية hashing</a> للتحقق من وجود مجموعة من الأنماط في نص ما.
</p>

<p>
	ونقول أنّ s سلسلة نصية جزئية من S إذا كانت s مُتضمّنة في S. على سبيل المثال، ver هي سلسلة نصية جزئية من stackoverﬂow. لكن لا ينبغي الخلط بين هذا المفهوم، وبين مفهوم التتابع الجزئئ subsequence الذي لا يشترط أن تكون حروفه متلاصقةً في النص، فمثلًا، تُعَد cover تتابعًا جزئيًا في stackoverﬂow، لكنها ليست سلسلةً نصيةً جزئيةً منها.
</p>

<p>
	في خوارزمية Rabin-Karp، سنحسب تجزئة النمط الذي نبحث عنه، ثمّ نتحقق مما إذا كانت هناك تعمية تداولية rolling hash في النص تتوافق مع النمط أم لا، وإذا لم تتطابق فذلك يضمن لنا أنّ النمط غير موجود في النص، أما في حال كان هناك تطابق فربّما يكون النمط موجودًا في النص. دعنا نلقي نظرةً على المثال التالي:
</p>

<p>
	لنفترض أنّ النص يساوي <code>yeminsajid</code>، وأننا نريد أن نعرف إن كان هذا النص يحتوي النمط <code>nsa</code>. لكي نحسب التجزئة والتجزئة التداولية سنحتاج إلى استخدام عدد أولي، ويمكنك هنا اختيار أيّ عدد أولي وليكن العدد Prime = 11.
</p>

<p>
	نحسب قيمة التجزئة باستخدام هذه الصيغة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_36" style="">
<span class="pun">(</span><span class="lit">1st</span><span class="pln"> letter</span><span class="pun">)</span><span class="pln"> X </span><span class="pun">(</span><span class="pln">prime</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="lit">2nd</span><span class="pln"> letter</span><span class="pun">)</span><span class="pln"> X </span><span class="pun">(</span><span class="pln">prime</span><span class="pun">)¹</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="lit">3rd</span><span class="pln"> letter</span><span class="pun">)</span><span class="pln"> X </span><span class="pun">(</span><span class="pln">prime</span><span class="pun">)²</span><span class="pln"> X </span><span class="pun">+</span><span class="pln"> </span><span class="pun">......</span></pre>

<p>
	لكل حرف رقم يميزه في قائمة الحروف الهجائية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_38" style="">
<span class="pln">a </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pln">    g </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">7</span><span class="pln">    m </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">13</span><span class="pln">  s </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">19</span><span class="pln">  y </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">25</span><span class="pln">
b </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">2</span><span class="pln">    h </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">8</span><span class="pln">    n </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">14</span><span class="pln">   t </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">20</span><span class="pln">   z </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">26</span><span class="pln">
c </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">3</span><span class="pln">    i </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">9</span><span class="pln">     o </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">15</span><span class="pln">   u </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">21</span><span class="pln">
d </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">4</span><span class="pln">    j </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">10</span><span class="pln">   p </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">16</span><span class="pln">   v </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">22</span><span class="pln">
e </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">5</span><span class="pln">    k </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">11</span><span class="pln">  q </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">17</span><span class="pln">   w </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">23</span><span class="pln">
f </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">6</span><span class="pln">     l </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">12</span><span class="pln">    r </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">18</span><span class="pln">   x </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">24</span></pre>

<p>
	قيمة تجزئة nsa هي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_40" style="">
<span class="pln"> </span><span class="lit">14</span><span class="pln"> X </span><span class="lit">11</span><span class="pun">⁰</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">19</span><span class="pln"> X </span><span class="lit">11</span><span class="pun">¹</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> X </span><span class="lit">11</span><span class="pun">²</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">344</span></pre>

<p>
	الآن نحسب التجزئة التداولية للنص، أي نحسب تجزئة كل سلسلة نصية جزئية مؤلفة من 3 حروف في النص، فإذا تطابقت التجزئة التداولية مع قيمة تجزئة النمط، نتحقق مما إذا كانت السلسلتان النصيّتان متطابقتان أم لا، وبما أنّ النمط يحتوي على 3 أحرف، فإننا نأخذ أوّل ثلاثة أحرف من النص yem ونحسب قيمة تجزئتها، فنحصل على:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_42" style="">
<span class="lit">25</span><span class="pln"> X </span><span class="lit">11</span><span class="pun">⁰</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> X </span><span class="lit">11</span><span class="pun">¹</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">13</span><span class="pln"> X </span><span class="lit">11</span><span class="pun">²</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1653</span></pre>

<p>
	لا تتطابق هذه القيمة مع قيمة تجزئة النمط، لذا فإنّ السلسلة النصية غير موجودة هنا، وسننتقل الآن إلى الخطوة التالية ونحسب قيمة التجزئة الخاصة بالسلسلة النصية emi التالية باستخدام الصيغة أعلاه.
</p>

<p>
	مشكلة هذا المنظور هي أنّ حساب التجزئة في كل مرة مكلف جدًا، لكن هناك تقنية يمكن أن تسرّع العملية برمّتها، وخطواتها كالآتي:
</p>

<ol>
<li>
		نطرح قيمة الحرف الأول من السلسلة النصية السابقة (التي حسبنا تجزئتها قبيل قليل) من قيمة التجزئة الحالية، والتي هي فـي هـذه الحالـة y. وسنحصل على <code>‎1653 - 25 = 1628‎</code>.
	</li>
	<li>
		نقسّم الناتج على العدد الأولي 11 الذي اخترناه سابقًا، وسنحصل على <code>‎1628 / 11 = 148‎</code>.
	</li>
	<li>
		نضيف ناتج العملية (ترتيب الحرف الجديد) X‏ 11<sup>m-y</sup>، حيث يمثّل m طول النمط، أما ترتيب الحرف الجديد فيساوي ترتيب i، وهو 9. نحصل على <code>11<sup>2</sup> = 1237‎</code>
	</li>
</ol>
<p>
	قيمة التجزئة الجديدة لا تساوي قيمة التجزئة الخاصة بالنمط، لذا نستمر بالبحث على المنوال نفسه، وبالنسبة للحرف <code>n</code> نحصل على:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_44" style="">
<span class="typ">Previous</span><span class="pln"> </span><span class="typ">String</span><span class="pun">:</span><span class="pln"> emi </span><span class="com">// السلسلة النصية السابقة</span><span class="pln">
</span><span class="typ">First</span><span class="pln"> </span><span class="typ">Letter</span><span class="pln"> of </span><span class="typ">Previous</span><span class="pln"> </span><span class="typ">String</span><span class="pun">:</span><span class="pln"> e</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln">  </span><span class="com">// الحرف الأول من السلسلة النصية السابقة</span><span class="pln">
</span><span class="typ">New</span><span class="pln"> </span><span class="typ">Letter</span><span class="pun">:</span><span class="pln"> n</span><span class="pun">(</span><span class="lit">14</span><span class="pun">)</span><span class="pln">     </span><span class="com">// الحرف الجديد </span><span class="pln">
</span><span class="typ">New</span><span class="pln"> </span><span class="typ">String</span><span class="pun">:</span><span class="pln"> </span><span class="str">"min"</span><span class="pln">     </span><span class="com">// السلسلة النصية الجديدة</span><span class="pln">
</span><span class="lit">1237</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1232</span><span class="pln">
</span><span class="lit">1232</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">11</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">112</span><span class="pln">
</span><span class="lit">112</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">14</span><span class="pln"> X </span><span class="lit">11</span><span class="pun">²</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1806</span></pre>

<p>
	ليس هناك تطابق أيضًا، لذا سنأخذ الآن الحرف s:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_46" style="">
<span class="typ">Previous</span><span class="pln"> </span><span class="typ">String</span><span class="pun">:</span><span class="pln"> min  </span><span class="com">// السلسلة النصية السابقة</span><span class="pln">
</span><span class="typ">First</span><span class="pln"> </span><span class="typ">Letter</span><span class="pln"> of </span><span class="typ">Previous</span><span class="pln"> </span><span class="typ">String</span><span class="pun">:</span><span class="pln"> m</span><span class="pun">(</span><span class="lit">13</span><span class="pun">)</span><span class="pln">  </span><span class="com">// الحرف الأول من السلسلة النصية السابقة</span><span class="pln">
</span><span class="typ">New</span><span class="pln"> </span><span class="typ">Letter</span><span class="pun">:</span><span class="pln"> s</span><span class="pun">(</span><span class="lit">19</span><span class="pun">)</span><span class="pln">   </span><span class="com">// الحرف الجديد </span><span class="pln">
</span><span class="typ">New</span><span class="pln"> </span><span class="typ">String</span><span class="pun">:</span><span class="pln"> </span><span class="str">"ins"</span><span class="pln">    </span><span class="com">// السلسلة النصية الجديدة</span><span class="pln">
</span><span class="lit">1806</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">13</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1793</span><span class="pln">  
</span><span class="lit">1793</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">11</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">163</span><span class="pln">
</span><span class="lit">163</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">19</span><span class="pln"> X </span><span class="lit">11</span><span class="pun">²</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2462</span></pre>

<p>
	ليس هناك تطابق أيضًا. بعد ذلك، نأخذ <code>a</code> فنحصل على:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_48" style="">
<span class="typ">Previous</span><span class="pln"> </span><span class="typ">String</span><span class="pun">:</span><span class="pln"> ins   </span><span class="com">// السلسلة النصية السابقة</span><span class="pln">
</span><span class="typ">First</span><span class="pln"> </span><span class="typ">Letter</span><span class="pln"> of </span><span class="typ">Previous</span><span class="pln"> </span><span class="typ">String</span><span class="pun">:</span><span class="pln"> i</span><span class="pun">(</span><span class="lit">9</span><span class="pun">)</span><span class="pln">  </span><span class="com">// الحرف الأول من السلسلة النصية السابقة</span><span class="pln">
</span><span class="typ">New</span><span class="pln"> </span><span class="typ">Letter</span><span class="pun">:</span><span class="pln"> a</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">  </span><span class="com">// الحرف الجديد</span><span class="pln">
</span><span class="typ">New</span><span class="pln"> </span><span class="typ">String</span><span class="pun">:</span><span class="pln"> </span><span class="str">"nsa"</span><span class="pln">  </span><span class="com">// السلسلة النصية الجديدة</span><span class="pln">
</span><span class="lit">2462</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">9</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2453</span><span class="pln">
</span><span class="lit">2453</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">11</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">223</span><span class="pln">
</span><span class="lit">223</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> X </span><span class="lit">11</span><span class="pun">²</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">344</span></pre>

<p>
	هنا حصل تطابق، لذا سنوازن الآن النمط بالسلسلة النصية الحالية، وبما أنّ كلا السلسلتين متطابقتين نستنج أنّ السلسلة النصية الجزئية موجودة في النص، ونعيد موضع بداية السلسلة النصية الجزئية. انظر المثال التوضيحي التالي:
</p>

<ul>
<li>
		حساب التجزئة:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_50" style="">
<span class="typ">Procedure</span><span class="pln"> </span><span class="typ">Calculate</span><span class="pun">-</span><span class="typ">Hash</span><span class="pun">(</span><span class="typ">String</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Prime</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">):</span><span class="pln">
hash </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">               </span><span class="com">// ‫هنا، تمثل x الطول</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> m from </span><span class="lit">1</span><span class="pln"> to x                      </span><span class="com">// البحث عن قيمة التجزئة</span><span class="pln">
   hash </span><span class="pun">:=</span><span class="pln"> hash </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Value</span><span class="pln"> of </span><span class="typ">String</span><span class="pun">[</span><span class="pln">m</span><span class="pun">])⁻¹</span><span class="pln">
end </span><span class="kwd">for</span><span class="pln">
</span><span class="typ">Return</span><span class="pln"> hash</span></pre>

<ul>
<li>
		إعادة حساب التجزئة، ستمثل <code>Curr</code> هنا الحرف الأول من السلسلة النصية السابقة:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_52" style="">
<span class="typ">Procedure</span><span class="pln"> </span><span class="typ">Recalculate</span><span class="pun">-</span><span class="typ">Hash</span><span class="pun">(</span><span class="typ">String</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Curr</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Prime</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Hash</span><span class="pun">):</span><span class="pln">
</span><span class="typ">Hash</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">Hash</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Value</span><span class="pln"> of </span><span class="typ">String</span><span class="pun">[</span><span class="typ">Curr</span><span class="pun">]</span><span class="pln"> 
</span><span class="typ">Hash</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">Hash</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="typ">Prime</span><span class="pln">
m </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">String</span><span class="pun">.</span><span class="pln">length
</span><span class="typ">New</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">Curr</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> m </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="typ">Hash</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">Hash</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Value</span><span class="pln"> of </span><span class="typ">String</span><span class="pun">[</span><span class="typ">New</span><span class="pun">])⁻¹</span><span class="pln">
</span><span class="typ">Return</span><span class="pln"> </span><span class="typ">Hash</span></pre>

<ul>
<li>
		مطابقة السلسلة النصية:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_54" style="">
<span class="typ">Procedure</span><span class="pln"> </span><span class="typ">String</span><span class="pun">-</span><span class="typ">Match</span><span class="pun">(</span><span class="typ">Text</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Pattern</span><span class="pun">,</span><span class="pln"> m</span><span class="pun">):</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i from m to </span><span class="typ">Pattern</span><span class="pun">-</span><span class="pln">length </span><span class="pun">+</span><span class="pln"> m </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="typ">Text</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> is not equal to </span><span class="typ">Pattern</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
        </span><span class="typ">Return</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
    end </span><span class="kwd">if</span><span class="pln">
end </span><span class="kwd">for</span><span class="pln">
</span><span class="typ">Return</span><span class="pln"> </span><span class="kwd">true</span></pre>

<ul>
<li>
		منظور رابين كارب:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_56" style="">
<span class="typ">Procedure</span><span class="pln"> </span><span class="typ">Rabin</span><span class="pun">-</span><span class="typ">Karp</span><span class="pun">(</span><span class="typ">Text</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Pattern</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Prime</span><span class="pun">):</span><span class="pln">
m </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">Pattern</span><span class="pun">.</span><span class="typ">Length</span><span class="pln">
</span><span class="typ">HashValue</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">Calculate</span><span class="pun">-</span><span class="typ">Hash</span><span class="pun">(</span><span class="typ">Pattern</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Prime</span><span class="pun">,</span><span class="pln"> m</span><span class="pun">)</span><span class="pln">
</span><span class="typ">CurrValue</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">Calculate</span><span class="pun">-</span><span class="typ">Hash</span><span class="pun">(</span><span class="typ">Pattern</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Prime</span><span class="pun">,</span><span class="pln"> m</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i from </span><span class="lit">1</span><span class="pln"> to </span><span class="typ">Text</span><span class="pun">.</span><span class="pln">length </span><span class="pun">-</span><span class="pln"> m
   </span><span class="kwd">if</span><span class="pln"> </span><span class="typ">HashValue</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="typ">CurrValue</span><span class="pln"> and </span><span class="typ">String</span><span class="pun">-</span><span class="typ">Match</span><span class="pun">(</span><span class="typ">Text</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Pattern</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">)</span><span class="pln"> is </span><span class="kwd">true</span><span class="pln">
       </span><span class="typ">Return</span><span class="pln"> i
   end </span><span class="kwd">if</span><span class="pln">
   </span><span class="typ">CurrValue</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">Recalculate</span><span class="pun">-</span><span class="typ">Hash</span><span class="pun">(</span><span class="typ">String</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">+</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Prime</span><span class="pun">,</span><span class="pln"> </span><span class="typ">CurrValue</span><span class="pun">)</span><span class="pln">
end </span><span class="kwd">for</span><span class="pln">
</span><span class="typ">Return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span></pre>

<p>
	ستعيد الخوارزمية -1 إذا لم تعثر على أي تطابق.
</p>

<p>
	تُستخدم هذه الخوارزمية للكشف عن الانتحال، إذ نعطيها مادةً نصيةً مصدريةً، فتبحث بسرعة في مقالة عما إذا كانت المقالة تحتوي جملًا أو عبارات من المادة المصدرية متجاهلةً تفاصيلًا معينةً من قبيل علامات الترقيم وحالة الحروف (أو تشكيلها). عادةً ما تكون هناك الكثير من السلاسل النصية (الجمل) التي ينبغي أن نبحث عنها، لذا فإنّ خوارزميات البحث التقليدية التي تبحث عن سلسلة نصية واحدة مثل خوارزمية Knuth- Morris-Pratt أو خوارزمية Boyer-Moore String، لن تكون عمليّةً هنا، لهذا يُفضّل استخدام خوارزمية Rabin-Karp. لكن من المهم أن تنتبه إلى أنّ خوارزمية Knuth- Morris-Pratt وخوارزمية Boyer-Moore String أسرع من خوارزمية Rabin-Karp.
</p>

<p>
	هناك تطبيقات أخرى كثيرة لخوارزمية Rabin-Karp، حيث يمكنك استخدامها مثلًا للعثور على السلاسل النصية الرقمية من طول معين في النص وموجودة بعدد ما وليكن k، وذلك عبر إجراء بعض التعديلات البسيطة على الخوارزمية.
</p>

<p>
	بالنسبة لنص طوله n، و p نمط مجموع أطوالها يساوي m، فإنّ حالتي التعقيد المتوسطة والفضلى تساويانO (n + m) ‎‎، كما تحتاج الخوازمية إلى مساحة O (p)‎‎؛ أما حالة التعقيد الأسوأ فتُساوي O (nm)‎‎.
</p>

<p>
	هذا تطبيق بلغة بايثون على خوارزمية KMP:
</p>

<ul>
<li>
		Haystack: السلسلة النصية التي سنبحث فيها.
	</li>
	<li>
		Needle: النمط المراد البحث عنه.
	</li>
	<li>
		التعقيد الزمني: التعقيد الزمني للجزء الذي يُجري عمليات البحث (التابع strstr) هو O (n)‎‎، حيث يمثّل <code>‎n‎</code> طول الوسيط haystack، ولكن لمّا كان الوسيط needle يُحلَّل قبليا لأجل بناء جدول السوابق preﬁx table، فسنحتاج مدة O (m)‎‎، وهي المدة المطلوب لبناء الجدول، حيث يمثل <code>‎m‎</code> طول needle، وهكذا فإنّ التعقيد الزمني الكلي لخوارزمية KMP يساوي O (n + m)‎‎.
	</li>
	<li>
		تعقيد المساحة: تحتاج الخوارزمية إلى مساحة بحجم O (m)‎‎ لأجل بناء جدول السوابق.
	</li>
</ul>
<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		<strong>ملاحظة</strong>: يعيد التقديم التالي موضع بدء التطابق في النص <strong>haystack</strong> (إذا كان هناك تطابق أصلًا)، أو يعيد العدد -1 في حالة لم يكن <strong>needle</strong> موجودًا في النص haystack، أو كان أحدهُما فارغًا.
	</p>
</blockquote>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_58" style="">
<span class="pln">def get_prefix_table</span><span class="pun">(</span><span class="pln">needle</span><span class="pun">):</span><span class="pln">
   prefix_set </span><span class="pun">=</span><span class="pln"> </span><span class="typ">set</span><span class="pun">()</span><span class="pln">
   n </span><span class="pun">=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">needle</span><span class="pun">)</span><span class="pln">
   prefix_table </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">0</span><span class="pun">]*</span><span class="pln">n
   delimeter </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
   </span><span class="kwd">while</span><span class="pun">(</span><span class="pln">delimeter</span><span class="pun">&lt;</span><span class="pln">n</span><span class="pun">):</span><span class="pln">
       prefix_set</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">needle</span><span class="pun">[:</span><span class="pln">delimeter</span><span class="pun">])</span><span class="pln">
       j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
       </span><span class="kwd">while</span><span class="pun">(</span><span class="pln">j</span><span class="pun">&lt;</span><span class="pln">delimeter</span><span class="pun">+</span><span class="lit">1</span><span class="pun">):</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> needle</span><span class="pun">[</span><span class="pln">j</span><span class="pun">:</span><span class="pln">delimeter</span><span class="pun">+</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> in prefix_set</span><span class="pun">:</span><span class="pln">
               prefix_table</span><span class="pun">[</span><span class="pln">delimeter</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> delimeter </span><span class="pun">-</span><span class="pln"> j </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
               </span><span class="kwd">break</span><span class="pln">
           j </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
       delimeter </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> prefix_table
def strstr</span><span class="pun">(</span><span class="pln">haystack</span><span class="pun">,</span><span class="pln"> needle</span><span class="pun">):</span><span class="pln">
   </span><span class="com"># ‫يمثل ‫m الموضع في S حيث يبدأ التطابق القادم لـ W</span><span class="pln">
   </span><span class="com"># ‫يمثل i فهرس المحرف الحالي W</span><span class="pln">
   haystack_len </span><span class="pun">=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">haystack</span><span class="pun">)</span><span class="pln">
   needle_len </span><span class="pun">=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">needle</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">needle_len </span><span class="pun">&gt;</span><span class="pln"> haystack_len</span><span class="pun">)</span><span class="pln"> or </span><span class="pun">(</span><span class="pln">not haystack_len</span><span class="pun">)</span><span class="pln"> or </span><span class="pun">(</span><span class="pln">not needle_len</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pln">
   prefix_table </span><span class="pun">=</span><span class="pln"> get_prefix_table</span><span class="pun">(</span><span class="pln">needle</span><span class="pun">)</span><span class="pln">
   m </span><span class="pun">=</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
   </span><span class="kwd">while</span><span class="pun">((</span><span class="pln">i</span><span class="pun">&lt;</span><span class="pln">needle_len</span><span class="pun">)</span><span class="pln"> and </span><span class="pun">(</span><span class="pln">m</span><span class="pun">&lt;</span><span class="pln">haystack_len</span><span class="pun">)):</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> haystack</span><span class="pun">[</span><span class="pln">m</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> needle</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]:</span><span class="pln">
           i </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
           m </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
       </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> i </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
               i </span><span class="pun">=</span><span class="pln"> prefix_table</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
           </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
               m </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> i</span><span class="pun">==</span><span class="pln">needle_len and haystack</span><span class="pun">[</span><span class="pln">m</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> needle</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]:</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> m </span><span class="pun">-</span><span class="pln"> needle_len
   </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> __name__ </span><span class="pun">==</span><span class="pln"> </span><span class="str">'__main__'</span><span class="pun">:</span><span class="pln">
   needle </span><span class="pun">=</span><span class="pln"> </span><span class="str">'abcaby'</span><span class="pln">
   haystack </span><span class="pun">=</span><span class="pln"> </span><span class="str">'abxabcabcaby'</span><span class="pln">
   print strstr</span><span class="pun">(</span><span class="pln">haystack</span><span class="pun">,</span><span class="pln"> needle</span><span class="pun">)</span></pre>

<p>
	هذا تطبيق على خوارزمية KMP في لغة C، الوسيط txt يمثل النص، فيما يمثل الوسيط pat النمط، يطبع هذا البرنامج كل ظهور للنمط pat في النص txt. مثلا، إن كان الدخل يساوي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_60" style="">
<span class="pln">  txt</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"THIS IS A TEST TEXT"</span><span class="pln">
  pat</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"TEST"</span></pre>

<p>
	فسيطبع البرنامج الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_62" style="">
<span class="typ">Pattern</span><span class="pln"> found at index </span><span class="lit">10</span></pre>

<p>
	بالنسبة للدخل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_64" style="">
<span class="pln">  txt</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"AABAACAADAABAAABAA"</span><span class="pln">
  pat</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="str">"AABA"</span></pre>

<p>
	يطبع البرنامج الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_66" style="">
<span class="pln">   </span><span class="typ">Pattern</span><span class="pln"> found at index </span><span class="lit">0</span><span class="pln">
   </span><span class="typ">Pattern</span><span class="pln"> found at index </span><span class="lit">9</span><span class="pln">
   </span><span class="typ">Pattern</span><span class="pln"> found at index </span><span class="lit">13</span></pre>

<p>
	هذا هو المثال التطبيقي على استخدام خورازمية KMP في لغة C:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_68" style="">
<span class="com">#include</span><span class="str">&lt;stdio.h&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="str">&lt;string.h&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="str">&lt;stdlib.h&gt;</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> computeLPSArray</span><span class="pun">(</span><span class="kwd">char</span><span class="pln"> </span><span class="pun">*</span><span class="pln">pat</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> M</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> </span><span class="pun">*</span><span class="pln">lps</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> </span><span class="typ">KMPSearch</span><span class="pun">(</span><span class="kwd">char</span><span class="pln"> </span><span class="pun">*</span><span class="pln">pat</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">char</span><span class="pln"> </span><span class="pun">*</span><span class="pln">txt</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> M </span><span class="pun">=</span><span class="pln"> strlen</span><span class="pun">(</span><span class="pln">pat</span><span class="pun">);</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> strlen</span><span class="pun">(</span><span class="pln">txt</span><span class="pun">);</span></pre>

<p>
	هنا ستنشئ <code>[]lps</code> لتخزين أطول قيم سابقة لاحقة للنمط، نتابع …
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_71" style="">
<span class="pln">   </span><span class="typ">int</span><span class="pln"> </span><span class="pun">*</span><span class="pln">lps </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> </span><span class="pun">*)</span><span class="pln">malloc</span><span class="pun">(</span><span class="kwd">sizeof</span><span class="pun">(</span><span class="typ">int</span><span class="pun">)*</span><span class="pln">M</span><span class="pun">);</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> j  </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">  </span><span class="com">// pat[] فهرس لـ</span></pre>

<p>
	الحساب القبلي للنمط، أي حساب مصفوفة <code>[]lps</code>، نتابع …
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_73" style="">
<span class="pln">   computeLPSArray</span><span class="pun">(</span><span class="pln">pat</span><span class="pun">,</span><span class="pln"> M</span><span class="pun">,</span><span class="pln"> lps</span><span class="pun">);</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">  </span><span class="com">// txt[] فهرس</span><span class="pln">
   </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> N</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
     </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">pat</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> txt</span><span class="pun">[</span><span class="pln">i</span><span class="pun">])</span><span class="pln">
     </span><span class="pun">{</span><span class="pln">
       j</span><span class="pun">++;</span><span class="pln">
       i</span><span class="pun">++;</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">
     </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">j </span><span class="pun">==</span><span class="pln"> M</span><span class="pun">)</span><span class="pln">
     </span><span class="pun">{</span><span class="pln">
       printf</span><span class="pun">(</span><span class="str">"Found pattern at index %d \n"</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">-</span><span class="pln">j</span><span class="pun">);</span><span class="pln">
       j </span><span class="pun">=</span><span class="pln"> lps</span><span class="pun">[</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">
     </span><span class="com">// تطابق j العثور على عدم تطابق بعد</span><span class="pln">
     </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> N </span><span class="pun">&amp;&amp;</span><span class="pln"> pat</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> txt</span><span class="pun">[</span><span class="pln">i</span><span class="pun">])</span><span class="pln">
     </span><span class="pun">{</span><span class="pln">
       </span><span class="com">// lps[0..lps[j-1]] لا تحاول التحقق من مطابقة الحروف</span><span class="pln">
       </span><span class="com">// لأننا نعلم أنها مطابقة</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">j </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
        j </span><span class="pun">=</span><span class="pln"> lps</span><span class="pun">[</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
       </span><span class="kwd">else</span><span class="pln">
        i </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">+</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   free</span><span class="pun">(</span><span class="pln">lps</span><span class="pun">);</span><span class="pln"> </span><span class="com">// لتجنب تسرب الذاكرة</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> computeLPSArray</span><span class="pun">(</span><span class="kwd">char</span><span class="pln"> </span><span class="pun">*</span><span class="pln">pat</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> M</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> </span><span class="pun">*</span><span class="pln">lps</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> len </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">  </span><span class="com">//  حجم أطول سابقة-لاحقة حالية</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
   lps</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> </span><span class="com">// يساوي 0 دائما lps[0]</span><span class="pln">
   i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> M</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">pat</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> pat</span><span class="pun">[</span><span class="pln">len</span><span class="pun">])</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        len</span><span class="pun">++;</span><span class="pln">
        lps</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> len</span><span class="pun">;</span><span class="pln">
        i</span><span class="pun">++;</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
      </span><span class="kwd">else</span><span class="pln"> </span><span class="com">// (pat[i] != pat[len])</span><span class="pln">
      </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">len </span><span class="pun">!=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
          </span><span class="com">// هنا فخ، انظر المثال التالي</span><span class="pln">
          </span><span class="com">// AAACAAAA و i = 7.</span><span class="pln">
          len </span><span class="pun">=</span><span class="pln"> lps</span><span class="pun">[</span><span class="pln">len</span><span class="pun">-</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
          </span><span class="com">// هنا i لاحظ أيضا أننا لم نزد قيمة</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">else</span><span class="pln"> </span><span class="com">// if (len == 0)</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
          lps</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
          i</span><span class="pun">++;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الخرج الناتج هو الآتي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5954_75" style="">
<span class="typ">Found</span><span class="pln"> pattern at index </span><span class="lit">10</span></pre>

<p>
	ترجمة -بتصرّف- للفصل 40 من الكتاب <a href="https://goalkicker.com/AlgorithmsBook/" rel="external nofollow">Algorithms Notes for Professionals</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%B1%D8%AA%D9%8A%D8%A8-%D9%88%D8%A3%D8%B4%D9%87%D8%B1%D9%87%D8%A7-r1413/" rel="">خوارزميات الترتيب وأشهرها</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%86-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1410/" rel="">أمثلة عن أنواع الخوارزميات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%A3%D8%B4%D8%AC%D8%A7%D8%B1-r1373/" rel="">خوارزميات تحليل المسارات في الأشجار</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-%D8%AF%D9%8A%D9%83%D8%B3%D8%AA%D8%B1%D8%A7-dijkstra%E2%80%99s-algorithm-r1336/" rel="">خوارزمية ديكسترا Dijkstra’s Algorithm</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1415</guid><pubDate>Sun, 26 Dec 2021 16:00:00 +0000</pubDate></item><item><title>&#x62E;&#x648;&#x627;&#x631;&#x632;&#x645;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x628;&#x62D;&#x62B; &#x648;&#x622;&#x644;&#x64A;&#x629; &#x639;&#x645;&#x644;&#x647;&#x627;</title><link>https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D9%88%D8%A2%D9%84%D9%8A%D8%A9-%D8%B9%D9%85%D9%84%D9%87%D8%A7-r1414/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_12/61cc137332c6a_-01.jpg.0942f0f3b4a4a9c45e469754120aea16.jpg" /></p>
<p>
	سوف نستعرض في هذه المقالة خوارِزميتان من <a href="https://academy.hsoub.com/programming/advanced/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1282/" rel="">خوارزميات</a> البحث الشهيرة، وهما خوارزمية البحث الثنائي، وخوارزمية البحث الخطي، مع تحليلهما وشرح آلية عملهما.
</p>

<h2>
	البحث الثنائي Binary Search
</h2>

<p>
	خوارزمية <a href="https://wiki.hsoub.com/Algorithms/binary_search" rel="external">البحث الثنائي</a> هي خوارزمية بحث في المصفوفات المرتبة تعتمد منظور فرق تسد، وتحتاج هذه الخوارزمية مدة قدرها <code>‎O(log n)‎</code> للعثور على موقع العنصر المبحوث عنه في المصفوفة المرتبة، حيث يمثّل <code>‎n‎</code> مساحة المَبحث، أي المصفوفة التي نبحث فيها.
</p>

<p>
	تبدأ خوارزمية البحث الثنائي في كل خطوة بالتحقق من القيمة الموجودة في منتصف المصفوفة mid، فإن كانت تساوي العنصر المبحوث عنه فإنها تتوقف وتعيد فهرسه؛ وإلا تقسّم المصفوفة إلى اثنتين هما مصفوفة [mid,b] ومصفوفة [a,mid]، حيث يمثل a و b طرفي المصفوفة.
</p>

<p>
	وإن كان العنصر المبحوث عنه موجودا في المصفوفة وكان أكبر من mid، فهذا يعني أنّه سيكون لا محالة في الجزء [mid,b] لأنّ المصفوفة مرتبة؛ أما إذا كان العنصر المبحوث عنه أصغر من mid فهذا يعني أنّه سيكون في الجزء [a,mid].
</p>

<p>
	نختار الآن الجزء المناسب، ونعيد تطبيق الخوارزمية عليه، ونستمر في هذه العملية إلى أن نجد العنصر المبحوث عنه أو تتساوى قيمة mid مع قيمة a، فإن لم تكن قيمة mid تساوي العنصر المبحوث، فهذا يعني أنّه غير موجود في المصفوفة.
</p>

<p>
	إليك مثالًا توضيحيًا؛ لنفترض أنّك خبير اقتصادي وقد تمّ تكليفك بمهمة تحديد سعر التوازن equilibrium price (أي السعر الذي يحقق المعادلة العرض = الطلب) لسلعة الأرز. تذكّر أنه كلما زاد السعر، زاد العرض وقلّ الطلب.
</p>

<p>
	لنفترضّ أنّ الشركة التي تعمل فيها توفر لك جميع المعطيات المتعلقة بالعرض والطلب المتعلقين بالأرز عندما يستقر سعر الأرز عند قيمة معيّنة <code>‎p‎</code>، فعندئذ تستطيع الحصول على العرض والطلب بوحدات الأرز. ويريد رئيسك أن تحسب سعر التوازن في أسرع وقت ممكن، لكن سينبّهك إلى أنّ سعر التوازن يجب أن يكون عددًا صحيحًا موجبًا لا يتجاوز <code>‎10^17‎</code>، كما انّه يضمن لك أنّه سيكون هناك حل عددي صحيح موجب واحد بالضبط في هذا النطاق.
</p>

<p>
	يُسمح لك باستدعاء الدالتين <code>‎getSupply(k)‎</code> و <code>‎getDemand(k)‎</code>، وَاللتان تعيدان كمية العرض وحجم الطلب بالنسبة للسعر K على التوالي.
</p>

<p>
	المبحث أو مساحة البحث هنا هي مصفوفة الأعداد الصحيحة من <code>‎1‎</code> إلى <code>‎10^17‎</code>. ويكون البحث الخطي في هذه الحالة غير مناسب لأنّ المصفوفة مرتّبة. لاحظ أنه كلما ارتفعت قيمة <code>‎k‎</code>، ستزيد قيمة <code>‎getSupply(k)‎</code>، وتنخفض قيمة <code>‎getDemand(k)‎</code>، ومن ثم تكون لدينا المتراجحة التالية:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix" data-gramm="false">
		<p>
			لكل <code>‎x &gt; y‎</code> لدينا: <code>getSupply(x) - getDemand(x) &gt; getSupply(y) - getDemand(y)‎‎</code>
		</p>
	</div>
</blockquote>

<p>
	أي أن زيادة السعر يصاحبها زيادة في الفرق بين العرض والطلب، وهذا منطقي ومتوقع. أيضًا، بما أنّ مساحة المبحث (المصفوفة) مرتّبة، فيمكننا استخدام خوارزمية البحث الثنائي.
</p>

<p>
	المثال التوضيحي التالي يبين كيفية استخدام خوارزمية البحث الثنائي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6499_7" style=""><span class="pln">high </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100000000000000000</span><span class="pln">     </span><span class="pun">&lt;-</span><span class="pln"> </span><span class="pun">الحد</span><span class="pln"> </span><span class="pun">الأقصى</span><span class="pln"> </span><span class="pun">لمساحة</span><span class="pln"> </span><span class="pun">المبحث</span><span class="pln">
low </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">                       </span><span class="pun">&lt;-</span><span class="pln">  </span><span class="pun">الحد</span><span class="pln"> </span><span class="pun">الأدنى</span><span class="pln"> </span><span class="pun">لمساحة</span><span class="pln"> </span><span class="pun">المبحث</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> high </span><span class="pun">-</span><span class="pln"> low </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
   mid </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">high </span><span class="pun">+</span><span class="pln"> low</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pln">    </span><span class="pun">&lt;-</span><span class="pln"> </span><span class="pun">خذ</span><span class="pln"> </span><span class="pun">القيمة</span><span class="pln"> </span><span class="pun">الوسطى</span><span class="pln">
   supply </span><span class="pun">=</span><span class="pln"> getSupply</span><span class="pun">(</span><span class="pln">mid</span><span class="pun">)</span><span class="pln"> 
   demand </span><span class="pun">=</span><span class="pln"> getDemand</span><span class="pun">(</span><span class="pln">mid</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> supply </span><span class="pun">&gt;</span><span class="pln"> demand       
       high </span><span class="pun">=</span><span class="pln"> mid             </span><span class="pun">&lt;-</span><span class="pln"> </span><span class="pun">الحل</span><span class="pln"> </span><span class="pun">موجود</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> </span><span class="pun">النصف</span><span class="pln"> </span><span class="pun">السفلي</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">مساحة</span><span class="pln"> </span><span class="pun">المبحث</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> demand </span><span class="pun">&gt;</span><span class="pln"> supply
       low </span><span class="pun">=</span><span class="pln"> mid              </span><span class="pun">&lt;-</span><span class="pln"> </span><span class="pun">الحل</span><span class="pln"> </span><span class="pun">موجود</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> </span><span class="pun">النصف</span><span class="pln"> </span><span class="pun">العلوي</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">مساحة</span><span class="pln"> </span><span class="pun">المبحث</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln">                       </span><span class="pun">&lt;-</span><span class="pln"> </span><span class="pun">الشرط:</span><span class="pln"> </span><span class="pun">العرض</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="pun">الطلب</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> mid             </span><span class="pun">&lt;-</span><span class="pln"> </span><span class="pun">العثور</span><span class="pln"> </span><span class="pun">على</span><span class="pln"> </span><span class="pun">الحل</span></pre>

<p>
	تستغرق هذه الخوارزمية وقتًا مقداره <code>‎~O(log 10^17)‎</code>. وعمومًا، يساوي تعقيد خوارزمية الترتيب الثنائي <code>‎~O(log S)‎</code>، حيث يمثّل <code>S</code> حجم مصفوفة البحث، لأنّنا نقلّص مساحة البحث إلى النصف في كل تكرار <a href="https://academy.hsoub.com/programming/cpp/%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1%D9%8A%D8%A9-loops-%D9%81%D9%8A-cpp-r893/" rel="">للحلقة while</a>، (من [low: high] إلى [low: mid] أو [mid: high] ).
</p>

<p>
	فيما يلي تطبيق على خوارزمية البحث الثنائي يستخدم التكرارية، في لغة <span class="ipsEmoji">?</span>
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6499_9" style=""><span class="typ">int</span><span class="pln"> binsearch</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> a</span><span class="pun">[],</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> high</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> mid</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">low </span><span class="pun">&gt;</span><span class="pln"> high</span><span class="pun">)</span><span class="pln">
     </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
   mid </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">low </span><span class="pun">+</span><span class="pln"> high</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">x </span><span class="pun">==</span><span class="pln"> a</span><span class="pun">[</span><span class="pln">mid</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">mid</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">x </span><span class="pun">&lt;</span><span class="pln"> a</span><span class="pun">[</span><span class="pln">mid</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       binsearch</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> mid </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       binsearch</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> mid </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> high</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	خوارزمية رابِن كارب Rabin Karp
</h2>

<p>
	خوارزمية رابِن كارب هي خوارزمية بحث نصية تستخدم دالة تعمية hashing للعثور على نمط معيّن من مجموعة من الأنماط النصية في سلسلة نصية، ومتوسط أوقات تشغيلها وأفضلها يساوي المدة O(n + m)‎‎ في المساحة (O(p، حيث يمثّل n طول السلسلة النصية، فيما يمثّل m طول النمط. بالمقابل، فأسوأ أوقات تشغيلها يساوي O(nm)‎‎.
</p>

<p>
	هذا تطبيق لخوارزمية مطابقة السلاسل النصية في لغة جافا، حيث يمثل <code>q</code> عددًا أوليًا، و <code>p</code> يمثل قيمة التجزئة الخاصة بالنمط، و <code>t</code> قيمة التجزئة الخاصة بالنص، و <code>d</code> يمثل عدد الحروف الأبجدية.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6499_11" style=""><span class="kwd">void</span><span class="pln"> </span><span class="typ">RabinfindPattern</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> text</span><span class="pun">,</span><span class="typ">String</span><span class="pln"> pattern</span><span class="pun">){</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> d</span><span class="pun">=</span><span class="lit">128</span><span class="pun">;</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> q</span><span class="pun">=</span><span class="lit">100</span><span class="pun">;</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> n</span><span class="pun">=</span><span class="pln">text</span><span class="pun">.</span><span class="pln">length</span><span class="pun">();</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> m</span><span class="pun">=</span><span class="pln">pattern</span><span class="pun">.</span><span class="pln">length</span><span class="pun">();</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> t</span><span class="pun">=</span><span class="lit">0</span><span class="pun">,</span><span class="pln">p</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> h</span><span class="pun">=</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">,</span><span class="pln">j</span><span class="pun">;</span><span class="pln">
</span><span class="com">//دالة حساب قيمة التجزئة</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;</span><span class="pln">m</span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++)</span><span class="pln">
           h </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">h</span><span class="pun">*</span><span class="pln">d</span><span class="pun">)%</span><span class="pln">q</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;</span><span class="pln">m</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">
       p </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">d</span><span class="pun">*</span><span class="pln">p </span><span class="pun">+</span><span class="pln"> pattern</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">))%</span><span class="pln">q</span><span class="pun">;</span><span class="pln">
       t </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">d</span><span class="pun">*</span><span class="pln">t </span><span class="pun">+</span><span class="pln"> text</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">))%</span><span class="pln">q</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
</span><span class="com">// البحث عن النمط</span><span class="pln">
   </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;</span><span class="pln">end</span><span class="pun">-</span><span class="pln">m</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">
       </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">p</span><span class="pun">==</span><span class="pln">t</span><span class="pun">){</span><span class="pln">
</span><span class="com">// إن تطابقت قيمة التجزئة، فقارن النمط حرفا حرفا</span><span class="pln">
           </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">j</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">j</span><span class="pun">&lt;</span><span class="pln">m</span><span class="pun">;</span><span class="pln">j</span><span class="pun">++)</span><span class="pln">
               </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">text</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">j</span><span class="pun">+</span><span class="pln">i</span><span class="pun">)!=</span><span class="pln">pattern</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">j</span><span class="pun">))</span><span class="pln">
               </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">j</span><span class="pun">==</span><span class="pln">m </span><span class="pun">&amp;&amp;</span><span class="pln"> i</span><span class="pun">&gt;=</span><span class="pln">start</span><span class="pun">)</span><span class="pln">
               </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Pattern match found at index "</span><span class="pun">+</span><span class="pln">i</span><span class="pun">);</span><span class="pln">           
       </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">i</span><span class="pun">&lt;</span><span class="pln">end</span><span class="pun">-</span><span class="pln">m</span><span class="pun">){</span><span class="pln">
           t </span><span class="pun">=(</span><span class="pln">d</span><span class="pun">*(</span><span class="pln">t </span><span class="pun">-</span><span class="pln"> text</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)*</span><span class="pln">h</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> text</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">+</span><span class="pln">m</span><span class="pun">))%</span><span class="pln">q</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">t</span><span class="pun">&lt;</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
               t</span><span class="pun">=</span><span class="pln">t</span><span class="pun">+</span><span class="pln">q</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">   
   </span><span class="pun">}</span><span class="pln">                               
</span><span class="pun">}</span></pre>

<p>
	نقسّم قيمة التجزئة على عدد أولي لتجنب وقوع أيّ تداخل، إذ أنّ القسمة على الأعداد الأولية تقلّل احتمال حدوث تداخل، ولكنّها لا تعدمه، فلا يزال احتمال أن يكون لسلسلتين نصيتين مختلفتين قيمة التجزئة نفسها قائمًا. ولأجل هذا، يجب أن تتحقق من النمط حرفًا حرفًا عند العثور على تطابق، من أجل التأكد أنك حصلت على تطابق تام.
</p>

<p>
	تعيد المعادلة التالية حساب قيمة التجزئة الخاصة بالنمط، أولًا عن طريق إزالة الحرف الموجود في أقصى اليسار، ثم إضافة الحرف الجديد من النص.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6499_13" style=""><span class="pln">t </span><span class="pun">=(</span><span class="pln">d</span><span class="pun">*(</span><span class="pln">t </span><span class="pun">-</span><span class="pln"> text</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">)*</span><span class="pln">h</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> text</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">+</span><span class="pln">m</span><span class="pun">))%</span><span class="pln">q</span><span class="pun">;</span></pre>

<h2>
	تحليل الحالات التعقيدية لخوارزمية البحث الخطي
</h2>

<p>
	كل خوارزمية لها ثلاث حالات تعقيد:
</p>

<ol>
	<li>
		أسوأ حالة.
	</li>
	<li>
		الحالة المتوسطة.
	</li>
	<li>
		أفضل حالة.
	</li>
</ol>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6499_16" style=""><span class="pun">#</span><span class="pln">include </span><span class="pun">&lt;</span><span class="pln">stdio</span><span class="pun">.</span><span class="pln">h</span><span class="pun">&gt;</span><span class="pln">
</span><span class="com">// ‫البحث عن x في arr[]‎‎، في حال العثور على x، تعيد الدالة الفهرس</span><span class="pln">
</span><span class="com">// وإلا أعِد -1</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> search</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> arr</span><span class="pun">[],</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> n</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> x</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">int</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">n</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">arr</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> x</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	برنامج مشغِّل لاختبار الدوال أعلاه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6499_18" style=""><span class="kwd">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
 </span><span class="kwd">int</span><span class="pln"> arr</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln"> </span><span class="lit">15</span><span class="pun">};</span><span class="pln">
 </span><span class="kwd">int</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">30</span><span class="pun">;</span><span class="pln">
 </span><span class="kwd">int</span><span class="pln"> n </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">sizeof</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)/</span><span class="kwd">sizeof</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]);</span><span class="pln">
 printf</span><span class="pun">(</span><span class="str">"%d is present at index %d"</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> search</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">));</span><span class="pln">
 getchar</span><span class="pun">();</span><span class="pln">
 </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span></pre>

<h3>
	تحليل أسوأ حالة
</h3>

<p>
	عند تحليل الحالة الأسوأ نحسب الحد الأعلى لوقت تشغيل الخوارزمية، ويجب أن نعرف الحالة التي تجعل الخوارزمية تنفّذ أقصى عدد من العمليات. وبالنسبة لخوارزمية البحث الخطي، تحدث أسوأ حالة عندما لا يكون العنصر المبحوث عنه (x) موجودًا في المصفوفة، فحينئذ سوف تقارنه دالة البحث <code>search()‎‎</code> مع جميع عناصر المصفوفة المبحوث فيها واحدًا تلو الآخر. وعليه، فإنّ أسوأ حالة تعقيدية في خوارزمية البحث الخطي تساوي ‎<code>Θ‎(n)</code>‎‎.
</p>

<h3>
	تحليل الحالة التعقيدية المتوسطة
</h3>

<p>
	عند تحليل الحالة التعقيدية المتوسطة، نأخذ جميع المدخلات الممكنة ونحسب أوقات تنفيذها بالنسبة لجميع المدخلات، ثمّ نجمع كل القيم المحسوبة ونقسّم المجموع على إجمالي عدد المدخلات. سيكون علينا أن نقدّر توزيع الحالات الممكنة.
</p>

<p>
	لنفترض أنّ جميع الحالات مُوزّعة توزيعًا منتظمًا uniformly distributed -بما في ذلك الحالات التي لا يكون فيها x ضمن المصفوفة-، ثم نجمع جميع تلك الحالات ونقسّم المجموع على (n +1).
</p>

<p>
	هذه صيغة الحالة التعقيدية المتوسطة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="87366" href="https://academy.hsoub.com/uploads/monthly_2021_12/UyxRr.jpg.27d0c3030ec16748349957875bdc289a.jpg" rel="" data-fileext="jpg"><img alt="UyxRr.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="87366" data-unique="u4ca91laj" style="width: 700px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_12/UyxRr.jpg.27d0c3030ec16748349957875bdc289a.jpg"></a>
</p>

<h3>
	تحليل أفضل حالة
</h3>

<p>
	عند تحليل أفضل حالة تعقيدية، نحسب الحد الأدنى لأوقات تشغيل الخوارزمية، ويجب أن نعرف الحالة التي تجعل الخوارزمية تنفّذ أقل عدد من العمليات. تحدث أفضل حالة في مشكلة البحث الخطي عندما يكون x في الموضع الأول، ففي هذه الحالة، سيكون عدد العمليات المُنفّذة ثابتًا (مهما كانت قيمة n)، لذا فإنّ التعقيد الزمني لأفضل حالة يساوي Θ(1)<code>‎‎</code>.
</p>

<p>
	عادةً ما نحلل أداء الخوارزمية بناءً على الحالة الأسوأ، إذ أنّ الحالة الأسوأ تعطينا فكرةً عن أقصى وقت يمكن أن تستغرقه الخوارزمية، وهذه معلومة حيوية؛ بالمقابل، لا يكون حساب الحالة المتوسطة سهلًا في معظم الحالات، وعليه فنادرًا ما نلجأ إليه، وذلك لأنه من أجل إجراء تحليل الحالة المتوسطة سيكون علينا أن نعرف التوزيع الرياضي لجميع المدخلات الممكنة، وذلك من الصعوبة بمكان. بالمقابل، لا يُعَد تحليل أفضل حالة مجديًا، إذ لن نستفيد شيئًا من معرفة الحد الأدنى الذي تستغرقه الخوارزمية، لأنه في الحالة الأسوأ، قد تستغرق الخوارزمية سنوات.
</p>

<p>
	في بعض <a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA/" rel="">الخوارزميات</a>، تكون جميع الحالات متماثلة تقريبًا، إذ لا توجد حالة أسوأ وحالة فضلى، نجد هذا على سبيل المثال في <a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%B1%D8%AA%D9%8A%D8%A8-%D9%88%D8%A3%D8%B4%D9%87%D8%B1%D9%87%D8%A7-r1413/" rel="">خوارزمية الترتيب</a> بالدمج، إذ ينفّذ الترتيب بالدمج عدد ‎Θ‎(nLogn)‎ عملية في جميع الحالات.
</p>

<p>
	تتمايز الحالة الأسوأ عن الفضلى في معظم خوارزميات الترتيب الأخرى، ففي التطبيق التقليدي مثلًا لخوارزمية الترتيب السريع -حيث يُختار المحور في الركن-، تحدث أسوأ حالة عندما تكون المصفوفة المراد ترتيبها مرتّبة سلفا، فيما تحدث أفضل حالة عندما يقسّم المحور المصفوفة إلى نصفين دائمًا؛ أما بالنسبة لخوارِزمية الترتيب بالإدراج، تحدث الحالة الأسوأ عندما تكون المصفوفة المراد ترتيبها مرتبةً ترتيبًا معكوسًا، فيما تحدث أفضل حالة عند تكون المصفوفة مُرتبةً في الاتجاه المراد.
</p>

<h2>
	تطبيق خوارزمية البحث الثنائي على أعداد مرتبة
</h2>

<p>
	هذا مثال توضيحي لتطبيق خوارزمية البحث الثنائي على الأعداد:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_6499_21" style=""><span class="kwd">int</span><span class="pln"> array</span><span class="pun">[</span><span class="lit">1000</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> sorted list of numbers </span><span class="pun">};</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">;</span><span class="pln">  </span><span class="com">// عدد المدخلات في مساحة المبحث</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> high</span><span class="pun">,</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> mid</span><span class="pun">;</span><span class="pln"> </span><span class="com">// قيم مؤقتة</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> x</span><span class="pun">;</span><span class="pln"> </span><span class="com">// القيمة المبحوث عنها</span><span class="pln">
low </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
high </span><span class="pun">=</span><span class="pln"> N </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">while</span><span class="pun">(</span><span class="pln">low </span><span class="pun">&lt;</span><span class="pln"> high</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   mid </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">low </span><span class="pun">+</span><span class="pln"> high</span><span class="pun">)/</span><span class="lit">2</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">array</span><span class="pun">[</span><span class="pln">mid</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> x</span><span class="pun">)</span><span class="pln">
       low </span><span class="pun">=</span><span class="pln"> mid </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln">
       high </span><span class="pun">=</span><span class="pln"> mid</span><span class="pun">;</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln"> 
</span><span class="kwd">if</span><span class="pun">(</span><span class="pln">array</span><span class="pun">[</span><span class="pln">low</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> x</span><span class="pun">)</span><span class="pln">
   </span><span class="com">// low العثور على العنصر عند الفهرس</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
   </span><span class="com">// لم نعثر على العنصر</span></pre>

<p>
	لا تحاول العودة مبكرًا بموازنة العنصر الأوسط array[mid]‎‎ بـ x، فذلك سيضيف عملية موازنة زائدة تبطئ الخوارزمية. لاحظ أن عليك إضافة 1 إلى قيمة <code>low</code> لتجنب أن يُقرّب ناتج القسمة الصحيحة إلى أسفل rounding down.
</p>

<p>
	يتيح الإصدار أعلاه من البحث الثنائي إمكانية إيجاد أصغر فهرس لظهور x في المصفوفة في حال كانت تحتوي عدة نسخ من x، ويمكن تعديل الخوارزمية لجعلها تعيد أكبر فهرس كما تبيّن الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_6499_23" style=""><span class="pln">while(low &lt; high)
   {
       mid = low + ((high - low) / 2);
       if(array[mid] &lt; x || (array[mid] == x &amp;&amp; array[mid + 1] == x))
           low = mid + 1;
       else
           high = mid; 
   }</span></pre>

<p>
	لاحظ أنه بدلًا من إجراء العملية التالية:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_8403_9" style=""><span class="pun">‎</span><span class="pln">mid </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">low </span><span class="pun">+</span><span class="pln"> high</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">‎</span><span class="pln">
</span></pre>

<p>
	فقد يكون الأفضل إجراء العملية الآتية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8403_6" style=""><span class="pun">‎</span><span class="pln">mid </span><span class="pun">=</span><span class="pln"> low </span><span class="pun">+</span><span class="pln"> </span><span class="pun">((</span><span class="pln">high </span><span class="pun">-</span><span class="pln"> low</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)‎</span><span class="pln">
</span></pre>

<p>
	في التطبيقات التي تستهدف لغات مثل Java لتقليل خطر حصول طفح overﬂow في حال كانت المدخلات كبيرة الحجم.
</p>

<h2>
	البحث الخطي linear search
</h2>

<p>
	<a href="https://wiki.hsoub.com/Algorithms/linear_search" rel="external">البحث الخطي</a> هي خوارزمية بسيطة، فهي تمرّ على جميع عناصر المصفوفة حتى تعثر على العنصر المبحوث عنه.
</p>

<p>
	تعقيد هذه الخوارزمية يساوي O(n)‎‎، حيث يمثّل n عدد العناصر. قد تسأل لماذا <code>O(n)‎‎</code>؟ لأنّه في أسوأ حالة، سيكون عليك المرور على جميع عناصر المصفوفة، أي على n عنصر.
</p>

<p>
	يمكن موازنة منظور خوارزمية <a href="https://academy.hsoub.com/programming/advanced/%D8%AF%D9%84%D9%8A%D9%84-%D8%B4%D8%A7%D9%85%D9%84-%D8%B9%D9%86-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%AA%D8%B9%D9%82%D9%8A%D8%AF-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-r1247/" rel="">البحث الخطي</a> بعملية البحث عن كتاب في رفّ من الكتب، إذ سيكون عليك الاطلاع عليها جميعًا حتى تجد الكتاب الذي تريده.
</p>

<p>
	هذا تطبيق لخوارزمية البحث الخطي <a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بلغة بايثون</a>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6499_25" style=""><span class="pln">def linear_search</span><span class="pun">(</span><span class="pln">searchable_list</span><span class="pun">,</span><span class="pln"> query</span><span class="pun">):</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> x in searchable_list</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> query </span><span class="pun">==</span><span class="pln"> x</span><span class="pun">:</span><span class="pln">
           </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">True</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">False</span><span class="pln">
linear_search</span><span class="pun">([</span><span class="str">'apple'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'banana'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'carrot'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'fig'</span><span class="pun">,</span><span class="pln"> </span><span class="str">'garlic'</span><span class="pun">],</span><span class="pln"> </span><span class="str">'fig'</span><span class="pun">)</span><span class="pln"> </span><span class="com">#returns True</span></pre>

<p>
	ترجمة -بتصرّف- للفصل 39 من الكتاب <a href="https://goalkicker.com/AlgorithmsBook/" rel="external nofollow">Algorithms Notes for Professionals</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%86-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1410/" rel="">أمثلة عن أنواع الخوارزميات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-%D8%AF%D9%8A%D9%83%D8%B3%D8%AA%D8%B1%D8%A7-dijkstra%E2%80%99s-algorithm-r1336/" rel="">خوارزمية ديكسترا Dijkstra’s Algorithm</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%A3%D8%B4%D8%AC%D8%A7%D8%B1-r1373/" rel="">خوارزميات تحليل المسارات في الأشجار</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D9%87%D8%A9-greedy-algorithms-r1366/" rel="">الخوارزميات الشرهة Greedy Algorithms</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1414</guid><pubDate>Wed, 22 Dec 2021 16:00:00 +0000</pubDate></item><item><title>&#x62E;&#x648;&#x627;&#x631;&#x632;&#x645;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x62A;&#x631;&#x62A;&#x64A;&#x628; &#x648;&#x623;&#x634;&#x647;&#x631;&#x647;&#x627;</title><link>https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%B1%D8%AA%D9%8A%D8%A8-%D9%88%D8%A3%D8%B4%D9%87%D8%B1%D9%87%D8%A7-r1413/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_12/61cc0aaa75af9_-01.jpg.95328364a723510a5b924fa0b669b9fa.jpg" /></p>
<p>
	سنتحدث في هذه المقالة عن بعض المفاهيم العامة المتعلقة<a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA/" rel=""> بخوارزميات</a> الترتيب، ثم نستعرض 10 من أشهر خوارزميات ترتيب المصفوفات.
</p>

<p>
	قبل أن نواصل، سنعطي بعض التعاريف العامة.
</p>

<ul>
	<li>
		خوارزميات الترتيب المستقرة: تكون خوارزمية ترتيب ما مستقرةً stable إذا كانت تحافظ على الترتيب النسبي للعناصر التي لها نفس قيمة المفتاح الذي يُجرى الترتيب وفقًا له.
	</li>
	<li>
		خوارزميات الترتيب الموضعية In place algorithms: نقول أنّ خوارزمية ترتيب ما هي خوارزمية موضعية In place إذا كانت الذاكرة الإضافية التي تستخدمها أثناء الترتيب تساوي <code>‎O(1)‎</code> (دون احتساب المصفوفة المراد ترتيبها).
	</li>
	<li>
		أسوء حالة تعقيدية Worst case complexity: نقول أنّ أسوء حالة تعقيدية Worst case complexity لخوارزمية تساوي <code>‎O(T(n))‎</code> إذا كان وقت تشغيلها لا يزيد عن <code>‎T(n)‎</code> مهما كانت المدخلات.
	</li>
	<li>
		أفضل حالة تعقيدية Best case complexity: نقول أنّ أفضل حالة تعقيدية Best case complexity لخوارزمية ما تساوي <code>‎O(T(n))‎</code> إذا كان وقت تشغيلها لا يقل عن <code>‎T(n)‎</code> مهما كانت المدخلات.
	</li>
	<li>
		أوسط حالة تعقيدية Average case complexity: نقول أنّ أوسط حالة تعقيدية Average case complexity لخوارزمية ترتيب ما تساوي <code>‎O(T(n))‎</code> إذا كان متوسط أوقات تشغيلها بالنسبة لجميع المدخلات الممكنة يساوي <code>‎T(n)‎</code>.
	</li>
</ul>

<h2>
	استقرار الترتيب Stability in Sorting
</h2>

<p>
	تكون خوارزمية الترتيب مستقرةً إذا كانت تحافظ على الترتيب النسبي للقيم ذات المفاتيح المتساوية في المصفوفة المُدخلة الأصلية بعد ترتيبها. أي إن كانت خوارزمية الترتيب مستقرةً وكان هناك كائنَان لهما مفاتيح متساوية، فسيكون ترتيبُهما في الخرج المُرتّب مماثلًا لتَرتيبهما في المصفوفة المدخلة غير المرتبة. انظر مصفوفة الأزواج التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_7" style=""><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span></pre>

<p>
	سنحاول ترتيب المصفوفة حسب العنصر الأول في كل زوج. سيخرج الترتيب المستقر لهذه القائمة ما يلي:
</p>

<pre class="ipsCode">(1, 2) (3, 4) (8, 6) (9, 7) (9, 3)
</pre>

<p>
	وهو ترتيبٌ مستقر لأنّ <code>‎(9, 3)‎</code> تظهر بعد <code>‎(9, 7)‎</code> في المصفوفة الأصلية أيضًا. أما الترتيب غير مستقر فيكون كما يلي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_3480_9" style=""><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">)</span></pre>

<p>
	قد ينتج عن الترتيب غير المستقر الخرج نفسه الذي يٌنتجه الترتيب المستقر أحيانًا، لكن ليس دائمًا.
</p>

<p>
	هذه بعض أشهر أنواع التراتيب المستقرة:
</p>

<ul>
	<li>
		الترتيب بالدمج Merge sort.
	</li>
	<li>
		الترتيب بالإدراج Insertion sort.
	</li>
	<li>
		ترتيب بالجذر Radix sort .
	</li>
	<li>
		ترتيب Tim.
	</li>
	<li>
		الترتيب بالفقاعات Bubble Sort.
	</li>
</ul>

<p>
	هذه بعض أنواع التراتيب غير المستقرة:
</p>

<ul>
	<li>
		الترتيب بالكومة Heap sort.
	</li>
	<li>
		الترتيب السريع Quick sort.
	</li>
</ul>

<p>
	سوف نستعرض في بقية هذه المقالة 10 خوارزميات ترتيب شهيرة.
</p>

<h2>
	الترتيب بالفقاعات Bubble Sort
</h2>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
	<thead>
		<tr>
			<th>
				المعامِل
			</th>
			<th>
				الوصف
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				ترتيب مستقر
			</td>
			<td>
				نعم
			</td>
		</tr>
		<tr>
			<td>
				ترتيب موضعي
			</td>
			<td>
				نعم
			</td>
		</tr>
		<tr>
			<td>
				أفضل حالة تعقيد
			</td>
			<td>
				<code>(O(n</code>
			</td>
		</tr>
		<tr>
			<td>
				أسوء حالة تعقيد
			</td>
			<td>
				<code>(O(n^2</code>
			</td>
		</tr>
		<tr>
			<td>
				أوسط حالة تعقيد
			</td>
			<td>
				<code>(O(n^2</code>
			</td>
		</tr>
		<tr>
			<td>
				تعقيد المساحة
			</td>
			<td>
				<code>(O(1</code>
			</td>
		</tr>
	</tbody>
</table>

<p>
	توازن خوارزمية الفقاعات <code>‎BubbleSort‎</code> كل زوج متتالي من العناصر في المصفوفة غير المرتبة، ثمّ تبدل مواضعهما إن كان تَرتيبهما خاطئًا. ويوضّح المثال التالي كيفية عمل خوارزمية الفقاعات على المصفوفة <code>‎{6,5,3,1,8,7,2,4}‎</code> (تُحاط الأزواج قيد المقارنة في كل خطوة بالرمز "**"):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_11" style=""><span class="pun">{</span><span class="lit">6</span><span class="pun">,</span><span class="lit">5</span><span class="pun">,</span><span class="lit">3</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">8</span><span class="pun">,</span><span class="lit">7</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">4</span><span class="pun">}</span><span class="pln">
</span><span class="pun">{**</span><span class="lit">5</span><span class="pun">,</span><span class="lit">6</span><span class="pun">**,</span><span class="lit">3</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">8</span><span class="pun">,</span><span class="lit">7</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">4</span><span class="pun">}</span><span class="pln"> </span><span class="pun">--</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">تبديل</span><span class="pln">
</span><span class="pun">{</span><span class="lit">5</span><span class="pun">,**</span><span class="lit">3</span><span class="pun">,</span><span class="lit">6</span><span class="pun">**,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">8</span><span class="pun">,</span><span class="lit">7</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">4</span><span class="pun">}</span><span class="pln"> </span><span class="pun">--</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">تبديل</span><span class="pln">
</span><span class="pun">{</span><span class="lit">5</span><span class="pun">,</span><span class="lit">3</span><span class="pun">,**</span><span class="lit">1</span><span class="pun">,</span><span class="lit">6</span><span class="pun">**,</span><span class="lit">8</span><span class="pun">,</span><span class="lit">7</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">4</span><span class="pun">}</span><span class="pln"> </span><span class="pun">--</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">تبديل</span><span class="pln">
</span><span class="pun">{</span><span class="lit">5</span><span class="pun">,</span><span class="lit">3</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,**</span><span class="lit">6</span><span class="pun">,</span><span class="lit">8</span><span class="pun">**,</span><span class="lit">7</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">4</span><span class="pun">}</span><span class="pln"> </span><span class="pun">--</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">لا</span><span class="pln"> </span><span class="pun">تبديل</span><span class="pln">
</span><span class="pun">{</span><span class="lit">5</span><span class="pun">,</span><span class="lit">3</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">6</span><span class="pun">,**</span><span class="lit">7</span><span class="pun">,</span><span class="lit">8</span><span class="pun">**,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">4</span><span class="pun">}</span><span class="pln"> </span><span class="pun">--</span><span class="pln"> </span><span class="lit">7</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">تبديل</span><span class="pln">
</span><span class="pun">{</span><span class="lit">5</span><span class="pun">,</span><span class="lit">3</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">6</span><span class="pun">,</span><span class="lit">7</span><span class="pun">,**</span><span class="lit">2</span><span class="pun">,</span><span class="lit">8</span><span class="pun">**,</span><span class="lit">4</span><span class="pun">}</span><span class="pln"> </span><span class="pun">--</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">تبديل</span><span class="pln">
</span><span class="pun">{</span><span class="lit">5</span><span class="pun">,</span><span class="lit">3</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">6</span><span class="pun">,</span><span class="lit">7</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,**</span><span class="lit">4</span><span class="pun">,</span><span class="lit">8</span><span class="pun">**}</span><span class="pln"> </span><span class="pun">--</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">تبديل</span></pre>

<p>
	نحصل بعد الدورة الأولى على المصفوفة <code>‎{5,3,1,6,7,2,4,8}‎</code>، لاحظ أنّ أكبر قيمة غير مرتبة في المصفوفة (8 في هذه الحالة) ستصل دائمًا إلى موضعها النهائي. للتأكد من أنّ المصفوفة مرتّبة ترتيبًا صحيحًا وأنّ كل عناصرها في المواضع الصحيحة، سيكون علينا تكرار هذه العملية n-1 مرّة، حيث يمثّل n طول المصفوفة المراد ترتيبها.
</p>

<p>
	خوارزمية الترتيب بالفقاعات التي تُعرف أيضًا باسم الترتيب المتدرّج Sinking Sort، هي خوارزمية ترتيب بسيطة تمرّ مرارًا وتكرارًا على المصفوفة حتى ترتّبها، وتوازن كل زوج متتال من العناصر، ثمّ تبدّلهما إن كان ترتيبهما خاطئًا.
</p>

<p>
	الرسم البياني التالي يمثّل آلية عمل خوارزمية الترتيب بالفقاعات:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="87364" href="https://academy.hsoub.com/uploads/monthly_2021_12/SDHQM.jpg.1824dbcdee74b94f88dd5185d827f170.jpg" rel="" data-fileext="jpg"><img alt="SDHQM.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="87364" data-unique="05la2601w" src="https://academy.hsoub.com/uploads/monthly_2021_12/SDHQM.jpg.1824dbcdee74b94f88dd5185d827f170.jpg"></a>
</p>

<p>
	هذه تطبيقات لخوارزمية الترتيب بالفقاعات بعدة لغات برمجة.
</p>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/cpp/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-c-r802/" rel="">لغة C++‎</a>:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_13" style=""><span class="kwd">void</span><span class="pln"> bubbleSort</span><span class="pun">(</span><span class="typ">vector</span><span class="str">&lt;int&gt;</span><span class="pln">numbers</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
      </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> numbers</span><span class="pun">.</span><span class="pln">size</span><span class="pun">()</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">--)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
          </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">&lt;=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
              </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">numbers</span><span class="pun">[</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> numbers</span><span class="pun">[</span><span class="pln">j</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                  swap</span><span class="pun">(</span><span class="pln">numbers</span><span class="pun">[</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">],</span><span class="pln">numbers</span><span class="pun">(</span><span class="pln">j</span><span class="pun">));</span><span class="pln">
              </span><span class="pun">}</span><span class="pln">
          </span><span class="pun">}</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span></pre>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/c/" rel="">لغة C</a>:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_15" style=""><span class="kwd">void</span><span class="pln"> bubble_sort</span><span class="pun">(</span><span class="kwd">long</span><span class="pln"> </span><span class="typ">list</span><span class="pun">[],</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> n</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
 </span><span class="kwd">long</span><span class="pln"> c</span><span class="pun">,</span><span class="pln"> d</span><span class="pun">,</span><span class="pln"> t</span><span class="pun">;</span><span class="pln">
 </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">c </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">;</span><span class="pln"> c </span><span class="pun">&lt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> c</span><span class="pun">++)</span><span class="pln">
 </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">d </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">;</span><span class="pln"> d </span><span class="pun">&lt;</span><span class="pln"> n </span><span class="pun">-</span><span class="pln"> c </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> d</span><span class="pun">++)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
     </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="typ">list</span><span class="pun">[</span><span class="pln">d</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="typ">list</span><span class="pun">[</span><span class="pln">d</span><span class="pun">+</span><span class="lit">1</span><span class="pun">])</span><span class="pln">
     </span><span class="pun">{</span><span class="pln">
       </span><span class="com">/* تبديل */</span><span class="pln">
       t         </span><span class="pun">=</span><span class="pln"> </span><span class="typ">list</span><span class="pun">[</span><span class="pln">d</span><span class="pun">];</span><span class="pln">
       </span><span class="typ">list</span><span class="pun">[</span><span class="pln">d</span><span class="pun">]</span><span class="pln">   </span><span class="pun">=</span><span class="pln"> </span><span class="typ">list</span><span class="pun">[</span><span class="pln">d</span><span class="pun">+</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
       </span><span class="typ">list</span><span class="pun">[</span><span class="pln">d</span><span class="pun">+</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> t</span><span class="pun">;</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
 </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<ul>
	<li>
		هذا تطبيق يستخدم <a href="https://academy.hsoub.com/programming/cpp/%D8%A7%D9%84%D9%85%D8%A4%D8%B4%D8%B1%D8%A7%D8%AA-pointers-%D9%81%D9%8A-cpp-r912/" rel="">المؤشرات</a>:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3480_19" style=""><span class="pln">void pointer_bubble_sort</span><span class="pun">(</span><span class="pln">long </span><span class="pun">*</span><span class="pln"> list</span><span class="pun">,</span><span class="pln"> long n</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
 long c</span><span class="pun">,</span><span class="pln"> d</span><span class="pun">,</span><span class="pln"> t</span><span class="pun">;</span><span class="pln">
 </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">c </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">;</span><span class="pln"> c </span><span class="pun">&lt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">);</span><span class="pln"> c</span><span class="pun">++)</span><span class="pln">
 </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">d </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">;</span><span class="pln"> d </span><span class="pun">&lt;</span><span class="pln"> n </span><span class="pun">-</span><span class="pln"> c </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> d</span><span class="pun">++)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
     </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">list </span><span class="pun">+</span><span class="pln"> d </span><span class="pun">)</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">*(</span><span class="pln">list</span><span class="pun">+</span><span class="pln">d</span><span class="pun">+</span><span class="lit">1</span><span class="pun">))</span><span class="pln">
     </span><span class="pun">{</span><span class="pln">
       </span><span class="pun">/*</span><span class="pln"> </span><span class="pun">تبديل</span><span class="pln"> </span><span class="pun">*/</span><span class="pln">
       t         </span><span class="pun">=</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">list </span><span class="pun">+</span><span class="pln"> d </span><span class="pun">);</span><span class="pln">
       </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">list </span><span class="pun">+</span><span class="pln"> d </span><span class="pun">)</span><span class="pln">   </span><span class="pun">=</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">list </span><span class="pun">+</span><span class="pln"> d </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
       </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="pln">list </span><span class="pun">+</span><span class="pln"> d </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> t</span><span class="pun">;</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
 </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/c-sharp/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D9%84%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-c-r597/" rel="">لغة C#‎‎</a>:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_21" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">BubbleSort</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">SortBubble</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">var i </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">.</span><span class="typ">Length</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">--)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">var j </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">.</span><span class="typ">Length</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">--)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">input</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">j </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">])</span><span class="pln"> </span><span class="kwd">continue</span><span class="pun">;</span><span class="pln">
               var temp </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">j </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">];</span><span class="pln">
               input</span><span class="pun">[</span><span class="pln">j </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">j</span><span class="pun">];</span><span class="pln">
               input</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">;</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> </span><span class="typ">Main</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">SortBubble</span><span class="pun">(</span><span class="pln">input</span><span class="pun">);</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> input</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/python/%D8%A7%D9%84%D9%85%D8%B1%D8%AC%D8%B9-%D8%A7%D9%84%D8%B4%D8%A7%D9%85%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B9%D9%84%D9%85-%D9%84%D8%BA%D8%A9-%D8%A8%D8%A7%D9%8A%D8%AB%D9%88%D9%86-r735/" rel="">بايثون</a>:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3480_23" style=""><span class="com">#!/usr/bin/python</span><span class="pln">
input_list </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">10</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">11</span><span class="pun">]</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">len</span><span class="pun">(</span><span class="pln">input_list</span><span class="pun">)):</span><span class="pln">
 </span><span class="kwd">for</span><span class="pln"> j </span><span class="kwd">in</span><span class="pln"> range</span><span class="pun">(</span><span class="pln">i</span><span class="pun">):</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">input_list</span><span class="pun">[</span><span class="pln">j</span><span class="pun">])</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> int</span><span class="pun">(</span><span class="pln">input_list</span><span class="pun">[</span><span class="pln">j</span><span class="pun">+</span><span class="lit">1</span><span class="pun">]):</span><span class="pln">
     input_list</span><span class="pun">[</span><span class="pln">j</span><span class="pun">],</span><span class="pln">input_list</span><span class="pun">[</span><span class="pln">j</span><span class="pun">+</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> input_list</span><span class="pun">[</span><span class="pln">j</span><span class="pun">+</span><span class="lit">1</span><span class="pun">],</span><span class="pln">input_list</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln">
</span><span class="kwd">print</span><span class="pln"> input_list</span></pre>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D9%84%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-java-r599/" rel="">جافا</a>:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_25" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">MyBubbleSort</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> bubble_srt</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> array</span><span class="pun">[])</span><span class="pln"> </span><span class="pun">{</span><span class="com">//main logic</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> n </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> k</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> m </span><span class="pun">=</span><span class="pln"> n</span><span class="pun">;</span><span class="pln"> m </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> m</span><span class="pun">--)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
               k </span><span class="pun">=</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
               </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">k</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                   swapNumbers</span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> k</span><span class="pun">,</span><span class="pln"> array</span><span class="pun">);</span><span class="pln">
               </span><span class="pun">}</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
           printNumbers</span><span class="pun">(</span><span class="pln">array</span><span class="pun">);</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> swapNumbers</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> j</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> temp</span><span class="pun">;</span><span class="pln">
       temp </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
       array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">j</span><span class="pun">];</span><span class="pln">
       array</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> printNumbers</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> input</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">", "</span><span class="pun">);</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"\n"</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">23</span><span class="pun">,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">,</span><span class="pln"> </span><span class="lit">34</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
       bubble_srt</span><span class="pun">(</span><span class="pln">input</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D8%A5%D9%84%D9%89-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-javascript-r550/" rel="">جافاسكربت</a>:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3480_27" style=""><span class="pln">       </span><span class="kwd">function</span><span class="pln"> bubbleSort</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln">
         </span><span class="pun">{</span><span class="pln">
               </span><span class="kwd">var</span><span class="pln"> swapped</span><span class="pun">;</span><span class="pln">
               </span><span class="kwd">do</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                   swapped </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
                   </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">var</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> a</span><span class="pun">.</span><span class="pln">length</span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                       </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> a</span><span class="pun">[</span><span class="pln">i</span><span class="pun">+</span><span class="lit">1</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                           </span><span class="kwd">var</span><span class="pln"> temp </span><span class="pun">=</span><span class="pln"> a</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
                           a</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> a</span><span class="pun">[</span><span class="pln">i</span><span class="pun">+</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
                           a</span><span class="pun">[</span><span class="pln">i</span><span class="pun">+</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">;</span><span class="pln">
                           swapped </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
                       </span><span class="pun">}</span><span class="pln">
                   </span><span class="pun">}</span><span class="pln">
               </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">swapped</span><span class="pun">);</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">

  </span><span class="kwd">var</span><span class="pln"> a </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">203</span><span class="pun">,</span><span class="pln"> </span><span class="lit">34</span><span class="pun">,</span><span class="pln"> </span><span class="lit">746</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">984</span><span class="pun">,</span><span class="pln"> </span><span class="lit">198</span><span class="pun">,</span><span class="pln"> </span><span class="lit">764</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">];</span><span class="pln">
  bubbleSort</span><span class="pun">(</span><span class="pln">a</span><span class="pun">);</span><span class="pln">
  console</span><span class="pun">.</span><span class="pln">log</span><span class="pun">(</span><span class="pln">a</span><span class="pun">);</span><span class="pln"> </span><span class="com">// [ 3, 9, 34, 198, 200, 203, 746, 764, 984 ]</span></pre>

<h2>
	الترتيب بالدمج Merge Sort
</h2>

<p>
	<a href="https://wiki.hsoub.com/Algorithms/merge_sort" rel="external">الترتيب بالدمج</a> هي خوارزمية تعتمد مبدأ فرّق تسد، إذ تقسم المصفوفةَ المدخلةَ إلى نصفين بشكل متتابع إلى أن تصبح لدينا n مصفوفة أحادية، حيث n يمثل حجم المصفوفة المُدخلة.
</p>

<p>
	بعد ذلك، تُدمج المصفوفات الجزئية المرتبة مثنى مثنى، إذ يُضاف أصغر العنصرين المتقابلين في المصفوفتين المراد دمجهما في كل خطوة. تستمر هذه العملية إلى حين الانتهاء من بناء المصفوفة المُرتّبة. يوضح المثال التالي آلية عمل خوارزمية الترتيب بالدمج:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="87356" href="https://academy.hsoub.com/uploads/monthly_2021_12/Bs29u.png.6051938770e79ce8751febdaf57bb8ca.png" rel="" data-fileext="png"><img alt="Bs29u.png" class="ipsImage ipsImage_thumbnailed" data-fileid="87356" data-unique="ixejncpvx" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_12/Bs29u.png.6051938770e79ce8751febdaf57bb8ca.png"></a>
</p>

<p>
	التعقيد الزمني للخوارزمية: <code>‎T(n) = 2T(n/2) + Θ(n)‎</code>.
</p>

<p>
	يمكن تطبيق التكرارية أعلاه إما باستخدام طريقة الشجرة التكرارية Recurrence Tree method أو الطريقة الرئيسية (Master method)، يمكنك معرفة تفاصيل هاتين الطريقتين من <a href="https://wiki.hsoub.com/Algorithms/merge_sort" rel="external">هنا</a>.
</p>

<p>
	تعقيد الطريقة الرئيسية يساوي <code>‎Θ(nLogn)‎</code> في جميع الحالات الثلاث (الأسوأ والمتوسطة والفضلى)، ذلك أنّ الترتيب بالدمج يقسّم المصفوفة تعاوديًا إلى أنصاف، ويستغرق وقتًا خطيًا لدمج نصفين، حيث لدينا:
</p>

<ul>
	<li>
		المساحة الإضافية: <code>‎O(n)‎</code>.
	</li>
	<li>
		نموذج الخوارزمية: فرّق تسد.
	</li>
	<li>
		الموضعيّة: على العموم، التطبيقات الشائعة للخوارزمية لا تكون موضعية.
	</li>
	<li>
		مستقرة: نعم.
	</li>
</ul>

<p>
	هذه بعض تطبيقات خوارزمية الدمج في بعض لغات البرمجة:
</p>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/go/%d8%aa%d8%b9%d8%b1%d9%81-%d8%b9%d9%84%d9%89-%d9%84%d8%ba%d8%a9-%d8%a7%d9%84%d8%a8%d8%b1%d9%85%d8%ac%d8%a9-go-r222/" rel="">لغة Go</a>:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_35" style=""><span class="pln">package main
</span><span class="kwd">import</span><span class="pln"> </span><span class="str">"fmt"</span><span class="pln">
func mergeSort</span><span class="pun">(</span><span class="pln">a </span><span class="pun">[]</span><span class="typ">int</span><span class="pun">)</span><span class="pln"> </span><span class="pun">[]</span><span class="typ">int</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> a
   </span><span class="pun">}</span><span class="pln">
   m </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">len</span><span class="pun">(</span><span class="pln">a</span><span class="pun">))</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
   f </span><span class="pun">:=</span><span class="pln"> mergeSort</span><span class="pun">(</span><span class="pln">a</span><span class="pun">[:</span><span class="pln">m</span><span class="pun">])</span><span class="pln">
   s </span><span class="pun">:=</span><span class="pln"> mergeSort</span><span class="pun">(</span><span class="pln">a</span><span class="pun">[</span><span class="pln">m</span><span class="pun">:])</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> merge</span><span class="pun">(</span><span class="pln">f</span><span class="pun">,</span><span class="pln"> s</span><span class="pun">)</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
func merge</span><span class="pun">(</span><span class="pln">f </span><span class="pun">[]</span><span class="typ">int</span><span class="pun">,</span><span class="pln"> s </span><span class="pun">[]</span><span class="typ">int</span><span class="pun">)</span><span class="pln"> </span><span class="pun">[]</span><span class="typ">int</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   var i</span><span class="pun">,</span><span class="pln"> j </span><span class="typ">int</span><span class="pln">
   size </span><span class="pun">:=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln">
   a </span><span class="pun">:=</span><span class="pln"> make</span><span class="pun">([]</span><span class="typ">int</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">,</span><span class="pln"> size</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> z </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> z </span><span class="pun">&lt;</span><span class="pln"> size</span><span class="pun">;</span><span class="pln"> z</span><span class="pun">++</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       lenF </span><span class="pun">:=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span><span class="pln">
       lenS </span><span class="pun">:=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">s</span><span class="pun">)</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> i </span><span class="pun">&gt;</span><span class="pln"> lenF</span><span class="pun">-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> j </span><span class="pun">&lt;=</span><span class="pln"> lenS</span><span class="pun">-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           a</span><span class="pun">[</span><span class="pln">z</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> s</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln">
           j</span><span class="pun">++</span><span class="pln">
       </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> j </span><span class="pun">&gt;</span><span class="pln"> lenS</span><span class="pun">-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> i </span><span class="pun">&lt;=</span><span class="pln"> lenF</span><span class="pun">-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           a</span><span class="pun">[</span><span class="pln">z</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> f</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
           i</span><span class="pun">++</span><span class="pln">
       </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> f</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> s</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           a</span><span class="pun">[</span><span class="pln">z</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> f</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
           i</span><span class="pun">++</span><span class="pln">
       </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           a</span><span class="pun">[</span><span class="pln">z</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> s</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln">
           j</span><span class="pun">++</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> a
</span><span class="pun">}</span><span class="pln">
func main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   a </span><span class="pun">:=</span><span class="pln"> </span><span class="pun">[]</span><span class="typ">int</span><span class="pun">{</span><span class="lit">75</span><span class="pun">,</span><span class="pln"> </span><span class="lit">12</span><span class="pun">,</span><span class="pln"> </span><span class="lit">34</span><span class="pun">,</span><span class="pln"> </span><span class="lit">45</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">123</span><span class="pun">,</span><span class="pln"> </span><span class="lit">32</span><span class="pun">,</span><span class="pln"> </span><span class="lit">56</span><span class="pun">,</span><span class="pln"> </span><span class="lit">32</span><span class="pun">,</span><span class="pln"> </span><span class="lit">99</span><span class="pun">,</span><span class="pln"> </span><span class="lit">123</span><span class="pun">,</span><span class="pln"> </span><span class="lit">11</span><span class="pun">,</span><span class="pln"> </span><span class="lit">86</span><span class="pun">,</span><span class="pln"> </span><span class="lit">33</span><span class="pun">}</span><span class="pln">
   fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln">
   fmt</span><span class="pun">.</span><span class="typ">Println</span><span class="pun">(</span><span class="pln">mergeSort</span><span class="pun">(</span><span class="pln">a</span><span class="pun">))</span><span class="pln">
</span><span class="pun">}</span></pre>

<ul>
	<li>
		لغة C
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_38" style=""><span class="typ">int</span><span class="pln"> merge</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> arr</span><span class="pun">[],</span><span class="typ">int</span><span class="pln"> l</span><span class="pun">,</span><span class="typ">int</span><span class="pln"> m</span><span class="pun">,</span><span class="typ">int</span><span class="pln"> h</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
 </span><span class="typ">int</span><span class="pln"> arr1</span><span class="pun">[</span><span class="lit">10</span><span class="pun">],</span><span class="pln">arr2</span><span class="pun">[</span><span class="lit">10</span><span class="pun">];</span><span class="pln">  </span><span class="com">// مصفوفتان مؤقتتان</span><span class="pln">
 hold the two arrays to be merged
 </span><span class="typ">int</span><span class="pln"> n1</span><span class="pun">,</span><span class="pln">n2</span><span class="pun">,</span><span class="pln">i</span><span class="pun">,</span><span class="pln">j</span><span class="pun">,</span><span class="pln">k</span><span class="pun">;</span><span class="pln">
 n1</span><span class="pun">=</span><span class="pln">m</span><span class="pun">-</span><span class="pln">l</span><span class="pun">+</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
 n2</span><span class="pun">=</span><span class="pln">h</span><span class="pun">-</span><span class="pln">m</span><span class="pun">;</span><span class="pln">
 </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">n1</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln">
   arr1</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]=</span><span class="pln">arr</span><span class="pun">[</span><span class="pln">l</span><span class="pun">+</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
 </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">j</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">&lt;</span><span class="pln">n2</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">++)</span><span class="pln">
   arr2</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]=</span><span class="pln">arr</span><span class="pun">[</span><span class="pln">m</span><span class="pun">+</span><span class="pln">j</span><span class="pun">+</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
 arr1</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]=</span><span class="lit">9999</span><span class="pun">;</span><span class="pln">  </span><span class="com">// لتحديد نهاية كل مصفوفة مؤقتة</span><span class="pln">
 arr2</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]=</span><span class="lit">9999</span><span class="pun">;</span><span class="pln">
 i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">
 j</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">
 </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">k</span><span class="pun">=</span><span class="pln">l</span><span class="pun">;</span><span class="pln"> k</span><span class="pun">&lt;=</span><span class="pln">h</span><span class="pun">;</span><span class="pln"> k</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// دمج مصفوفتين مرتبتين</span><span class="pln">
   </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">arr1</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]&lt;=</span><span class="pln">arr2</span><span class="pun">[</span><span class="pln">j</span><span class="pun">])</span><span class="pln">
     arr</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]=</span><span class="pln">arr1</span><span class="pun">[</span><span class="pln">i</span><span class="pun">++];</span><span class="pln">
   </span><span class="kwd">else</span><span class="pln">
     arr</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]=</span><span class="pln">arr2</span><span class="pun">[</span><span class="pln">j</span><span class="pun">++];</span><span class="pln">
 </span><span class="pun">}</span><span class="pln">
 </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> merge_sort</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> arr</span><span class="pun">[],</span><span class="typ">int</span><span class="pln"> low</span><span class="pun">,</span><span class="typ">int</span><span class="pln"> high</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
 </span><span class="typ">int</span><span class="pln"> mid</span><span class="pun">;</span><span class="pln">
 </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">low</span><span class="pun">&lt;</span><span class="pln">high</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   mid</span><span class="pun">=(</span><span class="pln">low</span><span class="pun">+</span><span class="pln">high</span><span class="pun">)/</span><span class="lit">2</span><span class="pun">;</span><span class="pln">
   </span><span class="com">// فرق تسد</span><span class="pln">
   merge_sort</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">,</span><span class="pln">low</span><span class="pun">,</span><span class="pln">mid</span><span class="pun">);</span><span class="pln">
   merge_sort</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">,</span><span class="pln">mid</span><span class="pun">+</span><span class="lit">1</span><span class="pun">,</span><span class="pln">high</span><span class="pun">);</span><span class="pln">
   </span><span class="com">// Combine</span><span class="pln">
   merge</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">,</span><span class="pln">low</span><span class="pun">,</span><span class="pln">mid</span><span class="pun">,</span><span class="pln">high</span><span class="pun">);</span><span class="pln">
 </span><span class="pun">}</span><span class="pln">
 </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<ul>
	<li>
		‎لغةC# ‎‎
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_40" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">MergeSort</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">Merge</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> l</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> m</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> r</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> j</span><span class="pun">;</span><span class="pln">
           var n1 </span><span class="pun">=</span><span class="pln"> m </span><span class="pun">-</span><span class="pln"> l </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
           var n2 </span><span class="pun">=</span><span class="pln"> r </span><span class="pun">-</span><span class="pln"> m</span><span class="pun">;</span><span class="pln">
           var left </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[</span><span class="pln">n1</span><span class="pun">];</span><span class="pln">
           var right </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[</span><span class="pln">n2</span><span class="pun">];</span><span class="pln">
           </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> n1</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               left</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">l </span><span class="pun">+</span><span class="pln"> i</span><span class="pun">];</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">

           </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">&lt;</span><span class="pln"> n2</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">++)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               right</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">m </span><span class="pun">+</span><span class="pln"> j </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">];</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
           i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
           j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
           var k </span><span class="pun">=</span><span class="pln"> l</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> n1 </span><span class="pun">&amp;&amp;</span><span class="pln"> j </span><span class="pun">&lt;</span><span class="pln"> n2</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">left</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> right</span><span class="pun">[</span><span class="pln">j</span><span class="pun">])</span><span class="pln">
               </span><span class="pun">{</span><span class="pln">
                   input</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> left</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
                   i</span><span class="pun">++;</span><span class="pln">
               </span><span class="pun">}</span><span class="pln">
               </span><span class="kwd">else</span><span class="pln">
               </span><span class="pun">{</span><span class="pln">
                   input</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> right</span><span class="pun">[</span><span class="pln">j</span><span class="pun">];</span><span class="pln">
                   j</span><span class="pun">++;</span><span class="pln">
               </span><span class="pun">}</span><span class="pln">
               k</span><span class="pun">++;</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
           </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;</span><span class="pln"> n1</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               input</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> left</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
               i</span><span class="pun">++;</span><span class="pln">
               k</span><span class="pun">++;</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
           </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">j </span><span class="pun">&lt;</span><span class="pln"> n2</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               input</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> right</span><span class="pun">[</span><span class="pln">j</span><span class="pun">];</span><span class="pln">
               j</span><span class="pun">++;</span><span class="pln">
               k</span><span class="pun">++;</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">SortMerge</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> l</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> r</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">l </span><span class="pun">&lt;</span><span class="pln"> r</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               </span><span class="typ">int</span><span class="pln"> m </span><span class="pun">=</span><span class="pln"> l </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="pln">r </span><span class="pun">-</span><span class="pln"> l</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
               </span><span class="typ">SortMerge</span><span class="pun">(</span><span class="pln">input</span><span class="pun">,</span><span class="pln"> l</span><span class="pun">,</span><span class="pln"> m</span><span class="pun">);</span><span class="pln">
               </span><span class="typ">SortMerge</span><span class="pun">(</span><span class="pln">input</span><span class="pun">,</span><span class="pln"> m </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> r</span><span class="pun">);</span><span class="pln">
               </span><span class="typ">Merge</span><span class="pun">(</span><span class="pln">input</span><span class="pun">,</span><span class="pln"> l</span><span class="pun">,</span><span class="pln"> m</span><span class="pun">,</span><span class="pln"> r</span><span class="pun">);</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> </span><span class="typ">Main</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="typ">SortMerge</span><span class="pun">(</span><span class="pln">input</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> input</span><span class="pun">.</span><span class="typ">Length</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
           </span><span class="kwd">return</span><span class="pln"> input</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span></pre>

<ul>
	<li>
		جافا: هذا تطبيق بلغة جافا يستخدم المقاربة العامة.
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_42" style=""><span class="kwd">public</span><span class="pln"> interface </span><span class="typ">InPlaceSort</span><span class="pun">&lt;</span><span class="pln">T extends </span><span class="typ">Comparable</span><span class="pun">&lt;</span><span class="pln">T</span><span class="pun">&gt;&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">void</span><span class="pln"> sort</span><span class="pun">(</span><span class="pln">final T</span><span class="pun">[]</span><span class="pln"> elements</span><span class="pun">);</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">MergeSort</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> T extends </span><span class="typ">Comparable</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> T </span><span class="pun">&gt;&gt;</span><span class="pln"> implements </span><span class="typ">InPlaceSort</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> T </span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="lit">@Override</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> sort</span><span class="pun">(</span><span class="pln">T</span><span class="pun">[]</span><span class="pln"> elements</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   T</span><span class="pun">[]</span><span class="pln"> arr </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">T</span><span class="pun">[])</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Comparable</span><span class="pun">[</span><span class="pln">elements</span><span class="pun">.</span><span class="pln">length</span><span class="pun">];</span><span class="pln">
   sort</span><span class="pun">(</span><span class="pln">elements</span><span class="pun">,</span><span class="pln"> arr</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> elements</span><span class="pun">.</span><span class="pln">length </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">// نتحقق من كلا الجانبين، ثم ندمجهما</span><span class="pln">
</span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> sort</span><span class="pun">(</span><span class="pln">T</span><span class="pun">[]</span><span class="pln"> elements</span><span class="pun">,</span><span class="pln"> T</span><span class="pun">[]</span><span class="pln"> arr</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> high</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">low </span><span class="pun">&gt;=</span><span class="pln"> high</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> mid </span><span class="pun">=</span><span class="pln"> low </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="pln">high </span><span class="pun">-</span><span class="pln"> low</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
   sort</span><span class="pun">(</span><span class="pln">elements</span><span class="pun">,</span><span class="pln"> arr</span><span class="pun">,</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> mid</span><span class="pun">);</span><span class="pln">
   sort</span><span class="pun">(</span><span class="pln">elements</span><span class="pun">,</span><span class="pln"> arr</span><span class="pun">,</span><span class="pln"> mid </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> high</span><span class="pun">);</span><span class="pln">
   merge</span><span class="pun">(</span><span class="pln">elements</span><span class="pun">,</span><span class="pln"> arr</span><span class="pun">,</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> high</span><span class="pun">,</span><span class="pln"> mid</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> merge</span><span class="pun">(</span><span class="pln">T</span><span class="pun">[]</span><span class="pln"> a</span><span class="pun">,</span><span class="pln"> T</span><span class="pun">[]</span><span class="pln"> b</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> high</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> mid</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> low</span><span class="pun">;</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> j </span><span class="pun">=</span><span class="pln"> mid </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
   </span><span class="com">// b نختار أصغر عنصر منهما، ثم نضعه في </span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> k </span><span class="pun">=</span><span class="pln"> low</span><span class="pun">;</span><span class="pln"> k </span><span class="pun">&lt;=</span><span class="pln"> high</span><span class="pun">;</span><span class="pln"> k</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&lt;=</span><span class="pln"> mid </span><span class="pun">&amp;&amp;</span><span class="pln"> j </span><span class="pun">&lt;=</span><span class="pln"> high</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">compareTo</span><span class="pun">(</span><span class="pln">a</span><span class="pun">[</span><span class="pln">j</span><span class="pun">])</span><span class="pln"> </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
               b</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> a</span><span class="pun">[</span><span class="pln">j</span><span class="pun">++];</span><span class="pln">
           </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
               b</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> a</span><span class="pun">[</span><span class="pln">i</span><span class="pun">++];</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">j </span><span class="pun">&gt;</span><span class="pln"> high </span><span class="pun">&amp;&amp;</span><span class="pln"> i </span><span class="pun">&lt;=</span><span class="pln"> mid</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           b</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> a</span><span class="pun">[</span><span class="pln">i</span><span class="pun">++];</span><span class="pln">
       </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&gt;</span><span class="pln"> mid </span><span class="pun">&amp;&amp;</span><span class="pln"> j </span><span class="pun">&lt;=</span><span class="pln"> high</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           b</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> a</span><span class="pun">[</span><span class="pln">j</span><span class="pun">++];</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> n </span><span class="pun">=</span><span class="pln"> low</span><span class="pun">;</span><span class="pln"> n </span><span class="pun">&lt;=</span><span class="pln"> high</span><span class="pun">;</span><span class="pln"> n</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       a</span><span class="pun">[</span><span class="pln">n</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> b</span><span class="pun">[</span><span class="pln">n</span><span class="pun">];</span><span class="pln">
   </span><span class="pun">}}}</span></pre>

<ul>
	<li>
		Java: هذا تطبيق آخر للخوارزمية بلغة Java، ولكن وفق منظور تصاعدي (من الأسفل إلى الأعلى)
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_44" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">MergeSortBU</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">Integer</span><span class="pun">[]</span><span class="pln"> array </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">15</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln"> </span><span class="lit">70</span><span class="pun">,</span><span class="pln">
</span><span class="lit">60</span><span class="pun">,</span><span class="lit">80</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">9</span><span class="pun">,</span><span class="lit">67</span><span class="pun">,</span><span class="lit">54</span><span class="pun">,</span><span class="lit">51</span><span class="pun">,</span><span class="lit">52</span><span class="pun">,</span><span class="lit">24</span><span class="pun">,</span><span class="lit">54</span><span class="pun">,</span><span class="lit">7</span><span class="pln"> </span><span class="pun">};</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">MergeSortBU</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> merge</span><span class="pun">(</span><span class="typ">Comparable</span><span class="pun">[]</span><span class="pln"> arrayToSort</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Comparable</span><span class="pun">[]</span><span class="pln"> aux</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> lo</span><span class="pun">,</span><span class="typ">int</span><span class="pln"> mid</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> hi</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> index </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> index </span><span class="pun">&lt;</span><span class="pln"> arrayToSort</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> index</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           aux</span><span class="pun">[</span><span class="pln">index</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> arrayToSort</span><span class="pun">[</span><span class="pln">index</span><span class="pun">];</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> lo</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> j </span><span class="pun">=</span><span class="pln"> mid </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> k </span><span class="pun">=</span><span class="pln"> lo</span><span class="pun">;</span><span class="pln"> k </span><span class="pun">&lt;=</span><span class="pln"> hi</span><span class="pun">;</span><span class="pln"> k</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&gt;</span><span class="pln"> mid</span><span class="pun">)</span><span class="pln">
               arrayToSort</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> aux</span><span class="pun">[</span><span class="pln">j</span><span class="pun">++];</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">j </span><span class="pun">&gt;</span><span class="pln"> hi</span><span class="pun">)</span><span class="pln">
               arrayToSort</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> aux</span><span class="pun">[</span><span class="pln">i</span><span class="pun">++];</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isLess</span><span class="pun">(</span><span class="pln">aux</span><span class="pun">[</span><span class="pln">i</span><span class="pun">],</span><span class="pln"> aux</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
               arrayToSort</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> aux</span><span class="pun">[</span><span class="pln">i</span><span class="pun">++];</span><span class="pln">
           </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
               arrayToSort</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> aux</span><span class="pun">[</span><span class="pln">j</span><span class="pun">++];</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> sort</span><span class="pun">(</span><span class="typ">Comparable</span><span class="pun">[]</span><span class="pln"> arrayToSort</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Comparable</span><span class="pun">[]</span><span class="pln"> aux</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> lo</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> hi</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> N </span><span class="pun">=</span><span class="pln"> arrayToSort</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> sz </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> sz </span><span class="pun">&lt;</span><span class="pln"> N</span><span class="pun">;</span><span class="pln"> sz </span><span class="pun">=</span><span class="pln"> sz </span><span class="pun">+</span><span class="pln"> sz</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> low </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> low </span><span class="pun">&lt;</span><span class="pln"> N</span><span class="pun">;</span><span class="pln"> low </span><span class="pun">=</span><span class="pln"> low </span><span class="pun">+</span><span class="pln"> sz </span><span class="pun">+</span><span class="pln"> sz</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
               </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Size:"</span><span class="pun">+</span><span class="pln"> sz</span><span class="pun">);</span><span class="pln">
               merge</span><span class="pun">(</span><span class="pln">arrayToSort</span><span class="pun">,</span><span class="pln"> aux</span><span class="pun">,</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> low </span><span class="pun">+</span><span class="pln"> sz </span><span class="pun">-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">,</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">low </span><span class="pun">+</span><span class="pln"> sz </span><span class="pun">+</span><span class="pln"> sz </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> N </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">));</span><span class="pln">
               print</span><span class="pun">(</span><span class="pln">arrayToSort</span><span class="pun">);</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> boolean isLess</span><span class="pun">(</span><span class="typ">Comparable</span><span class="pln"> a</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Comparable</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> a</span><span class="pun">.</span><span class="pln">compareTo</span><span class="pun">(</span><span class="pln">b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> print</span><span class="pun">(</span><span class="typ">Comparable</span><span class="pun">[]</span><span class="pln"> array</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">http</span><span class="pun">:</span><span class="com">//stackoverflow.com/documentation/algorithm/5732/merge-sort#</span><span class="pln">
       </span><span class="typ">StringBuffer</span><span class="pln"> buffer </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln">
</span><span class="typ">StringBuffer</span><span class="pun">();</span><span class="pln">http</span><span class="pun">:</span><span class="com">//stackoverflow.com/documentation/algorithm/5732/merge-sort#</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Comparable</span><span class="pln"> value </span><span class="pun">:</span><span class="pln"> array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
           buffer</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">value</span><span class="pun">);</span><span class="pln">
           buffer</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="str">' '</span><span class="pun">);</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">buffer</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">Comparable</span><span class="pun">[]</span><span class="pln"> aux </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Comparable</span><span class="pun">[</span><span class="pln">array</span><span class="pun">.</span><span class="pln">length</span><span class="pun">];</span><span class="pln">
       print</span><span class="pun">(</span><span class="pln">array</span><span class="pun">);</span><span class="pln">
       </span><span class="typ">MergeSortBU</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="pln">array</span><span class="pun">,</span><span class="pln"> aux</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> array</span><span class="pun">.</span><span class="pln">length </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<ul>
	<li>
		<a href="https://wiki.hsoub.com/Python" rel="external">بايثون</a>
	</li>
</ul>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3480_46" style=""><span class="kwd">def</span><span class="pln"> merge</span><span class="pun">(</span><span class="pln">X</span><span class="pun">,</span><span class="pln"> Y</span><span class="pun">):</span><span class="pln">
   </span><span class="str">" دمج مصفوفتين مرتبتين "</span><span class="pln">
   p1 </span><span class="pun">=</span><span class="pln"> p2 </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
   out </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
   </span><span class="kwd">while</span><span class="pln"> p1 </span><span class="pun">&lt;</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">X</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> p2 </span><span class="pun">&lt;</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">Y</span><span class="pun">):</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> X</span><span class="pun">[</span><span class="pln">p1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> Y</span><span class="pun">[</span><span class="pln">p2</span><span class="pun">]:</span><span class="pln">
           out</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">X</span><span class="pun">[</span><span class="pln">p1</span><span class="pun">])</span><span class="pln">
           p1 </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
       </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
           out</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">Y</span><span class="pun">[</span><span class="pln">p2</span><span class="pun">])</span><span class="pln">
           p2 </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
   out </span><span class="pun">+=</span><span class="pln"> X</span><span class="pun">[</span><span class="pln">p1</span><span class="pun">:]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> Y</span><span class="pun">[</span><span class="pln">p2</span><span class="pun">:]</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> out
</span><span class="kwd">def</span><span class="pln"> mergeSort</span><span class="pun">(</span><span class="pln">A</span><span class="pun">):</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">A</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> A
   </span><span class="kwd">if</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">A</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> sorted</span><span class="pun">(</span><span class="pln">A</span><span class="pun">)</span><span class="pln">
   mid </span><span class="pun">=</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">A</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> merge</span><span class="pun">(</span><span class="pln">mergeSort</span><span class="pun">(</span><span class="pln">A</span><span class="pun">[:</span><span class="pln">mid</span><span class="pun">]),</span><span class="pln"> mergeSort</span><span class="pun">(</span><span class="pln">A</span><span class="pun">[</span><span class="pln">mid</span><span class="pun">:]))</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> __name__ </span><span class="pun">==</span><span class="pln"> </span><span class="str">"__main__"</span><span class="pun">:</span><span class="pln">
   </span><span class="com"># Generate 20 random numbers and sort them</span><span class="pln">
   A </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">randint</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> i </span><span class="kwd">in</span><span class="pln"> xrange</span><span class="pun">(</span><span class="lit">20</span><span class="pun">)]</span><span class="pln">
   </span><span class="kwd">print</span><span class="pln"> mergeSort</span><span class="pun">(</span><span class="pln">A</span><span class="pun">)</span></pre>

<h2>
	الترتيب بالإدراج
</h2>

<p>
	<a href="https://wiki.hsoub.com/Algorithms/insertion_sort" rel="external">الترتيب بالإدراج</a> هي إحدى خوارزميات الترتيب البسيطة، إذ ترتّب العناصر واحدًا تلو الآخر بنفس الطريقة التي ترتّب فيها أوراق اللعب يدويًّا.
</p>

<p>
	الرسم البياني التالي يوضّح آلية عمل خوارزمية الترتيب بالإدراج:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="87359" href="https://academy.hsoub.com/uploads/monthly_2021_12/Insertion-sort-example-300px.gif.a81a5ede535d4b49fd2c69053afdb28f.gif" rel="" data-fileext="gif"><img alt="Insertion-sort-example-300px.gif" class="ipsImage ipsImage_thumbnailed" data-fileid="87359" data-unique="c5w2x7afo" style="width: 200px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_12/Insertion-sort-example-300px.gif.a81a5ede535d4b49fd2c69053afdb28f.gif"></a>
</p>

<p style="text-align: center;">
	المصدر: ويكيبديا
</p>

<p>
	يمكنك معرفة المزيد من التفاصيل حول آلية عمل الخوارزمية من <a href="https://wiki.hsoub.com/Algorithms/insertion_sort" rel="external">ويكي حسوب</a>.
</p>

<p>
	هذا تطبيق لخوارزمية الترتيب بالإدراج بلغة هاسكل Haskell:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3480_49" style=""><span class="pln">insertSort </span><span class="pun">::</span><span class="pln"> </span><span class="typ">Ord</span><span class="pln"> a </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">[</span><span class="pln">a</span><span class="pun">]</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">[</span><span class="pln">a</span><span class="pun">]</span><span class="pln">
insertSort </span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
insertSort </span><span class="pun">(</span><span class="pln">x</span><span class="pun">:</span><span class="pln">xs</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> insert x </span><span class="pun">(</span><span class="pln">insertSort xs</span><span class="pun">)</span><span class="pln">
insert </span><span class="pun">::</span><span class="pln"> </span><span class="typ">Ord</span><span class="pln"> a </span><span class="pun">=&gt;</span><span class="pln"> a</span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">[</span><span class="pln">a</span><span class="pun">]</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">[</span><span class="pln">a</span><span class="pun">]</span><span class="pln">
insert n </span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">n</span><span class="pun">]</span><span class="pln">
insert n </span><span class="pun">(</span><span class="pln">x</span><span class="pun">:</span><span class="pln">xs</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> n </span><span class="pun">&lt;=</span><span class="pln"> x    </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">n</span><span class="pun">:</span><span class="pln">x</span><span class="pun">:</span><span class="pln">xs</span><span class="pun">)</span><span class="pln">
 </span><span class="pun">|</span><span class="pln"> otherwise </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">:</span><span class="pln">insert n xs</span></pre>

<h2>
	الترتيب بالدلو Bucket Sort
</h2>

<p>
	<a href="https://wiki.hsoub.com/Algorithms/bucket_sort" rel="external">الترتيب بالدلو</a> هي خوارزمية ترتيب توزّع عناصر المصفوفة المراد ترتيبها على عدد من الدلاء (مصفوفات)، ثمّ تُرتّب عناصر كل دلو على حدة باستخدام خوارزمية ترتيب مختلفة، أو بتطبيق خوارزمية الترتيب بالدلو تكراريًا، يمكنك معرفة المزيد من التفاصيل عن هذه الخوارزمية من <a href="https://wiki.hsoub.com/Algorithms/bucket_sort" rel="external">موسوعة حسوب</a>.
</p>

<p>
	هذا تطبيق لخوارزمية الترتيب بالدلو بلغة C#‎‎
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_51" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">BucketSort</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">SortBucket</span><span class="pun">(</span><span class="pln">ref </span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> minValue </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> maxValue </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> k </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">.</span><span class="typ">Length</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">--)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> maxValue</span><span class="pun">)</span><span class="pln"> maxValue </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> minValue</span><span class="pun">)</span><span class="pln"> minValue </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="typ">List</span><span class="str">&lt;int&gt;</span><span class="pun">[]</span><span class="pln"> bucket </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">List</span><span class="str">&lt;int&gt;</span><span class="pun">[</span><span class="pln">maxValue </span><span class="pun">-</span><span class="pln"> minValue </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">];</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> bucket</span><span class="pun">.</span><span class="typ">Length</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">--)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           bucket</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">List</span><span class="str">&lt;int&gt;</span><span class="pun">();</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       foreach </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i in input</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           bucket</span><span class="pun">[</span><span class="pln">i </span><span class="pun">-</span><span class="pln"> minValue</span><span class="pun">].</span><span class="typ">Add</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       foreach </span><span class="pun">(</span><span class="typ">List</span><span class="str">&lt;int&gt;</span><span class="pln"> b in bucket</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">b</span><span class="pun">.</span><span class="typ">Count</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               foreach </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> t in b</span><span class="pun">)</span><span class="pln">
               </span><span class="pun">{</span><span class="pln">
                   input</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> t</span><span class="pun">;</span><span class="pln">
                   k</span><span class="pun">++;</span><span class="pln">
               </span><span class="pun">}</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> </span><span class="typ">Main</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">SortBucket</span><span class="pun">(</span><span class="pln">ref input</span><span class="pun">);</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> input</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	الترتيب السريع Quicksort
</h2>

<p>
	<a href="https://wiki.hsoub.com/Algorithms/quick_sort" rel="external">خوارزمية الترتيب السريع</a> هي خوارزمية ترتيب تنتقي عنصرًا من عناصر المصفوفة وتجعله محورًا، ثمّ تقسّم المصفوفة المعطاة حول ذلك العنصر، بحيث تأتي جميع العناصر الأصغر من المحور قبله، وجميع العناصر الأكبر منه تأتي بعده. تُطبّق الخوارزمية تكراريًا على الأقسام حتى تُرتّب المصفوفة بالكامل، وهناك طريقتان لتقديم هذه الخوارزمية.
</p>

<h3>
	طريقة لوموتو Lomuto
</h3>

<p>
	في هذه الطريقة يُنتقى أحد العناصر ليكون محور الترتيب، وغالبًا ما يكون العنصر الأخير من المصفوفة، ويُحفظ فهرس المحور ثم تُتعقّب المواقع التي تحتوي على العناصر التي تساوي قيمة المحور أو تصغُره، ويُجرى التبديل بين موقعي العنصرين إن عُثِر على عنصر أصغر من المحور، ويُزاد فهرس المحور بواحد. فيما يلي شيفرة عامة للخوارزمية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_54" style=""><span class="pln">partition</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> high</span><span class="pun">)</span><span class="pln"> is
pivot </span><span class="pun">:=</span><span class="pln"> A</span><span class="pun">[</span><span class="pln">high</span><span class="pun">]</span><span class="pln">
i </span><span class="pun">:=</span><span class="pln"> low
</span><span class="kwd">for</span><span class="pln"> j </span><span class="pun">:=</span><span class="pln"> low to high </span><span class="pun">–</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
 </span><span class="kwd">if</span><span class="pln"> A</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">≤</span><span class="pln"> pivot then
        swap A</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> with A</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln">
        i </span><span class="pun">:=</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
swap A</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> with A</span><span class="pun">[</span><span class="pln">high</span><span class="pun">]</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> i</span></pre>

<p>
	آلية الترتيب السريع:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_60" style=""><span class="pln">quicksort</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> high</span><span class="pun">)</span><span class="pln"> is
</span><span class="kwd">if</span><span class="pln"> low </span><span class="pun">&lt;</span><span class="pln"> high then
    p </span><span class="pun">:=</span><span class="pln"> partition</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> high</span><span class="pun">)</span><span class="pln">
    quicksort</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> p </span><span class="pun">–</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
    quicksort</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln"> p </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> high</span><span class="pun">)</span></pre>

<p>
	يوضّح المثال التالي آلية عمل خوارزمية الترتيب السريع:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="87365" href="https://academy.hsoub.com/uploads/monthly_2021_12/UWJZY.gif.109b598590cf2cf5a2e76f4766513ad6.gif" rel="" data-fileext="gif"><img alt="UWJZY.gif" class="ipsImage ipsImage_thumbnailed" data-fileid="87365" data-unique="me5pqirjc" src="https://academy.hsoub.com/uploads/monthly_2021_12/UWJZY.gif.109b598590cf2cf5a2e76f4766513ad6.gif"></a>
</p>

<h3>
	طريقة هور Hoare
</h3>

<p>
	تستخدم طريقة هور مؤشرين يبدآن بالإشارة إلى طرفي المصفوفة المُقسّمة، ثم يتحركان نحو بعضهمًا إلى أن يحصل انقلاب، أي تصبح القيمة الصغرى في الجانب الأيسر من المحور، والكبرى في الجانب الأيمن منه؛ وعند حصول الانقلاب تبدّل الخوارزمية بين موقعي القيمتين وتعاد العملية مرةً أخرى.
</p>

<p>
	عندما تلتقي الفهارس، تتوقف الخوارزمية ويُعاد الفهرس النهائي. تُعد طريقة هور أكثر فعاليةً من طريقة Lomuto، لأنّ عدد التبديلات التي تجريها أقل بثلاث مرات في المتوسط من طريقة Lomuto، كما أنّها أكثر فعاليةً في إنشاء الأقسام حتى عندما تكون جميع القيم متساوية.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_62" style=""><span class="pln">quicksort</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln"> lo</span><span class="pun">,</span><span class="pln"> hi</span><span class="pun">)</span><span class="pln"> is
</span><span class="kwd">if</span><span class="pln"> lo </span><span class="pun">&lt;</span><span class="pln"> hi then
    p </span><span class="pun">:=</span><span class="pln"> partition</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln"> lo</span><span class="pun">,</span><span class="pln"> hi</span><span class="pun">)</span><span class="pln">
    quicksort</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln"> lo</span><span class="pun">,</span><span class="pln"> p</span><span class="pun">)</span><span class="pln">
    quicksort</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln"> p </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> hi</span><span class="pun">)</span></pre>

<p>
	شيفرة عامة لتقسيم المصفوفة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_64" style=""><span class="pln">partition</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln"> lo</span><span class="pun">,</span><span class="pln"> hi</span><span class="pun">)</span><span class="pln"> is
pivot </span><span class="pun">:=</span><span class="pln"> A</span><span class="pun">[</span><span class="pln">lo</span><span class="pun">]</span><span class="pln">
i </span><span class="pun">:=</span><span class="pln"> lo </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
j </span><span class="pun">:=</span><span class="pln"> hi </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
loop forever
 </span><span class="kwd">do</span><span class="pun">:</span><span class="pln">
        i </span><span class="pun">:=</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
 </span><span class="kwd">while</span><span class="pln"> A</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> pivot </span><span class="kwd">do</span><span class="pln">

 </span><span class="kwd">do</span><span class="pun">:</span><span class="pln">
        j </span><span class="pun">:=</span><span class="pln"> j </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
 </span><span class="kwd">while</span><span class="pln"> A</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> pivot </span><span class="kwd">do</span><span class="pln">

 </span><span class="kwd">if</span><span class="pln"> i </span><span class="pun">&gt;=</span><span class="pln"> j then
 </span><span class="kwd">return</span><span class="pln"> j

    swap A</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> with A</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span></pre>

<p>
	هذا تطبيق لخوارزمية الترتيب السريع بلغة بايثون:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3480_66" style=""><span class="kwd">def</span><span class="pln"> quicksort</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">):</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">:</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> arr
    pivot </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">[</span><span class="pln">len</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">]</span><span class="pln">
    left </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">x </span><span class="kwd">for</span><span class="pln"> x </span><span class="kwd">in</span><span class="pln"> arr </span><span class="kwd">if</span><span class="pln"> x </span><span class="pun">&lt;</span><span class="pln"> pivot</span><span class="pun">]</span><span class="pln">
    middle </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">x </span><span class="kwd">for</span><span class="pln"> x </span><span class="kwd">in</span><span class="pln"> arr </span><span class="kwd">if</span><span class="pln"> x </span><span class="pun">==</span><span class="pln"> pivot</span><span class="pun">]</span><span class="pln">
    right </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="pln">x </span><span class="kwd">for</span><span class="pln"> x </span><span class="kwd">in</span><span class="pln"> arr </span><span class="kwd">if</span><span class="pln"> x </span><span class="pun">&gt;</span><span class="pln"> pivot</span><span class="pun">]</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> quicksort</span><span class="pun">(</span><span class="pln">left</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> middle </span><span class="pun">+</span><span class="pln"> quicksort</span><span class="pun">(</span><span class="pln">right</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">print</span><span class="pln"> quicksort</span><span class="pun">([</span><span class="lit">3</span><span class="pun">,</span><span class="lit">6</span><span class="pun">,</span><span class="lit">8</span><span class="pun">,</span><span class="lit">10</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">1</span><span class="pun">])</span></pre>

<p>
	الخرج الناتج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_68" style=""><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pln"> </span><span class="pun">،</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">،</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">،</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">،</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">،</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="pun">،</span><span class="pln"> </span><span class="lit">10</span><span class="pun">]</span></pre>

<p>
	وهذا تطبيق لطريقة Lomuto بلغة جافا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_70" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Solution</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="typ">Scanner</span><span class="pln"> sc </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Scanner</span><span class="pun">(</span><span class="typ">System</span><span class="pun">.</span><span class="pln">in</span><span class="pun">);</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> n </span><span class="pun">=</span><span class="pln"> sc</span><span class="pun">.</span><span class="pln">nextInt</span><span class="pun">();</span><span class="pln">
   </span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> ar </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[</span><span class="pln">n</span><span class="pun">];</span><span class="pln">
   </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">n</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln">
     ar</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> sc</span><span class="pun">.</span><span class="pln">nextInt</span><span class="pun">();</span><span class="pln">
    quickSort</span><span class="pun">(</span><span class="pln">ar</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> ar</span><span class="pun">.</span><span class="pln">length</span><span class="pun">-</span><span class="lit">1</span><span class="pun">);</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> quickSort</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> ar</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> high</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">low</span><span class="pun">&lt;</span><span class="pln">high</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> p </span><span class="pun">=</span><span class="pln"> partition</span><span class="pun">(</span><span class="pln">ar</span><span class="pun">,</span><span class="pln"> low</span><span class="pun">,</span><span class="pln"> high</span><span class="pun">);</span><span class="pln">
       quickSort</span><span class="pun">(</span><span class="pln">ar</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">,</span><span class="pln"> p</span><span class="pun">-</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
       quickSort</span><span class="pun">(</span><span class="pln">ar</span><span class="pun">,</span><span class="pln"> p</span><span class="pun">+</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> high</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">   
</span><span class="pun">}</span><span class="pln"> 
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> partition</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> ar</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> l</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> r</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> pivot </span><span class="pun">=</span><span class="pln"> ar</span><span class="pun">[</span><span class="pln">r</span><span class="pun">];</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln">l</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> j</span><span class="pun">=</span><span class="pln">l</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">&lt;</span><span class="pln">r</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">++)</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">ar</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> pivot</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
           </span><span class="typ">int</span><span class="pln"> t </span><span class="pun">=</span><span class="pln"> ar</span><span class="pun">[</span><span class="pln">j</span><span class="pun">];</span><span class="pln">
           ar</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> ar</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
           ar</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> t</span><span class="pun">;</span><span class="pln">
           i</span><span class="pun">++;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> t </span><span class="pun">=</span><span class="pln"> ar</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
   ar</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> ar</span><span class="pun">[</span><span class="pln">r</span><span class="pun">];</span><span class="pln">
   ar</span><span class="pun">[</span><span class="pln">r</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> t</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	الترتيب بالعد Counting Sort
</h2>

<ul>
	<li>
		المساحة الإضافية: <code>‎O(n+k)‎</code>
	</li>
	<li>
		التعقيد الزمني:
	</li>
	<li>
		الحالة الأسوأ: <code>‎O(n+k)‎</code>.
	</li>
	<li>
		الحالة الأفضل: <code>‎O(n)‎</code>.
	</li>
	<li>
		الحالة المتوسطة <code>‎O(n+k)‎</code>.
	</li>
</ul>

<p>
	<a href="https://wiki.hsoub.com/Algorithms/counting_sort" rel="external">الترتيب بالعد</a> Counting sort هي خوارزمية لترتيب الكائنات وفقًا لمفاتيحها.
</p>

<p>
	خطوات الخوارزمية:
</p>

<ol>
	<li>
		أنشئ مصفوفة C حجمها يساوي عدد العناصر الفريدة في المصفوفة المُدخلة A.
	</li>
	<li>
		املأ المصفوفة <span class="ipsEmoji">?</span> لكل x عنصر فريد من المصفوفة المُدخلة، تحتوي C[x]‎‎ تردّد ذلك العنصر في المصفوفة المُدخلة A.
	</li>
	<li>
		حوّل C إلى مصفوفة بحيث يشير C[x]‎‎ إلى عدد القيم التي تصغُر x عبر التكرار في المصفوفة، وعيّن مجموع القيمة السابقة لكل C [x]‎‎، وكذلك جميع القيم في C التي تظهر قبله.
	</li>
	<li>
		كرِّر خلفيًا على المصفوفة A مع وضع كل قيمة في مصفوفة B جديدة مرتبة في الفهرس المسجّل في C. ولكل A [x]‎‎، نعيّن قيمة B [C [A [x]]]‎‎ إلى A [x]‎‎، مع إنقاص قيمة C [A [x]]‎‎ بمقدار واحد في حال وجود قيم مكرّرة في المصفوفة الأصلية غير المرتبة.
	</li>
</ol>

<p>
	يوضّح المثال التالي آلية عمل خوارزمية الترتيب بالعد:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="87358" href="https://academy.hsoub.com/uploads/monthly_2021_12/ccdTK.jpg.263411352491472a7bcffb5bebb8fe00.jpg" rel="" data-fileext="jpg"><img alt="ccdTK.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="87358" data-unique="n99xunqxx" src="https://academy.hsoub.com/uploads/monthly_2021_12/ccdTK.jpg.263411352491472a7bcffb5bebb8fe00.jpg"></a>
</p>

<p>
	وفي ما يلي مثال توضيحي للخوارزمية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_74" style=""><span class="kwd">for</span><span class="pln"> x in input</span><span class="pun">:</span><span class="pln">
   count</span><span class="pun">[</span><span class="pln">key</span><span class="pun">(</span><span class="pln">x</span><span class="pun">)]</span><span class="pln"> </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
total </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i in range</span><span class="pun">(</span><span class="pln">k</span><span class="pun">):</span><span class="pln">
   oldCount </span><span class="pun">=</span><span class="pln"> count</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
   count</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> total
   total </span><span class="pun">+=</span><span class="pln"> oldCount
</span><span class="kwd">for</span><span class="pln"> x in input</span><span class="pun">:</span><span class="pln">
   output</span><span class="pun">[</span><span class="pln">count</span><span class="pun">[</span><span class="pln">key</span><span class="pun">(</span><span class="pln">x</span><span class="pun">)]]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> x
   count</span><span class="pun">[</span><span class="pln">key</span><span class="pun">(</span><span class="pln">x</span><span class="pun">)]</span><span class="pln"> </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> output</span></pre>

<p>
	يمكنك الاطلاع على المزيد من التفاصيل والأمثلة التوضيحية عن خوارزمية الترتيب بالعدّ من <a href="https://wiki.hsoub.com/Algorithms/counting_sort" rel="external">موسوعة حسوب</a>
</p>

<h2>
	الترتيب بالكومة Heap Sort
</h2>

<ul>
	<li>
		المساحة الإضافية: <code>‎O(1)‎</code>.
	</li>
	<li>
		التعقيد الزمني<code>:O(nlogn)‎</code>.
	</li>
</ul>

<p>
	<a href="https://wiki.hsoub.com/Algorithms/heap_sort" rel="external">الترتيب بالكومة</a> هي خوارزمية تستند على <a href="https://wiki.hsoub.com/Algorithms/heaps" rel="external">الكومة الثنائية</a> Binary Heap، وهي مشابهة لخوارزمية الترتيب بالتحديد Selection Sort التي تعتمد على اختيار العنصر الأكبر في المصفوفة في البداية، ثمّ تضعه في نهاية المصفوفة، ثمّ تعيد العملية على بقية العناصر.
</p>

<p>
	هذا مثال توضيحي لخوارزمية الترتيب بالكومة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_76" style=""><span class="pln">function heapsort</span><span class="pun">(</span><span class="pln">input</span><span class="pun">,</span><span class="pln"> count</span><span class="pun">)</span><span class="pln">

   heapify</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln">count</span><span class="pun">)</span><span class="pln">
   end </span><span class="pun">&lt;-</span><span class="pln"> count </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
   </span><span class="kwd">while</span><span class="pln"> end </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
   swap</span><span class="pun">(</span><span class="pln">a</span><span class="pun">[</span><span class="pln">end</span><span class="pun">],</span><span class="pln">a</span><span class="pun">[</span><span class="lit">0</span><span class="pun">])</span><span class="pln">
   end</span><span class="pun">&lt;-</span><span class="pln">end</span><span class="pun">-</span><span class="lit">1</span><span class="pln">
   restore</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> end</span><span class="pun">)</span><span class="pln">
function heapify</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> count</span><span class="pun">)</span><span class="pln">
   start </span><span class="pun">&lt;-</span><span class="pln"> parent</span><span class="pun">(</span><span class="pln">count </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">while</span><span class="pln"> start </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
       restore</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> start</span><span class="pun">,</span><span class="pln"> count </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln">
       start </span><span class="pun">&lt;-</span><span class="pln"> start </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	وهذا مثال على آلية عمل خوارزمية الترتيب بالكومة على المصفوفة [2,3,7,1,8,5,6]:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="87363" href="https://academy.hsoub.com/uploads/monthly_2021_12/rxRGq.png.81a0e698a702c1648263cc24b3a0ec93.png" rel="" data-fileext="png"><img alt="rxRGq.png" class="ipsImage ipsImage_thumbnailed" data-fileid="87363" data-unique="cyhm8dx55" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_12/rxRGq.png.81a0e698a702c1648263cc24b3a0ec93.png"></a>
</p>

<p>
	هذا تطبيق لخوارزمية الترتيب بالكومة بلغة C#‎‎:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_80" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">HeapSort</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">Heapify</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> n</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> largest </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> l </span><span class="pun">=</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> r </span><span class="pun">=</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">l </span><span class="pun">&lt;</span><span class="pln"> n </span><span class="pun">&amp;&amp;</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">l</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">largest</span><span class="pun">])</span><span class="pln">
           largest </span><span class="pun">=</span><span class="pln"> l</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">r </span><span class="pun">&lt;</span><span class="pln"> n </span><span class="pun">&amp;&amp;</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">r</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">largest</span><span class="pun">])</span><span class="pln">
           largest </span><span class="pun">=</span><span class="pln"> r</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">largest </span><span class="pun">!=</span><span class="pln"> i</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           var temp </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
           input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">largest</span><span class="pun">];</span><span class="pln">
           input</span><span class="pun">[</span><span class="pln">largest</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">;</span><span class="pln">
           </span><span class="typ">Heapify</span><span class="pun">(</span><span class="pln">input</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">,</span><span class="pln"> largest</span><span class="pun">);</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">SortHeap</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> n</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">var i </span><span class="pun">=</span><span class="pln"> n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">--)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="typ">Heapify</span><span class="pun">(</span><span class="pln">input</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">);</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> j </span><span class="pun">=</span><span class="pln"> n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">--)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           var temp </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="lit">0</span><span class="pun">];</span><span class="pln">
           input</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">j</span><span class="pun">];</span><span class="pln">
           input</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">;</span><span class="pln">
           </span><span class="typ">Heapify</span><span class="pun">(</span><span class="pln">input</span><span class="pun">,</span><span class="pln"> j</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> </span><span class="typ">Main</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">SortHeap</span><span class="pun">(</span><span class="pln">input</span><span class="pun">,</span><span class="pln"> input</span><span class="pun">.</span><span class="typ">Length</span><span class="pun">);</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> input</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	الترتيب بالتدوير Cycle Sort
</h2>

<p>
	<a href="https://wiki.hsoub.com/Algorithms/cycle_sort" rel="external">الترتيب بالتدوير</a> هي خوارزمية موضعية غير مستقرة، وتُعدّ مثاليةً من حيث عدد مرات الكتابة في المصفوفة الأصلية وعدد مرات الكتابة في الذاكرة، فكل عنصر يُكتب إمّا مرةً واحدةً إن لم يكن في موضعه الصحيح، أو لا يُكتب على الإطلاق.
</p>

<p>
	يمكنك معرفة المزيد من التفاصيل والأمثلة التوضيحية عن خوارزمية الترتيب بالتدوير من <a href="https://wiki.hsoub.com/Algorithms/cycle_sort" rel="external">موسوعة حسوب</a>
</p>

<p>
	هذا مثال توضيحي عن تطبيق على الخوارزمية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_83" style=""><span class="pun">(</span><span class="pln">input</span><span class="pun">)</span><span class="pln">
output </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> cycleStart from </span><span class="lit">0</span><span class="pln"> to length</span><span class="pun">(</span><span class="pln">array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
   item </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">cycleStart</span><span class="pun">]</span><span class="pln">
   pos </span><span class="pun">=</span><span class="pln"> cycleStart
   </span><span class="kwd">for</span><span class="pln"> i from cycleStart </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to length</span><span class="pun">(</span><span class="pln">array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> item</span><span class="pun">:</span><span class="pln">
           pos </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> pos </span><span class="pun">==</span><span class="pln"> cycleStart</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">continue</span><span class="pln">
   </span><span class="kwd">while</span><span class="pln"> item </span><span class="pun">==</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">pos</span><span class="pun">]:</span><span class="pln">
       pos </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
   array</span><span class="pun">[</span><span class="pln">pos</span><span class="pun">],</span><span class="pln"> item </span><span class="pun">=</span><span class="pln"> item</span><span class="pun">,</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">pos</span><span class="pun">]</span><span class="pln">
   writes </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
   </span><span class="kwd">while</span><span class="pln"> pos </span><span class="pun">!=</span><span class="pln"> cycleStart</span><span class="pun">:</span><span class="pln">
       pos </span><span class="pun">=</span><span class="pln"> cycleStart
       </span><span class="kwd">for</span><span class="pln"> i from cycleStart </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to length</span><span class="pun">(</span><span class="pln">array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> item</span><span class="pun">:</span><span class="pln">
               pos </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
       </span><span class="kwd">while</span><span class="pln"> item </span><span class="pun">==</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">pos</span><span class="pun">]:</span><span class="pln">
           pos </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
       array</span><span class="pun">[</span><span class="pln">pos</span><span class="pun">],</span><span class="pln"> item </span><span class="pun">=</span><span class="pln"> item</span><span class="pun">,</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">pos</span><span class="pun">]</span><span class="pln">
       writes </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> outout</span></pre>

<h2>
	ترتيب الفردي-الزوجي Odd-Even Sort
</h2>

<ul>
	<li>
		المساحة الإضافية: <code>‎O(n)‎</code>
	</li>
	<li>
		التعقيد الزمني: <code>‎O(n)‎</code>
	</li>
</ul>

<p>
	<a href="https://wiki.hsoub.com/Algorithms/odd_even_sort" rel="external">خوارزمية ترتيب الفردي-الزوجي</a> Odd-Even Sort (أو الترتيب بالطوب Brick sort هي خوارزمية ترتيب بسيطة طُوِّرت لتُستخدم مع المعالجات المتوازية ذات التقاطعات المحلية parallel processors with local interconnection.
</p>

<p>
	توازن هذه الخوارزمية بين جميع أزواج العناصر المتجاورة ذات الفهارس الفردية / الزوجية في المصفوفة، وتبدل العناصر إذا وجدت أنّ الزوج مرتّب ترتيبًا خاطئًا. تكرر الخوارزمية الخطوة نفسها، لكن هذه المرة على الأزواج ذات الفهارس الزوجية / الفردية، وتستمر في المناوبة بين النمط زوجي / فردي وفردي / زوجي إلى أن تُرتّب المصفوفة.
</p>

<p>
	هذا مثال توضيحي لخوارزمية الطوب Brick:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_85" style=""><span class="kwd">if</span><span class="pln"> n</span><span class="pun">&gt;</span><span class="lit">2</span><span class="pln"> then
   </span><span class="lit">1.</span><span class="pln"> apply odd</span><span class="pun">-</span><span class="pln">even merge</span><span class="pun">(</span><span class="pln">n</span><span class="pun">/</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> recursively to the even subsequence a0</span><span class="pun">,</span><span class="pln"> a2</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...,</span><span class="pln"> an</span><span class="pun">-</span><span class="lit">2</span><span class="pln"> and to the
odd subsequence a1</span><span class="pun">,</span><span class="pln"> a3</span><span class="pun">,</span><span class="pln"> </span><span class="pun">,</span><span class="pln"> </span><span class="pun">...,</span><span class="pln"> an</span><span class="pun">-</span><span class="lit">1</span><span class="pln">
   </span><span class="lit">2.</span><span class="pln"> comparison </span><span class="pun">[</span><span class="pln">i </span><span class="pun">:</span><span class="pln"> i</span><span class="pun">+</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> all i element </span><span class="pun">{</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln"> </span><span class="pun">...,</span><span class="pln"> n</span><span class="pun">-</span><span class="lit">3</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
   comparison </span><span class="pun">[</span><span class="lit">0</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">]</span></pre>

<p>
	هذا رسم توضيحي لآلية عمل خوارزمية الترتيب فردي/زوجي على مجموعة عشوائية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="87362" href="https://academy.hsoub.com/uploads/monthly_2021_12/Odd_even_sort_animation.gif.4921741f55da2db9d1fdfb6fac3638f3.gif" rel="" data-fileext="gif"><img alt="Odd_even_sort_animation.gif" class="ipsImage ipsImage_thumbnailed" data-fileid="87362" data-unique="6cxj9q7zf" src="https://academy.hsoub.com/uploads/monthly_2021_12/Odd_even_sort_animation.gif.4921741f55da2db9d1fdfb6fac3638f3.gif"></a>
</p>

<p style="text-align: center;">
	المصدر: ويكيبيديا
</p>

<p>
	وهذا مثال توضيحي على الخوارزمية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="87361" href="https://academy.hsoub.com/uploads/monthly_2021_12/odd-even-sort.png.18623197d1aa7fc60e9736a9e34312f1.png" rel="" data-fileext="png"><img alt="odd-even-sort.png" class="ipsImage ipsImage_thumbnailed" data-fileid="87361" data-unique="pacnr6pil" style="width: 400px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_12/odd-even-sort.png.18623197d1aa7fc60e9736a9e34312f1.png"></a>
</p>

<p>
	وفيما يلي تطبيق بلغة C#‎‎ لخوارزمية الترتيب بقوالب الطوب:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_87" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">OddEvenSort</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">SortOddEven</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> n</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       var sort </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">sort</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           sort </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">var i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">])</span><span class="pln"> </span><span class="kwd">continue</span><span class="pun">;</span><span class="pln">
               var temp </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
               input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">];</span><span class="pln">
               input</span><span class="pun">[</span><span class="pln">i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">;</span><span class="pln">
               sort </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
           </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">var i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">+=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">])</span><span class="pln"> </span><span class="kwd">continue</span><span class="pun">;</span><span class="pln">
               var temp </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
               input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">];</span><span class="pln">
               input</span><span class="pun">[</span><span class="pln">i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">;</span><span class="pln">
               sort </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> </span><span class="typ">Main</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">SortOddEven</span><span class="pun">(</span><span class="pln">input</span><span class="pun">,</span><span class="pln"> input</span><span class="pun">.</span><span class="typ">Length</span><span class="pun">);</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> input</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	الترتيب بالتحديد Selection Sort
</h2>

<ul>
	<li>
		المساحة الإضافية: <code>‎O(n)‎</code>
	</li>
	<li>
		التعقيد الزمني: <code>‎O(n^2)‎</code>
	</li>
</ul>

<p>
	<a href="https://wiki.hsoub.com/Algorithms/selection_sort" rel="external">الترتيب بالتحديد</a> هي خوارزمية موضعية لترتيب المصفوفات، تعقيدها الزمني يساوي O (n2)‎‎، ما يجعلها غير فعالة مع المصفوفات الكبيرة، وعادةً ما يكون أداؤها أسوأ من خوارزميات الإدراج المماثلة. بالمقابل، تتميّز خوارزمية الترتيب بالتحديد بالبساطة وقد تتفوّق أداءً على بعض <a href="https://academy.hsoub.com/programming/advanced/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1345/" rel="">الخوارزميات</a> الأعقد في بعض الحالات، خاصّةً عندما تكون الذاكرة الإضافية محدودة.
</p>

<p>
	تقسّم الخوارزمية المصفوفة إلى قسمين هما مصفوفة تضم العناصر المرتبة فعليًا، والتي تُبنى من اليسار إلى اليمين من مقدمة المصفوفة (اليسرى)؛ فيما تضم المصفوفة الأخرى العناصر المتبقية التي تنتظر أن تُرتّب، والتي تشغل بقية المصفوفة.
</p>

<p>
	وتكون المصفوفة المرتّبة فارغةً في البداية، بينما تحتوى المصفوفة غير المرتّبة كل عناصر المصفوفة المُدخلة. تبحث الخوارزمية عن أصغر عنصر (أو أكبر عنصر، بحسب غرض الترتيب) في المصفوفة غير المرتّبة وتبدّله بالعنصر غير المرتّب الموجود في أقصى اليسار (أي تضعه في المكان الصحيح)، ثمّ تنقل حدود المصفوفة الفرعية عنصرًا واحدًا إلى اليمين .
</p>

<p>
	هذا مثال توضيحي للخوارزمية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_89" style=""><span class="pln">function select</span><span class="pun">(</span><span class="typ">list</span><span class="pun">[</span><span class="lit">1.</span><span class="pun">.</span><span class="pln">n</span><span class="pun">],</span><span class="pln"> k</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i from </span><span class="lit">1</span><span class="pln"> to k
    minIndex </span><span class="pun">=</span><span class="pln"> i
    minValue </span><span class="pun">=</span><span class="pln"> </span><span class="typ">list</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> j from i</span><span class="pun">+</span><span class="lit">1</span><span class="pln"> to n
        </span><span class="kwd">if</span><span class="pln"> </span><span class="typ">list</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> minValue
            minIndex </span><span class="pun">=</span><span class="pln"> j
            minValue </span><span class="pun">=</span><span class="pln"> </span><span class="typ">list</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln">
    swap </span><span class="typ">list</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> and </span><span class="typ">list</span><span class="pun">[</span><span class="pln">minIndex</span><span class="pun">]</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> </span><span class="typ">list</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span></pre>

<p>
	وهذا تمثيل بصري للخوارزمية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="87360" href="https://academy.hsoub.com/uploads/monthly_2021_12/LZepY.gif.7c5958efbb5fb250277ba7c2d67ec805.gif" rel="" data-fileext="gif"><img alt="LZepY.gif" class="ipsImage ipsImage_thumbnailed" data-fileid="87360" data-unique="p4y08g6ou" style="width: 250px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_12/LZepY.gif.7c5958efbb5fb250277ba7c2d67ec805.gif"></a>
</p>

<p>
	وهذا مثال على خوارزمية الترتيب بالتحديد:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="87357" href="https://academy.hsoub.com/uploads/monthly_2021_12/CaSlf.jpg.aa86b4ee1dbb3278dc9b2852dbf5cc3f.jpg" rel="" data-fileext="jpg"><img alt="CaSlf.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="87357" data-unique="snt2is5sz" style="width: 300px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_12/CaSlf.thumb.jpg.9227ef2cc6fa54a5b38f204709504b7f.jpg"></a>
</p>

<p>
	فيما يلي تطبيق على لخوارزمية بلغة C #‎‎:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_91" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">SelectionSort</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">SortSelection</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> n</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> n </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           var minId </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
           </span><span class="typ">int</span><span class="pln"> j</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">j </span><span class="pun">=</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">&lt;</span><span class="pln"> n</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">++)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">input</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">minId</span><span class="pun">])</span><span class="pln"> minId </span><span class="pun">=</span><span class="pln"> j</span><span class="pun">;</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
           var temp </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">minId</span><span class="pun">];</span><span class="pln">
           input</span><span class="pun">[</span><span class="pln">minId</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
           input</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> </span><span class="typ">Main</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> input</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">SortSelection</span><span class="pun">(</span><span class="pln">input</span><span class="pun">,</span><span class="pln"> input</span><span class="pun">.</span><span class="typ">Length</span><span class="pun">);</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> input</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	وهذا تطبيق على الخوارزمية بلغة إكسير Elixir:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3480_93" style=""><span class="pln">defmodule </span><span class="typ">Selection</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
 def sort</span><span class="pun">(</span><span class="typ">list</span><span class="pun">)</span><span class="pln"> when is_list</span><span class="pun">(</span><span class="typ">list</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
   do_selection</span><span class="pun">(</span><span class="typ">list</span><span class="pun">,</span><span class="pln"> </span><span class="pun">[])</span><span class="pln">
 end
 def do_selection</span><span class="pun">([</span><span class="pln">head</span><span class="pun">|[]],</span><span class="pln"> acc</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
   acc </span><span class="pun">++</span><span class="pln"> </span><span class="pun">[</span><span class="pln">head</span><span class="pun">]</span><span class="pln">
 end
 def do_selection</span><span class="pun">(</span><span class="typ">list</span><span class="pun">,</span><span class="pln"> acc</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
   min </span><span class="pun">=</span><span class="pln"> min</span><span class="pun">(</span><span class="typ">list</span><span class="pun">)</span><span class="pln">
   do_selection</span><span class="pun">(:</span><span class="pln">lists</span><span class="pun">.</span><span class="kwd">delete</span><span class="pun">(</span><span class="pln">min</span><span class="pun">,</span><span class="pln"> </span><span class="typ">list</span><span class="pun">),</span><span class="pln"> acc </span><span class="pun">++</span><span class="pln"> </span><span class="pun">[</span><span class="pln">min</span><span class="pun">])</span><span class="pln">
 end
 defp min</span><span class="pun">([</span><span class="pln">first</span><span class="pun">|[</span><span class="pln">second</span><span class="pun">|[]]])</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
   smaller</span><span class="pun">(</span><span class="pln">first</span><span class="pun">,</span><span class="pln"> second</span><span class="pun">)</span><span class="pln">
 end
 defp min</span><span class="pun">([</span><span class="pln">first</span><span class="pun">|[</span><span class="pln">second</span><span class="pun">|</span><span class="pln">tail</span><span class="pun">]])</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
   min</span><span class="pun">([</span><span class="pln">smaller</span><span class="pun">(</span><span class="pln">first</span><span class="pun">,</span><span class="pln"> second</span><span class="pun">)|</span><span class="pln">tail</span><span class="pun">])</span><span class="pln">
 end
 defp smaller</span><span class="pun">(</span><span class="pln">e1</span><span class="pun">,</span><span class="pln"> e2</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> e1 </span><span class="pun">&lt;=</span><span class="pln"> e2 </span><span class="kwd">do</span><span class="pln">
     e1
   </span><span class="kwd">else</span><span class="pln">
     e2
   end
 end
end
</span><span class="typ">Selection</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">([</span><span class="lit">100</span><span class="pun">,</span><span class="lit">4</span><span class="pun">,</span><span class="lit">10</span><span class="pun">,</span><span class="lit">6</span><span class="pun">,</span><span class="lit">9</span><span class="pun">,</span><span class="lit">3</span><span class="pun">])</span><span class="pln">
</span><span class="pun">|&gt;</span><span class="pln"> IO</span><span class="pun">.</span><span class="pln">inspect</span></pre>

<p>
	ترجمة -بتصرّف- للفصول من 28 إلى 38 من الكتاب <a href="https://goalkicker.com/AlgorithmsBook/" rel="external nofollow">Algorithms Notes for Professionals</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/advanced/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%86-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1410/" rel="">أمثلة عن أنواع الخوارزميات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%A3%D8%B4%D8%AC%D8%A7%D8%B1-r1373/" rel="">خوارزميات تحليل المسارات في الأشجار</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-%D8%AF%D9%8A%D9%83%D8%B3%D8%AA%D8%B1%D8%A7-dijkstra%E2%80%99s-algorithm-r1336/" rel="">خوارزمية ديكسترا Dijkstra’s Algorithm</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D9%87%D8%A9-greedy-algorithms-r1366/" rel="">الخوارزميات الشرهة Greedy Algorithms</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1413</guid><pubDate>Fri, 17 Dec 2021 16:00:00 +0000</pubDate></item><item><title>&#x623;&#x645;&#x62B;&#x644;&#x629; &#x639;&#x646; &#x623;&#x646;&#x648;&#x627;&#x639; &#x627;&#x644;&#x62E;&#x648;&#x627;&#x631;&#x632;&#x645;&#x64A;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/advanced/%D8%A3%D9%85%D8%AB%D9%84%D8%A9-%D8%B9%D9%86-%D8%A3%D9%86%D9%88%D8%A7%D8%B9-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1410/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_12/61caed8bd1e9c_-01.jpg.67913e452bc428b841b566304e1e620d.jpg" /></p>
<p>
	نستعرض في هذه المقالة أمثلةً على مجموعة من <a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA/" rel="">الخوارزميات</a>، مثل خوارزمية الأعداد الكاتالانية وخوارزمية بريزنهام لرسم المستقيمات، وخوارزميات إدارة ذاكرة التخزين المؤقت، إضافة إلى بعض الخوارزميات متعددة الخيوط.
</p>

<h2>
	خوارزمية رسم المستقيمات
</h2>

<p>
	تُرسم المستقيمات على شاشة الحاسوب بِمدِّ نقاط متتابعة ومتقاربة على طول المسار الذي يمرّ منه المستقيم بين النقطتين اللتين تحدّدان طرفي المستقيم، وسنستعرض في هذه الفقرة إحدى أفضل الخوارزميات التي يستخدمها المبرمجون لحساب إحداثيات هذه النقاط وهي <a href="https://ar.wikipedia.org/wiki/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9_%D8%A8%D8%B1%D9%8A%D8%B2%D9%86%D9%87%D8%A7%D9%85_%D9%84%D8%B1%D8%B3%D9%85_%D9%85%D8%B3%D8%AA%D9%82%D9%8A%D9%85" rel="external nofollow">خوارزمية بريزنهام لرسم المستقيمات</a>، التي هي عبارة عن خوارزمية لرسم الخطوط بفعالية ودقّة، طورها جاك إيلتون بريزنهام Jack E. Bresenham، وهي دقيقة وسريعة لأنها تتم بإجراء عمليات على الأعداد الصحيحة فقطـ، وهي تسع أيضًا رسم الدوائر والمنحنيات الأخرى.
</p>

<p>
	وفي خوارزمية بريزنهام، لنقل أنّ <a href="https://ar.wikipedia.org/wiki/%D9%85%D9%8A%D9%84_%D8%A7%D9%84%D9%85%D8%B3%D8%AA%D9%82%D9%8A%D9%85" rel="external nofollow">ميل المستقيم</a> الذي نريد رسمه هو m.
</p>

<ul>
	<li>
		إن كان ‎‎|m|&lt;1:
	</li>
	<li>
		إما تُزاد قيمة الإحداثية x.
	</li>
	<li>
		أو تُزاد قيمتا الإحداثيتان x و y معًا باستخدام معامل قرار decision parameter خاصّ.
	</li>
	<li>
		إن كان ‎‎|m|&lt;1‎‎:
	</li>
	<li>
		إما أن تُزاد قيمة y.
	</li>
	<li>
		أو تُزاد قيمتا x و y معا باستخدام معامل قرار خاصّ.
	</li>
</ul>

<p>
	والآن، نستعرض خطوات الخوارزمية اعتمادًا على ميل المستقيم المراد رسمه.
</p>

<h3>
	الحالة الأولى: ‎‎| m | &lt;1
</h3>

<ol>
	<li>
		أدخِل طرفي المستقيم (x1، y1) و (x2، y2).
	</li>
	<li>
		ارسم النقطة الأولى (x1، y1).
	</li>
	<li>
		احسب القيمتين:
		<ul style="margin-right: 40px;">
			<li>
				Delx = | x2 ‎–‎ x1 | ‎‎.
			</li>
			<li>
				Dely = | y2 –‎ y1 | ‎‎.
			</li>
		</ul>
	</li>
	<li>
		احسب معامل القرار الأولي عبر الصيغة التالية:
		<ul style="margin-right: 40px;">
			<li>
				P = 2 * dely –‎ delx
			</li>
		</ul>
	</li>
	<li>
		لكل I من 0 إلى delx:
	</li>
</ol>

<ul style="margin-right: 40px;">
	<li>
		إذا كان p &lt;0، فسيكون:
		<ul>
			<li>
				X1 = x1 + 1.
			</li>
			<li>
				ارسم (x1، y1).
			</li>
			<li>
				P = p + 2dely.
			</li>
		</ul>
	</li>
	<li>
		وإلا:
		<ul>
			<li>
				X1 = x1 + 1.
			</li>
			<li>
				Y1 = y1 + 1.
			</li>
			<li>
				ارسم (x1، y1).
			</li>
			<li>
				P = p + 2dely –‎ 2 * delx.
			</li>
		</ul>
	</li>
	<li>
		نهاية عبارة إن.
	</li>
	<li>
		نهاية عبارة لكل.
	</li>
	<li>
		النهاية.
	</li>
</ul>

<p>
	فيما يلي شيفرة الخوارزمية، وهي برنامج مكتوب بلغة C لتطبيق خوارزمية بريزنهام في حالة ‎‎| m | &lt;1:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3577_7" style=""><span class="pun">#</span><span class="pln">include</span><span class="pun">&lt;</span><span class="pln">stdio</span><span class="pun">.</span><span class="pln">h</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">#</span><span class="pln">include</span><span class="pun">&lt;</span><span class="pln">conio</span><span class="pun">.</span><span class="pln">h</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">#</span><span class="pln">include</span><span class="pun">&lt;</span><span class="pln">graphics</span><span class="pun">.</span><span class="pln">h</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">#</span><span class="pln">include</span><span class="pun">&lt;</span><span class="pln">math</span><span class="pun">.</span><span class="pln">h</span><span class="pun">&gt;</span><span class="pln">
</span><span class="kwd">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">   
    </span><span class="kwd">int</span><span class="pln"> gdriver</span><span class="pun">=</span><span class="pln">DETECT</span><span class="pun">,</span><span class="pln">gmode</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">int</span><span class="pln"> x1</span><span class="pun">,</span><span class="pln">y1</span><span class="pun">,</span><span class="pln">x2</span><span class="pun">,</span><span class="pln">y2</span><span class="pun">,</span><span class="pln">delx</span><span class="pun">,</span><span class="pln">dely</span><span class="pun">,</span><span class="pln">p</span><span class="pun">,</span><span class="pln">i</span><span class="pun">;</span><span class="pln">
    initgraph</span><span class="pun">(&amp;</span><span class="pln">gdriver</span><span class="pun">,&amp;</span><span class="pln">gmode</span><span class="pun">,</span><span class="str">"c:\\TC\\BGI"</span><span class="pun">);</span><span class="pln">
    printf</span><span class="pun">(</span><span class="str">"Enter the intial points: "</span><span class="pun">);</span><span class="pln">
    scanf</span><span class="pun">(</span><span class="str">"%d"</span><span class="pun">,&amp;</span><span class="pln">x1</span><span class="pun">);</span><span class="pln">
    scanf</span><span class="pun">(</span><span class="str">"%d"</span><span class="pun">,&amp;</span><span class="pln">y1</span><span class="pun">);</span><span class="pln">
    printf</span><span class="pun">(</span><span class="str">"Enter the end points: "</span><span class="pun">);</span><span class="pln">
    scanf</span><span class="pun">(</span><span class="str">"%d"</span><span class="pun">,&amp;</span><span class="pln">x2</span><span class="pun">);</span><span class="pln">
    scanf</span><span class="pun">(</span><span class="str">"%d"</span><span class="pun">,&amp;</span><span class="pln">y2</span><span class="pun">);</span><span class="pln">
    putpixel</span><span class="pun">(</span><span class="pln">x1</span><span class="pun">,</span><span class="pln">y1</span><span class="pun">,</span><span class="pln">RED</span><span class="pun">);</span><span class="pln">
    delx</span><span class="pun">=</span><span class="pln">fabs</span><span class="pun">(</span><span class="pln">x2</span><span class="pun">-</span><span class="pln">x1</span><span class="pun">);</span><span class="pln">
    dely</span><span class="pun">=</span><span class="pln">fabs</span><span class="pun">(</span><span class="pln">y2</span><span class="pun">-</span><span class="pln">y1</span><span class="pun">);</span><span class="pln">
    p</span><span class="pun">=(</span><span class="lit">2</span><span class="pun">*</span><span class="pln">dely</span><span class="pun">)-</span><span class="pln">delx</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;</span><span class="pln">delx</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">
        </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">p</span><span class="pun">&lt;</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">{</span><span class="pln">
            x1</span><span class="pun">=</span><span class="pln">x1</span><span class="pun">+</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
            putpixel</span><span class="pun">(</span><span class="pln">x1</span><span class="pun">,</span><span class="pln">y1</span><span class="pun">,</span><span class="pln">RED</span><span class="pun">);</span><span class="pln">
            p</span><span class="pun">=</span><span class="pln">p</span><span class="pun">+(</span><span class="lit">2</span><span class="pun">*</span><span class="pln">dely</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">else</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
            x1</span><span class="pun">=</span><span class="pln">x1</span><span class="pun">+</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
            y1</span><span class="pun">=</span><span class="pln">y1</span><span class="pun">+</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
            putpixel</span><span class="pun">(</span><span class="pln">x1</span><span class="pun">,</span><span class="pln">y1</span><span class="pun">,</span><span class="pln">RED</span><span class="pun">);</span><span class="pln">
            p</span><span class="pun">=</span><span class="pln">p</span><span class="pun">+(</span><span class="lit">2</span><span class="pun">*</span><span class="pln">dely</span><span class="pun">)-(</span><span class="lit">2</span><span class="pun">*</span><span class="pln">delx</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    getch</span><span class="pun">();</span><span class="pln">
    closegraph</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3>
	الحالة الثانية: ‎‎| m | &gt; 1:
</h3>

<ol>
	<li>
		أدخل طرفي المستقيم (x1، y1) و (x2، y2).
	</li>
	<li>
		ارسم النقطة الأولى (x1، y1).
	</li>
	<li>
		احسب القيمتين:
		<ul style="margin-right: 40px;">
			<li>
				Delx = | x2 –‎ x1 | ‎‎.
			</li>
			<li>
				Dely = | y2 ‎–‎ y1 | ‎‎.
			</li>
		</ul>
	</li>
	<li>
		احسب معامل القرار الأول عبر الصيغة التالية:
		<ul style="margin-right: 40px;">
			<li>
				P = 2 * dely –‎ delx.
			</li>
		</ul>
	</li>
	<li>
		لكل I من 0 إلى delx:
	</li>
</ol>

<ul style="margin-right: 40px;">
	<li>
		إذا كان p &lt;0 فسيكون:
		<ul>
			<li>
				Y1 = y1 + 1.
			</li>
			<li>
				ارسم (x1، y1).
			</li>
			<li>
				P = p + delx.
			</li>
		</ul>
	</li>
	<li>
		وإلا:
		<ul>
			<li>
				X1 = x1 + 1.
			</li>
			<li>
				Y1 = y1 + 1.
			</li>
			<li>
				ارسم (x1، y1)
			</li>
			<li>
				P = p + 2delx –‎ 2 * dely.
			</li>
		</ul>
	</li>
	<li>
		نهاية عبارة إن.
	</li>
	<li>
		نهاية عبارة لكل.
	</li>
	<li>
		النهاية.
	</li>
</ul>

<p>
	انظر إلى الشيفرة أدناه، وهي برنامج مكتوب بلغة C لتطبيق خوارزمية بريزنهام في حالة ‎‎| m | &gt; 1:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3577_11" style=""><span class="com">#include</span><span class="str">&lt;stdio.h&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="str">&lt;conio.h&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="str">&lt;graphics.h&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="str">&lt;math.h&gt;</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln">
    </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> gdriver</span><span class="pun">=</span><span class="pln">DETECT</span><span class="pun">,</span><span class="pln">gmode</span><span class="pun">;</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> x1</span><span class="pun">,</span><span class="pln">y1</span><span class="pun">,</span><span class="pln">x2</span><span class="pun">,</span><span class="pln">y2</span><span class="pun">,</span><span class="pln">delx</span><span class="pun">,</span><span class="pln">dely</span><span class="pun">,</span><span class="pln">p</span><span class="pun">,</span><span class="pln">i</span><span class="pun">;</span><span class="pln">
    initgraph</span><span class="pun">(&amp;</span><span class="pln">gdriver</span><span class="pun">,&amp;</span><span class="pln">gmode</span><span class="pun">,</span><span class="str">"c:\\TC\\BGI"</span><span class="pun">);</span><span class="pln">
    printf</span><span class="pun">(</span><span class="str">"Enter the intial points: "</span><span class="pun">);</span><span class="pln">
    scanf</span><span class="pun">(</span><span class="str">"%d"</span><span class="pun">,&amp;</span><span class="pln">x1</span><span class="pun">);</span><span class="pln">
    scanf</span><span class="pun">(</span><span class="str">"%d"</span><span class="pun">,&amp;</span><span class="pln">y1</span><span class="pun">);</span><span class="pln">
    printf</span><span class="pun">(</span><span class="str">"Enter the end points: "</span><span class="pun">);</span><span class="pln">
    scanf</span><span class="pun">(</span><span class="str">"%d"</span><span class="pun">,&amp;</span><span class="pln">x2</span><span class="pun">);</span><span class="pln">
    scanf</span><span class="pun">(</span><span class="str">"%d"</span><span class="pun">,&amp;</span><span class="pln">y2</span><span class="pun">);</span><span class="pln">
    putpixel</span><span class="pun">(</span><span class="pln">x1</span><span class="pun">,</span><span class="pln">y1</span><span class="pun">,</span><span class="pln">RED</span><span class="pun">);</span><span class="pln">
    delx</span><span class="pun">=</span><span class="pln">fabs</span><span class="pun">(</span><span class="pln">x2</span><span class="pun">-</span><span class="pln">x1</span><span class="pun">);</span><span class="pln">
    dely</span><span class="pun">=</span><span class="pln">fabs</span><span class="pun">(</span><span class="pln">y2</span><span class="pun">-</span><span class="pln">y1</span><span class="pun">);</span><span class="pln">
    p</span><span class="pun">=(</span><span class="lit">2</span><span class="pun">*</span><span class="pln">delx</span><span class="pun">)-</span><span class="pln">dely</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;</span><span class="pln">delx</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">
        </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">p</span><span class="pun">&lt;</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
            y1</span><span class="pun">=</span><span class="pln">y1</span><span class="pun">+</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
            putpixel</span><span class="pun">(</span><span class="pln">x1</span><span class="pun">,</span><span class="pln">y1</span><span class="pun">,</span><span class="pln">RED</span><span class="pun">);</span><span class="pln">
            p</span><span class="pun">=</span><span class="pln">p</span><span class="pun">+(</span><span class="lit">2</span><span class="pun">*</span><span class="pln">delx</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">else</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
        x1</span><span class="pun">=</span><span class="pln">x1</span><span class="pun">+</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
        y1</span><span class="pun">=</span><span class="pln">y1</span><span class="pun">+</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
        putpixel</span><span class="pun">(</span><span class="pln">x1</span><span class="pun">,</span><span class="pln">y1</span><span class="pun">,</span><span class="pln">RED</span><span class="pun">);</span><span class="pln">
        p</span><span class="pun">=</span><span class="pln">p</span><span class="pun">+(</span><span class="lit">2</span><span class="pun">*</span><span class="pln">delx</span><span class="pun">)-(</span><span class="lit">2</span><span class="pun">*</span><span class="pln">dely</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    getch</span><span class="pun">();</span><span class="pln">
    closegraph</span><span class="pun">();</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	خوارزمية الأعداد الكاتالانية
</h2>

<p>
	<a href="https://wiki.hsoub.com/Algorithms/Catalan_numbers" rel="external">خوارزمية الأعداد الكاتالانية</a> Catalan Number Algorithm هي إحدى خوارزميات <a href="https://academy.hsoub.com/programming/advanced/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AF%D9%8A%D9%86%D8%A7%D9%85%D9%8A%D9%83%D9%8A%D8%A9-r1365/" rel="">البرمجة الديناميكية</a>، وتشكل الأعداد الكاتلانية في الرياضيات التوافقية combinatorial mathematics سلسلةً من الأعداد الطبيعية التي تظهر في العديد من المسائل العددية المختلفة، وخاصةً المقادير التي تُعرّف بطريقة تكرارية، كما تظهر في مشاكل عدّ الأشجار. ويمكن استخدام خوارزمية الأعداد الكاتالانية لحساب مقادير مثل:
</p>

<ul>
	<li>
		عدد الطرق التي يمكن تكديس القطع النقدية بها في صف سفلي يتكون من n قطعة نقدية متتالية في المستوى، بحيث لا يُسمح بوضع أي قطعة نقدية على جانبي القطع النقدية السفلية، كما يجب أن تكون كل قطعة نقدية فوق قطعنين نقديتين أُخريين، الجواب هو العدد الكتالاني رقم n.
	</li>
	<li>
		عدد التعابير التي تحتوي على n زوج من الأقواس الهلالية، والتي تطابق بعضها البعض تطابقًا صحيحًا هو العدد الكتالاني رقم n.
	</li>
	<li>
		عدد الطرق الممكنة لقطع مضلّع محدّب ذو n+2 وجهًا‏ n+2-sided convex polygon في مستوى ما إلى مثلثات عبر ربط الحروف ذات الخطوط المستقيمة غير المتقاطعة هو العدد الكاتالاني رقم n.
	</li>
</ul>

<p>
	يُحصَل على العدد الكاتالاني رقم n مباشرةً عبر المعادلة التالية التي تستخدم <a href="https://ar.wikipedia.org/wiki/%D9%85%D8%B9%D8%A7%D9%85%D9%84_%D8%AB%D9%86%D8%A7%D8%A6%D9%8A" rel="external nofollow">المعاملات الثنائية</a>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="87291" href="https://academy.hsoub.com/uploads/monthly_2021_12/UP8N4.png.a673ae397904128ea0e797b8e5c26c41.png" rel=""><img alt="UP8N4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="87291" data-unique="ampwzb22x" src="https://academy.hsoub.com/uploads/monthly_2021_12/UP8N4.png.a673ae397904128ea0e797b8e5c26c41.png"></a>
</p>

<p>
	إليك مثال على عدد كاتالاني:
</p>

<ul>
	<li>
		n = 4
	</li>
</ul>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="87292" href="https://academy.hsoub.com/uploads/monthly_2021_12/VBGLB.png.ef0b44d191c6d6efa723af86f119a61d.png" rel=""><img alt="VBGLB.png" class="ipsImage ipsImage_thumbnailed" data-fileid="87292" data-unique="yqr6xkise" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_12/VBGLB.png.ef0b44d191c6d6efa723af86f119a61d.png"></a>
</p>

<ul>
	<li>
		المساحة الإضافية = <code>‎O(n)‎</code>.
	</li>
	<li>
		تعقيد الوقت = <code>‎O(n^2)‎</code>.
	</li>
</ul>

<h2>
	الخوارزميات متعددة الخيوط Multithreaded Algorithms
</h2>

<p>
	سنستعرض في هذه الفقرة أمثلة على بعض الخوارزميات متعددة الخيوط.
</p>

<p>
	مثال عن ضرب المصفوفة المربعة Square matrix multiplication:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3577_17" style=""><span class="pln">multiply</span><span class="pun">-</span><span class="pln">square</span><span class="pun">-</span><span class="pln">matrix</span><span class="pun">-</span><span class="pln">parallel</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln"> B</span><span class="pun">)</span><span class="pln">
    n </span><span class="pun">=</span><span class="pln"> A</span><span class="pun">.</span><span class="pln">lines 
    C </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Matrix</span><span class="pun">(</span><span class="pln">n</span><span class="pun">,</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span><span class="com">//n*n إنشاء مصفوفة من الحجم</span><span class="pln">
    parallel </span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to n
        parallel </span><span class="kwd">for</span><span class="pln"> j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to n
            C</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
            pour k </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to n
                C</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> C</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> A</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">k</span><span class="pun">]*</span><span class="pln">B</span><span class="pun">[</span><span class="pln">k</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln">
 </span><span class="kwd">return</span><span class="pln"> C</span></pre>

<p>
	مثال عن خوارزمية ضرب مصفوفة ومتجه متعددة الخيوط:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3577_19" style=""><span class="pln">matrix</span><span class="pun">-</span><span class="typ">vector</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln">x</span><span class="pun">)</span><span class="pln">
    n </span><span class="pun">=</span><span class="pln"> A</span><span class="pun">.</span><span class="pln">lines
    y </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Vector</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span><span class="com">//create a new vector of length n</span><span class="pln">
    parallel </span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to n
        y</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
    parallel </span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to n
 </span><span class="kwd">for</span><span class="pln"> j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to n
            y</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> y</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> A</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]*</span><span class="pln">x</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln">
 </span><span class="kwd">return</span><span class="pln"> y</span></pre>

<h3>
	خوارزمية دمج وترتيب متعددة الخيوط
</h3>

<p>
	لتكن A وB مصفوفتان، وليكن p و r فهرسان للمصفوفة A، سنحاول ترتيب المصفوفة الجزئية A [p..r]‎‎. وسنملأ المصفوفة B عند ترتيب المصفوفة الجزئية.
</p>

<p>
	في الشيفرة التالية، ترتب الدالة <code>p-merge-sort (A، p، r، B، s)‎‎</code> عناصر A [p..r]‎‎ وتضعها في B [s..s + rp]‎‎.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3577_21" style=""><span class="pln">p</span><span class="pun">-</span><span class="pln">merge</span><span class="pun">-</span><span class="pln">sort</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln">p</span><span class="pun">,</span><span class="pln">r</span><span class="pun">,</span><span class="pln">B</span><span class="pun">,</span><span class="pln">s</span><span class="pun">)</span><span class="pln">
    n </span><span class="pun">=</span><span class="pln"> r</span><span class="pun">-</span><span class="pln">p</span><span class="pun">+</span><span class="lit">1</span><span class="pln">
 </span><span class="kwd">if</span><span class="pln"> n</span><span class="pun">==</span><span class="lit">1</span><span class="pln">
        B</span><span class="pun">[</span><span class="pln">s</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> A</span><span class="pun">[</span><span class="pln">p</span><span class="pun">]</span><span class="pln">
 </span><span class="kwd">else</span><span class="pln">
        T </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span><span class="com">//create a new array T of size n</span><span class="pln">
        q </span><span class="pun">=</span><span class="pln"> floor</span><span class="pun">((</span><span class="pln">p</span><span class="pun">+</span><span class="pln">r</span><span class="pun">)/</span><span class="lit">2</span><span class="pun">))</span><span class="pln">
        q_prime </span><span class="pun">=</span><span class="pln"> q</span><span class="pun">-</span><span class="pln">p</span><span class="pun">+</span><span class="lit">1</span><span class="pln">
        spawn p</span><span class="pun">-</span><span class="pln">merge</span><span class="pun">-</span><span class="pln">sort</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln">p</span><span class="pun">,</span><span class="pln">q</span><span class="pun">,</span><span class="pln">T</span><span class="pun">,</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
        p</span><span class="pun">-</span><span class="pln">merge</span><span class="pun">-</span><span class="pln">sort</span><span class="pun">(</span><span class="pln">A</span><span class="pun">,</span><span class="pln">q</span><span class="pun">+</span><span class="lit">1</span><span class="pun">,</span><span class="pln">r</span><span class="pun">,</span><span class="pln">T</span><span class="pun">,</span><span class="pln">q_prime</span><span class="pun">+</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
        sync
        p</span><span class="pun">-</span><span class="pln">merge</span><span class="pun">(</span><span class="pln">T</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="pln">q_prime</span><span class="pun">,</span><span class="pln">q_prime</span><span class="pun">+</span><span class="lit">1</span><span class="pun">,</span><span class="pln">n</span><span class="pun">,</span><span class="pln">B</span><span class="pun">,</span><span class="pln">s</span><span class="pun">)</span></pre>

<p>
	في الشيفرة أدناه، تجري الدالة المساعدة <code>p-merge</code> عملية الدمج بالتوازي، وتفترض هذه الدالة أنّ المصفوفتين الجزئيتين المراد دمجهما موجودتان في المصفوفة نفسها، ولكنّها لا تفترض أنهما متجاورتان في المصفوفة، لذا علينا تزويدها بالفهارس p1 وr1 p2 وr2.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3577_23" style=""><span class="pln">p</span><span class="pun">-</span><span class="pln">merge</span><span class="pun">(</span><span class="pln">T</span><span class="pun">,</span><span class="pln">p1</span><span class="pun">,</span><span class="pln">r1</span><span class="pun">,</span><span class="pln">p2</span><span class="pun">,</span><span class="pln">r2</span><span class="pun">,</span><span class="pln">A</span><span class="pun">,</span><span class="pln">p3</span><span class="pun">)</span><span class="pln">
    n1 </span><span class="pun">=</span><span class="pln"> r1</span><span class="pun">-</span><span class="pln">p1</span><span class="pun">+</span><span class="lit">1</span><span class="pln">
    n2 </span><span class="pun">=</span><span class="pln"> r2</span><span class="pun">-</span><span class="pln">p2</span><span class="pun">+</span><span class="lit">1</span><span class="pln">
 </span><span class="kwd">if</span><span class="pln"> n1</span><span class="pun">&lt;</span><span class="pln">n2     </span><span class="com">// n1&gt;=n2 التحقق من أنّ</span><span class="pln">
        permute p1 and p2
        permute r1 and r2
        permute n1 and n2
 </span><span class="kwd">if</span><span class="pln"> n1</span><span class="pun">==</span><span class="lit">0</span><span class="pln"> </span><span class="com">// كلاهما فارغ؟</span><span class="pln">
 </span><span class="kwd">return</span><span class="pln">
 </span><span class="kwd">else</span><span class="pln">
        q1 </span><span class="pun">=</span><span class="pln"> floor</span><span class="pun">((</span><span class="pln">p1</span><span class="pun">+</span><span class="pln">r1</span><span class="pun">)/</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
        q2 </span><span class="pun">=</span><span class="pln"> dichotomic</span><span class="pun">-</span><span class="pln">search</span><span class="pun">(</span><span class="pln">T</span><span class="pun">[</span><span class="pln">q1</span><span class="pun">],</span><span class="pln">T</span><span class="pun">,</span><span class="pln">p2</span><span class="pun">,</span><span class="pln">r2</span><span class="pun">)</span><span class="pln">
        q3 </span><span class="pun">=</span><span class="pln"> p3 </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="pln">q1</span><span class="pun">-</span><span class="pln">p1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="pln">q2</span><span class="pun">-</span><span class="pln">p2</span><span class="pun">)</span><span class="pln">
        A</span><span class="pun">[</span><span class="pln">q3</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> T</span><span class="pun">[</span><span class="pln">q1</span><span class="pun">]</span><span class="pln">
        spawn p</span><span class="pun">-</span><span class="pln">merge</span><span class="pun">(</span><span class="pln">T</span><span class="pun">,</span><span class="pln">p1</span><span class="pun">,</span><span class="pln">q1</span><span class="pun">-</span><span class="lit">1</span><span class="pun">,</span><span class="pln">p2</span><span class="pun">,</span><span class="pln">q2</span><span class="pun">-</span><span class="lit">1</span><span class="pun">,</span><span class="pln">A</span><span class="pun">,</span><span class="pln">p3</span><span class="pun">)</span><span class="pln">
        p</span><span class="pun">-</span><span class="pln">merge</span><span class="pun">(</span><span class="pln">T</span><span class="pun">,</span><span class="pln">q1</span><span class="pun">+</span><span class="lit">1</span><span class="pun">,</span><span class="pln">r1</span><span class="pun">,</span><span class="pln">q2</span><span class="pun">,</span><span class="pln">r2</span><span class="pun">,</span><span class="pln">A</span><span class="pun">,</span><span class="pln">q3</span><span class="pun">+</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
        sync</span></pre>

<p>
	الشيفرة أدناه تمثل دالة البحث الانقسامي المساعِدة auxillary function dichotomic-search، ويكون <code>x</code> فيها هو المفتاح المراد البحث عنه في المصفوفة الفرعية T [p..r]‎‎.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3577_25" style=""><span class="pln">dichotomic</span><span class="pun">-</span><span class="pln">search</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln">T</span><span class="pun">,</span><span class="pln">p</span><span class="pun">,</span><span class="pln">r</span><span class="pun">)</span><span class="pln"> 
    inf </span><span class="pun">=</span><span class="pln"> p
    sup </span><span class="pun">=</span><span class="pln"> max</span><span class="pun">(</span><span class="pln">p</span><span class="pun">,</span><span class="pln">r</span><span class="pun">+</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
 </span><span class="kwd">while</span><span class="pln"> inf</span><span class="pun">&lt;</span><span class="pln">sup
        half </span><span class="pun">=</span><span class="pln"> floor</span><span class="pun">((</span><span class="pln">inf</span><span class="pun">+</span><span class="pln">sup</span><span class="pun">)/</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
 </span><span class="kwd">if</span><span class="pln"> x</span><span class="pun">&lt;=</span><span class="pln">T</span><span class="pun">[</span><span class="pln">half</span><span class="pun">]</span><span class="pln">
            sup </span><span class="pun">=</span><span class="pln"> half
 </span><span class="kwd">else</span><span class="pln">
            inf </span><span class="pun">=</span><span class="pln"> half</span><span class="pun">+</span><span class="lit">1</span><span class="pln">
 </span><span class="kwd">return</span><span class="pln"> sup</span></pre>

<h2>
	خوارزمية KMP
</h2>

<p>
	<a href="https://wiki.hsoub.com/Algorithms/KMP" rel="external">خوارزمية KMP</a> هي خوارزمية لمطابقة الأنماط، إذ تبحث عن مواضع ظهور كلمةٍ ما W في سلسلة نصية S.
</p>

<p>
	ومبدأ هذه <a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D9%81%D9%8A-%D8%A7%D9%84%D9%86%D8%B5%D9%88%D8%B5-r1415/" rel="">الخوارزمية</a> أنّه في كلّ مرة نرصد فيها عدم تطابق، فإنّنا سنكون على علم ببعض الحروف الموجودة في النص والتي ستكون مطابقة في الخطوة القادمة. سنستغل هذه المعلومة لتجنب مطابَقة الحروف التي نعلم بأنّها ستكون متطابقة بأي حال. ولا يتجاوز تعقيد هذه الخوارزمية O (n)‎‎ في أسوأ الحالات.
</p>

<p>
	سنأخذ مثالًا على هذا النوع من الخوارزميات؛ تتألف هذه الخوارزمية من خطوتين:
</p>

<ol>
	<li>
		الخطوة الأولى: التجهيز
		<ul style="margin-right: 40px;">
			<li>
				نعالج النمط معالجةً مسبقة، وننشئ مصفوفة مساعدة <code>lps []‎‎</code> تُستخدم لتخطي المحارف أثناء المطابقة.
			</li>
			<li>
				تشير <code>lps[]‎‎</code> هنا إلى أطول سابقة ملائمة proper preﬁx تكون لاحقة suﬃx أيضًا. نقصد بالسابقة المناسبة أيّ سابقة تبدأ بها السلسلة النصية المبحوث عنها، شرط ألا تحتوي كامل السلسلة النصية. مثلاً، سوابق "ABC" الملائمة هي "" و "A" و "AB"، أما اللواحق الخاصة بهذه السلسلة النصية فهي: "" و "C" و "BC" و "ABC".
			</li>
		</ul>
	</li>
	<li>
		الخطوة الثانية: البحث
	</li>
</ol>

<ul style="margin-right: 40px;">
	<li>
		نستمر في مطابقة المحارف txt ‎‎ و ‎pat [j]‎، ونستمر في زيادة <code>i</code> و <code>j</code> طالما تطابق <code>pat [j]‎‎</code> و <code>txt‎‎</code>.
	</li>
	<li>
		عندما نرصد عدم تطابق فإننا نعلم أنّ الأحرف <code>pat[0..j-1]</code>  تتطابق مع <code>txt [i-j +1… i-1]‎‎</code>. ونعلم أيضًا أنّ <code>lps[j-1]‎‎</code> يساوي تعداد محارف <code>pat[0 … j-1]‎‎</code> التي هي سوابق ملائمة ولواحق على حدّ سواء، لهذا لا نحتاج إلى مطابقة أحرف<code>lps [j-1]‎‎</code> مع <code>txt [ij… i-1]‎‎</code>، لأنّنا نعلم سلفًا أنّها مُتطابقة.
	</li>
</ul>

<p>
	فيما يلي تطبيق على ذلك بلغة جافا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3577_27" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> KMP </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="com">// TODO Auto-generated method stub</span><span class="pln">
       </span><span class="typ">String</span><span class="pln"> str </span><span class="pun">=</span><span class="pln"> </span><span class="str">"abcabdabc"</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">String</span><span class="pln"> pattern </span><span class="pun">=</span><span class="pln"> </span><span class="str">"abc"</span><span class="pun">;</span><span class="pln">
       KMP obj </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> KMP</span><span class="pun">();</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">patternExistKMP</span><span class="pun">(</span><span class="pln">str</span><span class="pun">.</span><span class="pln">toCharArray</span><span class="pun">(),</span><span class="pln"> pattern</span><span class="pun">.</span><span class="pln">toCharArray</span><span class="pun">()));</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">

   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">[]</span><span class="pln"> computeLPS</span><span class="pun">(</span><span class="kwd">char</span><span class="pun">[]</span><span class="pln"> str</span><span class="pun">){</span><span class="pln">
       </span><span class="kwd">int</span><span class="pln"> lps</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">[</span><span class="pln">str</span><span class="pun">.</span><span class="pln">length</span><span class="pun">];</span><span class="pln">

       lps</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">int</span><span class="pln"> j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> i </span><span class="pun">=</span><span class="lit">1</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;</span><span class="pln">str</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">str</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> str</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]){</span><span class="pln">
               lps</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> j</span><span class="pun">+</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
               j</span><span class="pun">++;</span><span class="pln">

               i</span><span class="pun">++;</span><span class="pln">
           </span><span class="pun">}</span><span class="kwd">else</span><span class="pun">{</span><span class="pln">
               </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">j</span><span class="pun">!=</span><span class="lit">0</span><span class="pun">){</span><span class="pln">
                   j </span><span class="pun">=</span><span class="pln"> lps</span><span class="pun">[</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
               </span><span class="pun">}</span><span class="kwd">else</span><span class="pun">{</span><span class="pln">
                   lps</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> j</span><span class="pun">+</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
                   i</span><span class="pun">++;</span><span class="pln">
               </span><span class="pun">}</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">

       </span><span class="pun">}</span><span class="pln">

       </span><span class="kwd">return</span><span class="pln"> lps</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">

   </span><span class="kwd">public</span><span class="pln"> boolean patternExistKMP</span><span class="pun">(</span><span class="kwd">char</span><span class="pun">[]</span><span class="pln"> text</span><span class="pun">,</span><span class="kwd">char</span><span class="pun">[]</span><span class="pln"> pat</span><span class="pun">){</span><span class="pln">
       </span><span class="kwd">int</span><span class="pun">[]</span><span class="pln"> lps </span><span class="pun">=</span><span class="pln"> computeLPS</span><span class="pun">(</span><span class="pln">pat</span><span class="pun">);</span><span class="pln">
       </span><span class="kwd">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">,</span><span class="pln">j</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">while</span><span class="pun">(</span><span class="pln">i</span><span class="pun">&lt;</span><span class="pln">text</span><span class="pun">.</span><span class="pln">length </span><span class="pun">&amp;&amp;</span><span class="pln"> j</span><span class="pun">&lt;</span><span class="pln">pat</span><span class="pun">.</span><span class="pln">length</span><span class="pun">){</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">text</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> pat</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]){</span><span class="pln">
               i</span><span class="pun">++;</span><span class="pln">
               j</span><span class="pun">++;</span><span class="pln">
           </span><span class="pun">}</span><span class="kwd">else</span><span class="pun">{</span><span class="pln">
               </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">j</span><span class="pun">!=</span><span class="lit">0</span><span class="pun">){</span><span class="pln">
                   j </span><span class="pun">=</span><span class="pln"> lps</span><span class="pun">[</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
               </span><span class="pun">}</span><span class="kwd">else</span><span class="pun">{</span><span class="pln">
                   i</span><span class="pun">++;</span><span class="pln">
               </span><span class="pun">}</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">

       </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">j</span><span class="pun">==</span><span class="pln">pat</span><span class="pun">.</span><span class="pln">length</span><span class="pun">)</span><span class="pln">
           </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<h2>
	خوارزمية مسافة التعديل الديناميكية Edit Distance Dynamic Algorithm
</h2>

<p>
	بيان المشكلة: إذا أُعطيت سلسلتين نصيتين str1 و str2، فما هو العدد الأدنى للعمليات التي يمكن إجراؤها على str1 لتحويلها إلى str2. علمًا بأنّ العمليات الممكنة هي:
</p>

<ol>
	<li>
		الإدراج Insert.
	</li>
	<li>
		الحذف Remove.
	</li>
	<li>
		الاستبدال Replace.
	</li>
</ol>

<p>
	إليك مثال:
</p>

<ul>
	<li>
		إن كانت str1 = "geek"‎‎ و str2 = "gesek"‎‎ فالجواب هو 1، لأنّنا نحتاج فقط إلى إدراج الحرف s في السلسلة النصية str1.
	</li>
	<li>
		إن كانت str1 = "march"‎‎ و str2 = "cart"‎‎ فالجواب هو 3، لأنّنا نحتاج إلى 3 عمليات هي وضع c مكان m، ثمّ حذف c، ثمّ وضع t مكان h.
	</li>
</ul>

<p>
	ولحل هذه المشكلة، سنستخدم المصفوفة dp[n+1] [m+1]‎‎ ثنائية الأبعاد، حيث يمثّل n طول السلسلة النصية الأولى، و m طول السلسلة النصية الثانية. على سبيل المثال، إذا كانت str1 تساوي "azcef" و str2 تساوي "abcdef"، فستكون المصفوفة من البعدين dp [6] [7]‎‎، وستُخزّن الإجابة النهائية في الموضع dp [5] [6]‎‎.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3577_29" style=""><span class="pln">            </span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">6</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">  
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">z</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln"> 
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">5</span><span class="pln">  </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">      </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span></pre>

<p>
	بالنسبة للفهرس dp [1] [1]‎‎، ليس علينا فعل شيء لتحويل a إلى a لأنّهما متساويان، لذا نضع 0 هناك.
</p>

<p>
	وبالنسبة للفهرس dp [1] [2]‎‎، ما الذي علينا أن نفعله لتحويل a إلى ab؟ سنحتاج إلى عملية واحدة، وهي إدراج الحرف b. ستبدو المصفوفة كما يلي بعد التكرار الأول:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3577_31" style=""><span class="pln">            </span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">z</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">   </span><span class="pun">|</span><span class="pln"> 
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">5</span><span class="pln">  </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span></pre>

<p>
	بالنسبة للفهرس dp [2] [1]‎‎، لأجل تحويل az إلى a، نحتاج إلى إزالة z، ومن ثم نضع 1 في dp [2] [1]‎‎. أما بالنسبة لـ dp [2] [2]‎‎، نحتاج إلى استبدال z بـ b، ومن ثم نضع 1 في dp [2] [2]‎‎.
</p>

<p>
	هكذا ستبدو المصفوفة الآن:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_3577_35" style=""><span class="pln">            </span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">z</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">   </span><span class="pun">|</span><span class="pln"> 
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">5</span><span class="pln">  </span><span class="pun">|</span><span class="pln">    </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span></pre>

<p>
	نستمر في إعادة العملية إلى أن نحوّل السلسلة النصية الأولى إلى الثانية ("azcef" ‏ ← "abcdef")، وستبدو المصفوفة النهائية هكذا:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_3577_37" style=""><span class="pln">            </span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">a</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">z</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln">   </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span><span class="pln">
</span><span class="pun">(</span><span class="pln">f</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">5</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---+---+---+---+---+---+---+</span></pre>

<p>
	هذه هي الصيغة العامة لتحديث المصفوفة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3577_39" style=""><span class="kwd">if</span><span class="pln"> characters are same
    dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">][</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">];</span><span class="pln">  </span><span class="com">// الحرفان متطابقان</span><span class="pln">
</span><span class="kwd">else</span><span class="pln">
    dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="typ">Min</span><span class="pun">(</span><span class="pln">dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">][</span><span class="pln">j</span><span class="pun">],</span><span class="pln"> dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">],</span><span class="pln"> dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">][</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">])</span></pre>

<p>
	هذا تطبيق مكتوب بلغة جافا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3577_41" style=""><span class="kwd">public</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> getMinConversions</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> str1</span><span class="pun">,</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> str2</span><span class="pun">){</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> dp</span><span class="pun">[][]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()+</span><span class="lit">1</span><span class="pun">][</span><span class="pln">str2</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()+</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
   </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;=</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">length</span><span class="pun">();</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> j</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">j</span><span class="pun">&lt;=</span><span class="pln">str2</span><span class="pun">.</span><span class="pln">length</span><span class="pun">();</span><span class="pln">j</span><span class="pun">++){</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">i</span><span class="pun">==</span><span class="lit">0</span><span class="pun">)</span><span class="pln">

               dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> j</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">j</span><span class="pun">==</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
               dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> str2</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">))</span><span class="pln">
               dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">][</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
           </span><span class="kwd">else</span><span class="pun">{</span><span class="pln">
               dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">][</span><span class="pln">j</span><span class="pun">],</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">],</span><span class="pln"> dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">][</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]));</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> dp</span><span class="pun">[</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()][</span><span class="pln">str2</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()];</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	التعقيد الزمني لهذه الخوارزمية هو O(n^2)‎‎.
</p>

<h2>
	الخوارزميات المتصلة Online algorithms
</h2>

<p>
	تنشأ مشكلة <a href="https://academy.hsoub.com/programming/general/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%AE%D8%B2%D9%8A%D9%86-%D8%A7%D9%84%D9%85%D8%A4%D9%82%D8%AA-%D9%84%D9%84%D9%88%D9%8A%D8%A8-web-caching-%D8%A7%D9%84%D9%85%D8%B5%D8%B7%D9%84%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A9-r204/" rel="">التخزين المؤقت caching</a> من محدودية مساحة التخزين، وسنفترض أنّ ذاكرة التخزين المؤقت <code>‎C‎</code> تحتوي على <code>‎k‎</code> صفحة، ونحن نريد معالجة سلسلة من طلبات الصفحات عددها <code>‎m‎</code> طلب، ويجب تخزينها في ذاكرة التخزين المؤقت قبل معالجتها.
</p>

<p>
	إذا كانت <code>‎m&lt;=k‎</code> فلن تكون هناك مشكلة إذ سنضع جميع العناصر في ذاكرة التخزين المؤقت، ولكن في العادة تكون <code>‎m&gt;&gt;k‎</code>.
</p>

<p>
	تكون طلبيّة ما مقبولة في ذاكرة التخزين المؤقت (نقول أنها cache hit) إذا كان العنصر موجودًا في ذاكرة التخزين المؤقت بالفعل، وإلا نقول أنّها مُفوَّتة من ذاكرة التخزين المؤقت cache miss، وفي مثل هذه الحالة سيكون علينا إحضار العنصر المطلوب إلى ذاكرة التخزين المؤقت وإخراج عنصر آخر وذلك على افتراض أنّ ذاكرة التخزين المؤقت ممتلئة. إن الهدف هنا هو تصميم جدول إخلاء eviction schedule يقلّل عدد عمليات الإخلاء الضرورية قدر الإمكان.
</p>

<p>
	هناك العديد من الاستراتيجيات الممكنة لحلّ هذه المشكلة، منها:
</p>

<ol>
	<li>
		من دخل أولًا، يخرج أولًا First in, ﬁrst out أو FIFO: تُخلى أقدم صفحة.
	</li>
	<li>
		من دخل آخرًا، يخرج أولًا Last in, ﬁrst out أو LIFO: تُخلى أحدث صفحة.
	</li>
	<li>
		الأقل استخدامًا مؤخرًا LRU: تخلى الصفحة التي كان آخر وصول لها هو الأبكر.
	</li>
	<li>
		الأقل طلبًا LFU: تخلى الصفحة التي طُلِبت أقل عدد من المرّات.
		<ul>
			<li>
				أطول مسافة أمامية LFD: تخلى الصفحة التي لن تُطلَب إلا بعد أطول مدة.
			</li>
		</ul>
	</li>
	<li>
		التفريغ عند الامتلاء FWF: مسح ذاكرة التخزين المؤقت كاملة بمجرد حدوث فوات في ذاكرة التخزين المؤقت.
	</li>
</ol>

<p>
	هناك طريقتان للتعامل مع هذه المشكلة:
</p>

<ol>
	<li>
		الطريقة غير المتصلة oﬄine: يكون فيها تسلسل الطلبات معروف منذ البدء.
	</li>
	<li>
		الطريقة المتصلة online: يكون تسلسل الطلبات غير معروف مسبقًا.
	</li>
</ol>

<p>
	وقبل أن نواصل، سنقدم بعض التعاريف الرياضية المساعدة.
</p>

<ul>
	<li>
		التعريف 1: نقول أنّ المشكلة <code>‎Π‎</code> هي مشكلة تحسين optimization problem إن كانت تتألف من مجموعة من الحالات <code>‎ΣΠ‎</code>، بحيث يكون لكل حالة <code>‎σ∈ΣΠ‎</code> مجموعة من الحلول ودالة تقييم<code>f σ: Ζσ → ℜ≥ 0</code> تعطي قيمة حقيقية موجبة لكلّ حل من تلك الحلول، ونرمز لقيمة الحل الأمثل (optimal solution) من بين كل حلول الحالة σ بالرمز OPT (σ‎)‎‎.
	</li>
</ul>

<p style="margin-right: 40px;">
	ولكل خوارزمية A، يشير الرمز A (σ‎)‎‎ إلى حل الخوارزمية A للمشكلة ‎Π‎ في الحالة σ، بينما يساوي التعبير <code>wA (‎σ‎) = fσ‎ (A (‎σ))‎‎</code> قيمة الخوارزمية.
</p>

<ul>
	<li>
		التعريف 2: نقول أنّ <a href="https://en.wikipedia.org/wiki/Online_algorithm" rel="external nofollow">خوارزمية متصلة</a> A لمشكلة تصغير <code>‎Π‎</code> ‏minimization problem لديها معدل تنافسي competetive ratio قيمته r ‎≥ 1 إذا كان هناك ثابت <code>‎τ∈ℜ‎</code> يحقّق:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3577_43" style=""><span class="pln">wA</span><span class="pun">(σ)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> f</span><span class="pun">σ(</span><span class="pln">A</span><span class="pun">(σ))</span><span class="pln"> </span><span class="pun">≤</span><span class="pln"> r </span><span class="pun">⋅</span><span class="pln"> OPT</span><span class="pun">(σ)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">τ</span></pre>

<p>
	لكل الحالات <code>‎σ∈ΣΠ‎</code>، نقول أنّ الخَوارزمية A خوارزمية متصلة ذات r تنافسية r-competitive online algorithm إن كان لدينا:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_3577_45" style=""><span class="pln">wA</span><span class="pun">(σ)</span><span class="pln"> </span><span class="pun">≤</span><span class="pln"> r </span><span class="pun">⋅</span><span class="pln"> OPT</span><span class="pun">(σ)</span></pre>

<p>
	لكل عنصر <code>‎σ∈ΣΠ‎</code>، نقول أنّ A خوارزمية متصلة ذات r تنافسية قطعًا strictly r-competitive online algorithm.
</p>

<ul>
	<li>
		تعريف 3: نقول أنّ خوارزمية A خوارزمية واسمة Marking Algorithm فقط إذا لم تكن تُخلي أيّ صفحة موسومة من ذاكرة التخزين المؤقت، مما يعني أنّ الصفحات التي تُستخدم أثناء أيّ مرحلة لن تُخلى.
	</li>
</ul>

<p>
	خاصية 1.3: الخوارِزميتان LRU -الأقل استخدامًا مؤخرًا Least recently used، أي إخلاء الصفحة التي لم يُدخل إليها منذ أطول مدة-، و FWF -التفريغ عند الملء Flush when full، وتعني مسح ذاكرة التخزين المؤقت بمجرد وقوع فوات في ذاكرة التخزين المؤقت cache miss- هما خوارِزميتان واسمَتان.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<strong>برهان</strong>: في بداية كل مرحلة (ما عدا المرحلة الأولى) يكون هناك فوات في خوارزمية FWF ، كما تُمسَح ذاكرة التخزين المؤقت. هذا يعني أنّه ستكون لدينا عدد k صفحة فارغة. وفي كل مرحلة، ستُطلب k صفحة مختلفة على الأكثر، لذا لا بدّ أن يكون هناك إخلاء خلال هذه المرحلة. وعليه فإنّ FWF هي خوارزمية واسمة.
	</p>
</blockquote>

<p>
	دعنا نفترض أن LRU ليست خوارزميةًواسمة، إذًا ستكون هناك حالة <code>‎σ‎</code>، بحيث تخلي الخوازرمية LRU صفحة x موسومة marked page في المرحلة i. وإن كان <code>‎σt‎</code> هو الطلب في المرحلة i حيث أُخلِيت الصفحة x، وبما أن صفحة x موسومة، فلا بدّ أن يكون هناك طلب سابق <code>‎σt*‎</code> للصفحة x في المرحلة نفسها، لذا تكون t * &lt;t<t strong="">. </t>
</p>

<p>
	بعد t* ‎، ستكون x هي الصفحة الأحدث في ذاكرة التخزين المؤقت، لذا ينبغي أن يطلب التسلسل <code>σt*+1,...,σt</code> على الأقل k صفحة مختلفة عن x، وذلك لأجل إخلائها عند الوقت t. هذا يعني أنّ المرحلة i قد طلبت على الأقل k +1 صفحة مختلفة، وهذا يتعارض مع تعريف المرحلة. وعليه نستنتج أنّ LRU خوارزمية واسمة.
</p>

<p>
	خاصية 1.4: كل الخوارزميات الواسمة هي خوارزميات ذات k تنافسية قطعًا.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<strong>برهان</strong>: إذا كانت <code>‎σ‎</code> حالة من مشكلة التصفيح paging problem، و هي عدد مراحل <code>‎σ‎</code>، وإذا كانت l = 1، فستكون كل الخوارزميات الواسمة مُثلى ولا يمكن للخوارزمية غير المتصلة oﬄine algorithm المثلى أن تكون أفضل.
	</p>
</blockquote>

<p>
	إذا افترضنا أنّ l ≥ 2، فستكون تكلفة جميع الخوارزميات الواسمة للحالة <code>‎σ‎</code> أصغر من l ⋅ k، لأنه لا يمكن للخوارزمية الواسمة أن تخلي في كل مرحلة أكثر من k صفحة دون إخلاء صفحة واحدة واسمة على الأقل.
</p>

<p>
	سنحاول الآن أن نبيّن أنّ الخوارزمية غير المتصلة المثلى optimal oﬄine algorithm تخلي على الأقل <code>k + l-2</code> صفحةً في الحالة <code>‎σ‎</code>، حيث تُخلي k في المرحلة الأولى، إضافةً إلى صفحة واحدة على الأقل في كل مرحلة تالية خلال المرحلة الأخيرة:
</p>

<p>
	نعرّف الآن <code>l - 2</code> تسلسلًا فرعيًا منفصلا للحالة <code>‎σ‎</code>، يبدأ التسلسلi ∈ {1,…,l-2} ‎‎ في الموضع الثاني من المرحلة i + 1 وينتهي عند الموضع الأول للمرحلة i + 2. لتكن x الصفحة الأولى من المرحلة i +1، في بداية التسلسل i توجد صفحة x، إضافةً إلى k-1 صفحة مختلفة على الأكثر في ذاكرة التخزين المؤقت الخاصة بالخوارزميات غير المتصلة المثلى.
</p>

<p>
	هناك k صفحة مطلوبة في التسلسل i مختلفة عن x، لذا يتوجّب على الخوارزمية غير المتصلة المثلى إخلاء صفحة واحدة على الأقل في كل تسلسل. وبما أن ذاكرة التخزين المؤقت في المرحلة الأولى فارغة، فإنّ الخوارزمية غير المتصلة المثلى تجري k عملية إخلاء خلال المرحلة الأولى. وهذا يبيّن أنّ:
</p>

<pre class="ipsCode"><strong>wA(σ) ≤ l⋅k ≤ (k+l-2)k ≤ OPT(σ) ⋅ k
</strong></pre>

<p>
	خاصية 1.5: الخوارزمِيتان LRU و FWF خوارِزميتان ذواتا k تنافسية قطعا.
</p>

<p>
	لتكن A خوارزمية متصلة، إذا لم تكن هناك أيّ ثابتة r بحيث تكون هذه الخوارزمية ذات r تنافسية، نقول أنّ A غير تنافسية not competitive.
</p>

<p>
	خاصية 1.6: الخوارزميتان LFU و LIFO غير تنافُسيتان.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<strong>برهان</strong>: لتكن l ‎≥‎ 2 ثابتة، و k ‎≥‎ 2 حجم ذاكرة التخزين المؤقت، سنرقّم صفحات ذاكرة التخزين المؤقت كما يلي 1، …، k +1. انظر التسلسل التالي:
	</p>
</blockquote>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="87293" href="https://academy.hsoub.com/uploads/monthly_2021_12/zS05d.png.cff54348215b9411e0cfc0c8bdb9370a.png" rel=""><img alt="zS05d.png" class="ipsImage ipsImage_thumbnailed" data-fileid="87293" data-unique="kccpja9s9" src="https://academy.hsoub.com/uploads/monthly_2021_12/zS05d.png.cff54348215b9411e0cfc0c8bdb9370a.png"></a>
</p>

<p>
	الصفحة الأولى مطلوبة عدد l مرّة، وكذلك الصفحة 2، وهكذا دواليك، وفي النهاية سيكون لدينا (l-1) طلبًا للصفحة k و k +1.
</p>

<p>
	تملأ الخوارِزميتان LFU و LIFO صفحات المخزن المؤقت بـالصفحات من 1 إلى k، وعند طلب الصفحة k +1 تُخلى الصفحة k، والعكس صحيح. هذا يعني أنّ كل طلب من التسلسل ‎‎(k,k+1)l-1 يخلي صفحة واحدة.
</p>

<p>
	أيضًا، هناك مرات فوات قدرها k-1 فواتًا في ذاكرة التخزين المؤقت cache misses في أول استخدام للصفحات من 1 إلى (k-1)، وهذا يعني أنّ الخوارزميتَين LFU و LIFO تخليان k-1 +2 (l-1)‎‎ صفحة بالضبط.
</p>

<p>
	سنحاول الآن أن نثبت أنّه لكل ثابتة <code>‎τ∈ℜ‎</code>، ولكل ثابتة r ‎≤ 1، يوجد <code>l</code> يحقق:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="87289" href="https://academy.hsoub.com/uploads/monthly_2021_12/lUOxY.png.a2a919b26925ebce57c52ed0cd1c1d2e.png" rel=""><img alt="lUOxY.png" class="ipsImage ipsImage_thumbnailed" data-fileid="87289" data-unique="3zajkoni2" style="width: 380px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_12/lUOxY.png.a2a919b26925ebce57c52ed0cd1c1d2e.png"></a>
</p>

<p>
	والذي يساوي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="87288" href="https://academy.hsoub.com/uploads/monthly_2021_12/arDFI.png.cf9a1512fda4b1b92438e6a3cc9fa137.png" rel=""><img alt="arDFI.png" class="ipsImage ipsImage_thumbnailed" data-fileid="87288" data-unique="d2eqy489d" style="width: 570px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_12/arDFI.png.cf9a1512fda4b1b92438e6a3cc9fa137.png"></a>
</p>

<p>
	لتحقيق هذه المتراجحة، يكفي أن تختار عدد <code>I</code> كبيرًا بما يكفي.
</p>

<p>
	نستنتج من كل هذا أنّ الخوارزميتَين LFU و LIFO غير تنافسيتَين.
</p>

<p>
	خاصية 1.7: لكل r &lt;k، لا توجد أيّ خوارزمية حتمية متصلة ذات r تنافسية لحل مشكلة التصفيح r-competetive deterministic online algorithm for paging.
</p>

<h3>
	المنظور غير المتصل Oﬄine Approach
</h3>

<p>
	قبل المواصلة، راجع مقالة <a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D9%87%D8%A9-r1372/" rel="">تطبيقات خوارزميات الشَّرِهة</a>، وراجع فقرة التخزين المؤقت غير المتصل والاستراتيجيات الخمس المستخدمة فيها.
</p>

<p>
	لقد وسّعنا برنامج المثال بإضافة استراتيجية FWF:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3577_50" style=""><span class="kwd">class</span><span class="pln"> FWF </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Strategy</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">public</span><span class="pun">:</span><span class="pln">
   FWF</span><span class="pun">()</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Strategy</span><span class="pun">(</span><span class="str">"FWF"</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">int</span><span class="pln"> apply</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> requestIndex</span><span class="pun">)</span><span class="pln"> override
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">cache</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> request</span><span class="pun">[</span><span class="pln">requestIndex</span><span class="pun">])</span><span class="pln">
               </span><span class="kwd">return</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
           </span><span class="com">// بعد أول صفحة فارغة، يجب أن تكون كل الصفحات الأخرى فارغة</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">cache</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> emptyPage</span><span class="pun">)</span><span class="pln">
               </span><span class="kwd">return</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="com">// لا صفحات حرة</span><span class="pln">

       </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">void</span><span class="pln"> update</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> cachePos</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> requestIndex</span><span class="pun">,</span><span class="pln"> bool cacheMiss</span><span class="pun">)</span><span class="pln"> override
   </span><span class="pun">{</span><span class="pln">
       </span><span class="com">// لا صفحات حرة  -&gt; فوات -&gt; مسح المخزن المؤقت</span><span class="pln">

       </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">cacheMiss </span><span class="pun">&amp;&amp;</span><span class="pln"> cachePos </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
               cache</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> emptyPage</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	يمكنك تحميل الشيفرة المصدرية كاملة من <a href="http://pastebin.com/AF7EC2xJ" rel="external nofollow">pastebin</a>.
</p>

<p>
	إذا أعدنا استخدام المثال، فسنحصل على النتيجة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3577_52" style=""><span class="typ">Strategy</span><span class="pun">:</span><span class="pln"> FWF
</span><span class="typ">Cache</span><span class="pln"> initial</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln">b</span><span class="pun">,</span><span class="pln">c</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Request</span><span class="pln"> cache </span><span class="lit">0</span><span class="pln"> cache </span><span class="lit">1</span><span class="pln"> cache </span><span class="lit">2</span><span class="pln"> cache miss
  a             a             b             c
  a             a             b             c
  d             d             X             X             x
  e             d             e             X
  b             d             e             b
  b             d             e             b
  a             a             X             X             x
  c             a             c             X
  f              a             c             f
  d             d             X             X             x
  e             d             e             X
  a             d             e             a
  f              f             X             X             x
  b             f             b             X
  e             f             b             e
  c             c             X             X             x
</span><span class="typ">Total</span><span class="pln"> cache misses</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span></pre>

<p>
	على الرغم من أنّ خوارزمية LFD مثلى، إلا أنّ خوارزمية FWF تتميّز بأنّ عدد الفوات فيها أقل، غير أن الهدف الرئيسي هو تقليل عدد عمليات الإخلاء إلى الحد الأدنى، وفي خوارزمية FWF تحدث 5 حالات فوات، مما يعني أنّه ستكون هناك 15 عملية إخلاء، ما يجعلها الخيار الأسوء.
</p>

<h3>
	المنظور المتصل Online Approach
</h3>

<p>
	نريد الآن أن نبحث عن حل لمشكلة التصفيح المتصل online problem of paging، نحن نعلم أنّه لا يمكن لأيّ خوارزمية متصلة أن تكون أفضل من الخوارزمية غير المتصلة المثلى، لأنّه في الخوارزمية غير المتصلة تكون سلسلة الطلبات معروفة منذ البداية، وذلك على خلاف الخوارزميات المتصلة التي لا تعرف مسبقًا إلا الطلبات السابقة وليس اللاحقة، لهذا فإنّ الخوارزميات غير المتصلة لديها دائما معلومات أكثر موازنةً بالخوارزميات المتصلة، ما يجعلها أكثر كفاءة.
</p>

<p>
	سنحتاج إلى بعض التعريفات الدقيقة قبل أن نواصل:
</p>

<ul>
	<li>
		التعريف 1: نقول أنّ المشكلة <code>‎Π‎</code> هي مشكلة تحسين optimization problem إن كانت تتألف من مجموعة من الحالات <code>‎ΣΠ‎</code>. بحيث يكون لكل حالة <code>‎σ∈ΣΠ‎</code> مجموعة من الحلول، ودالة تقييم<code>f σ: Ζσ → ℜ≥ 0</code> تعطي قيمة حقيقية موجبة لكلّ حل من تلك الحلول. نرمز للحل الأمثل optimal solution من بين كل حلول الحالة σ بالرمز OPT (σ‎)‎‎.
	</li>
</ul>

<p style="margin-right: 40px;">
	لكل خوارزمية A، يشير الرمز A (σ‎)‎‎ إلى حل الخوارزمية A للمشكلة ‎Π‎ في الحالة σ، فيما يساوي التعبير <code>wA (‎σ‎) = fσ‎ (A (‎σ))‎‎</code> قيمة الخوارزمية.
</p>

<ul>
	<li>
		التعريف 2: نقول أنّ <a href="https://en.wikipedia.org/wiki/Online_algorithm" rel="external nofollow">خوارزمية متصلة</a> A لمشكلة تصغير ‎Π‎<code>minimization problem</code> لديها معدل تنافسي competetive ratio قيمته r ‎≥ 1 إذا كان هناك عدد <code>‎τ∈ℜ‎</code> ثابت يحقّق:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_3577_54" style=""><span class="pln">wA</span><span class="pun">(σ)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> f</span><span class="pun">σ(</span><span class="pln">A</span><span class="pun">(σ))</span><span class="pln"> </span><span class="pun">≤</span><span class="pln"> r </span><span class="pun">⋅</span><span class="pln"> OPT</span><span class="pun">(σ)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">τ</span></pre>

<p>
	لكل الحالات <code>‎σ∈ΣΠ‎</code>، نقول أنّ الخَوارزمية A خوارزمية r-تكرارية متصلة r-competitive online algorithm إن كان لدينا:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_3577_56" style=""><span class="pln">wA</span><span class="pun">(σ)</span><span class="pln"> </span><span class="pun">≤</span><span class="pln"> r </span><span class="pun">⋅</span><span class="pln"> OPT</span><span class="pun">(σ)</span></pre>

<p>
	لكل عنصر <code>‎σ∈ΣΠ‎</code>، نقول أنّ A خوارزمية متصلة تنافسية قطعا strictly r-competitive online algorithm.
</p>

<p>
	لذا فإن السؤال هو مدى تنافسية خوارزميتنا المتصلة موازنةً بالخوارزمية غير المتصلة المثلى. وصف كل من آلان بورودين Allan Borodin وران الينيف Ran El-Yaniv في <a href="http://www.cs.technion.ac.il/~rani/book.html" rel="external nofollow">كتابهما</a> الشهير خوارزميةَ التصفيح المتصل بالتعبير الطريف التالي:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		هناك <strong>خصم شرير</strong> يعرِف خوارِزميتك والخوارزمية غير المتصلة المثلى. ويحاول في كل خطوة أن يطلب صفحةً تكون أسوأ ما يكون لك، وفي الوقت نفسه تكون أفضل ما يكون للخوارزمية غير المتصلة. والعامل التنافسي competitive factor لخوارزميتك هو مؤشر على مدى سوء خَوارزميتك موازنةً بخوارزمية الخصم المثلى غير المتصلة.
	</p>
</blockquote>

<p>
	إذا أردت أن تكون مكان الخصم، فيمكنك تجربة <a href="https://pastebin.com/index" rel="external nofollow">لعبة الخصم</a> (حاول التغلب على استراتيجيات التصفيح).
</p>

<h4>
	الخوارزميات الواسمة Marking Algorithms
</h4>

<p>
	بدلاً من تحليل كل الخوارزميات على حدة، سنحلّل عائلةً خاصةً من الخوارزميات المتصلة الخاصة بمشكلة التصفيح تسمّى خوارزميات الوسم أو الخوارزميات الواسمة marking algorithms.
</p>

<p>
	تعريف: نقول أنّ خوارزمية A خوارزمية واسمةً، فقط إذا لم تكن تُخلي أيّ صفحة موسومة من ذاكرة التخزين المؤقت، مما يعني أنّ الصفحات التي تُستخدم أثناء أيّ مرحلة لن تُخلى.
</p>

<p>
	لتكن <code>‎σ=(σ1,...,σp)‎‎</code> حالة من المشكلة، و k حجم ذاكرة التخزين المؤقت، فعندئذ يمكن تقسيم <code>‎σ‎</code> إلى مراحل:
</p>

<ul>
	<li>
		المرحلة 1 هي أقصى تتابع لـ <code>‎σ‎</code> من البداية حتى أقصى k صفحة مختلفة مطلوبة.
	</li>
	<li>
		المرحلة i ‎≥‎ 2 هي أقصى تتابع لـ <code>‎σ‎</code> من نهاية المرحلة i-1 حتى أقصى k صفحة مختلفة مطلوبة
	</li>
</ul>

<p>
	على سبيل المثال: في الحالة k = 3، نحصل على:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileext="png" data-fileid="87290" href="https://academy.hsoub.com/uploads/monthly_2021_12/u4VjA.png.c625138c8ec6434578d771b6b22bda07.png" rel=""><img alt="u4VjA.png" class="ipsImage ipsImage_thumbnailed" data-fileid="87290" data-unique="wyu5kfqax" src="https://academy.hsoub.com/uploads/monthly_2021_12/u4VjA.png.c625138c8ec6434578d771b6b22bda07.png"></a>
</p>

<p>
	تتذكّر الخوارزميات الواسمة (ضمنيًا أو صراحة) ما إذا كانت الصفحة موسومةً أم لا، وتكون كل الصفحات غير موسومة في بداية كل مرحلة، وتوسم الصفحة بمجرد أن تُطلب أثناء مرحلة ما.
</p>

<p>
	خاصية 1.3: الخوارِزميتان LRU (وتعني الأقل استخدامًا مؤخرًا - Least recently used، أي إخلاء الصفحة التي لم يُدخل إليها منذ أطول مدة)، و FWF (أي التفريغ عند الملء - Flush when full، وتعني مسح ذاكرة التخزين المؤقت بمجرد وقوع فوات في ذاكرة التخزين المؤقت cache miss) هما خوارِزميتان واسمَتان marking algorithm.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<strong>برهان</strong>: في بداية كل مرحلة (ما عدا المرحلة الأولى) يكون هناك فوات في خوارزمية FWF ، كما تُمسَح ذاكرة التخزين المؤقت، هذا يعني أنّه ستكون لدينا k صفحة فارغة. وفي كل مرحلة، ستُطلب k صفحة مختلفة على الأكثر، لذلك لا بدّ أن يكون هناك إخلاء خلال هذه المرحلة. وبالتالي فإنّ FWF هي خوارزمية واسمة.
	</p>
</blockquote>

<p>
	لنفترض أنّ LRU ليست خوارزميةً واسمة، إذًا ستكون هناك حالة <code>σ</code> بحيث تخلي الخوازرمية LRU صفحة x موسومة marked page في المرحلة i. ليكن *<code>σt‏</code> هو الطلب في المرحلة i، حيث أُخلِيت الصفحة x، عندئذ وبما أن الصفحة x موسومة، فلا بدّ أن يكون هناك طلب سابق *<code>σt‏</code> للصفحة x في المرحلة نفسها، لذلك فإنّ t * &lt;t.
</p>

<p>
	بعد * t‎‎، ستكون x هي الصفحة الأحدث في ذاكرة التخزين المؤقت، لذلك ينبغي أن يطلب التسلسل <code>σt*+1,...,σt</code> على الأقل k صفحة مختلفة عن x لأجل إخلائها عند الوقت t، وهذا يعني أنّ المرحلة i قد طلبت على الأقل k +1 صفحة مختلفة، مما يتعارض مع تعريف المرحلة، وعليه نستنتج أنّ LRU خوارزمية واسمة.
</p>

<p>
	خاصية 1.4: كل الخوارزميات الواسمة هي خوارزميات ذات k تنافسية قطعًا.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		: لتكن <code>‎σ‎</code> حالة من مشكلة التصفيح paging problem، و l عدد مراحل <code>‎σ‎</code>. إذا كانت l = 1، ستكون كل الخوارزميات الواسمة مُثلى، ولا يمكن للخوارزمية غير المتصلة oﬄine algorithm المثلى أن تكون أفضل.
	</p>
</blockquote>

<p>
	إذا افترضنا أنّ ‎ l ≥ 2، فستكون تكلفة جميع الخوارزميات الواسمة للحالة <code>‎σ‎</code> أصغر من ‎‎ l ⋅ k، لأنه لا يمكن للخوارزمية الواسمة أن تخلي في كل مرحلة أكثر من k صفحة دون إخلاء صفحة واحدة واسمة على الأقل.
</p>

<p>
	سنحاول الآن أن نبيّن أنّ الخوارزمية غير المتصلة المثلى optimal oﬄine algorithm تخلي على الأقل <code>k + l-2</code> صفحة في الحالة <code>‎σ‎</code>، حيث تُخلي k في المرحلة الأولى، إضافةً إلى صفحة واحدة على الأقل في كل مرحلة تالية عدا المرحلة الأخيرة.
</p>

<p>
	نعرّف الآن <code>l - 2</code> تسلسلًا فرعيًا منفصلا للحالة <code>‎σ‎</code>، يبدأ التسلسل i ∈ {1,…,l-2}‎ في الموضع الثاني من المرحلة i + 1 وينتهي عند الموضع الأول للمرحلة i + 2. لتكن x الصفحة الأولى من المرحلة i +1. في بداية التسلسل i توجد صفحة x، إضافةً إلى k-1 صفحة مختلفة على الأكثر في ذاكرة التخزين المؤقت الخاصة بالخوارزميات غير المتصلة المثلى.
</p>

<p>
	في التسلسل i، هناك عدد k صفحة مطلوبة مختلفة عن x، لذا يتوجّب على الخوارزمية غير المتصلة المثلى إخلاء صفحة واحدة على الأقل في كل تسلسل. وبما أن ذاكرة التخزين المؤقت في المرحلة الأولى فارغة، فإنّ الخوارزمية غير المتصلة المثلى تجري k عملية إخلاء خلال المرحلة الأولى، وهذا يبيّن أنّ:
</p>

<pre class="ipsCode"><strong><strong>wA(σ) ≤ l⋅k ≤ (k+l-2)k ≤ OPT(σ) ⋅ k
</strong></strong></pre>

<p>
	خاصية 1.5: الخوارزميتان LRU و FWF خوارزميتان ذواتا k تنافسية قطعًا.
</p>

<ul>
	<li>
		تمرين: أثبت أنّ خوارزمية FIFO ليست خوارزميةً واسمة، وإنّما خوارزمية ذات k تنافسية قطعًا.
	</li>
	<li>
		لتكن A خوارزمية متصلة، إذا لم تكن هناك أيّ ثابتة r بحيث تكون هذه الخوارزمية ذات r تنافسية، نقول أنّ A غير تنافسية not competitive.
	</li>
</ul>

<p>
	خاصية 1.6: الخوارزميتان LFU و LIFO غير تنافُسيتان.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix" data-gramm="false">
		<p>
			 
		</p>

		<p>
			برهان: لتكن l ‎≥‎ 2 ثابتة، و k ‎≥‎ 2 هو حجم ذاكرة التخزين المؤقت، سنرقّم صفحات ذاكرة التخزين المؤقت كما يلي 1، …، k +1. انظر التسلسل التالي:
		</p>

		<p style="text-align: center;">
			<img alt="zS05d.png" class="ipsImage ipsImage_thumbnailed" data-fileid="87293" data-unique="fimt2i0q9" style="width: 400px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_12/zS05d.png.cff54348215b9411e0cfc0c8bdb9370a.png">
		</p>

		<p>
			 
		</p>
	</div>
</blockquote>

<p>
	الصفحة الأولى مطلوبة عدد l مرّة، وكذلك الصفحة 2، وهكذا دواليك. في النهاية، سيكون هناك (l-1) طلبًا للصفحة k و k +1.
</p>

<p>
	تملأ الخوارِزميتان LFU وLIFO صفحات المخزن المؤقت بـالصفحات من 1 إلى k، وتُخلى الصفحة k عند طلب الصفحة k +1، والعكس صحيح. هذا يعني أنّ كل طلب من التسلسل ‎‎(k,k+1)l-1 يخلي صفحة واحدة.
</p>

<p>
	أيضًا، هناك عدد k-1 فواتًا في ذاكرة التخزين المؤقت cache misses في أول استخدام للصفحات من 1 إلى (k-1)، وهذا يعني أنّ الخوارزميتَين LFU و LIFO تخليان k-1 +2 (l-1)‎‎ صفحة بالضبط.
</p>

<p>
	الآن، سنحاول أن نثبت أنّه لكل ثابتة <code>‎τ∈ℜ‎</code>، ولكل ثابتة r ‎≤ 1، يوجد <code>l</code> يحقق:
</p>

<p style="text-align: center;">
	<img alt="lUOxY.png" class="ipsImage ipsImage_thumbnailed" data-fileid="87289" data-unique="j6a5p7cul" style="width: 400px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_12/lUOxY.png.a2a919b26925ebce57c52ed0cd1c1d2e.png">
</p>

<p>
	والذي يساوي:
</p>

<p style="text-align: center;">
	<img alt="arDFI.png" class="ipsImage ipsImage_thumbnailed" data-fileid="87288" data-unique="eknb8ail8" style="width: 550px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_12/arDFI.png.cf9a1512fda4b1b92438e6a3cc9fa137.png">
</p>

<p>
	لتحقيق هذه المتراجحة، يكفي أن تختار عدد I كبيرًا بما يكفي، من ذلك نستنتج أنّ الخوارزميتَين LFU و LIFO غير تنافسيتَين.
</p>

<p>
	خاصية 1.7: لكل r &lt;k، لا توجد أيّ خوارزمية حتمية متصلة ذات r تنافسية لحل مشكلة التصفيح r-competetive deterministic online algorithm for paging.
</p>

<p>
	برهان هذه الخاصية طويل نوعًا ما ويستند إلى فكرة أنّ LFD هي خوارزمية مثلى.
</p>

<p>
	السؤال الآن هو: هل هناك منظور أفضل؟ للإجابة على هذا السؤال سيكون علينا أن نتجاوز المنظور الحتمي deterministic approach ونستخدم المقاربات العشوائية في خوَارزميتنا، وهو أمر سنعود إليه لاحقًا في هذه السلسلة.
</p>

<p>
	ترجمة -بتصرّف- للفصول 21 و 23 و 24 و25 و26 و27 من كتاب <a href="https://goalkicker.com/AlgorithmsBook/" rel="external nofollow">Algorithms Notes for Professionals</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%B1%D8%AA%D9%8A%D8%A8-%D9%88%D8%A3%D8%B4%D9%87%D8%B1%D9%87%D8%A7-r1413/" rel="">خوارزميات الترتيب وأشهرها</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%A3%D8%B4%D8%AC%D8%A7%D8%B1-r1373/" rel="">خوارزميات تحليل المسارات في الأشجار</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1282/" rel="">مدخل إلى الخوارزميا</a><a href="https://academy.hsoub.com/programming/advanced/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1282/" rel="">ت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/python/" rel="">تعلم بايثون</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/php/" rel="">تعلم PHP</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1410</guid><pubDate>Fri, 10 Dec 2021 16:00:00 +0000</pubDate></item><item><title>&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x62E;&#x631;&#x64A;&#x637;&#x629; &#x648;&#x645;&#x62C;&#x645;&#x648;&#x639;&#x629; &#x644;&#x628;&#x646;&#x627;&#x621; &#x645;&#x641;&#x647;&#x631;&#x633; Indexer</title><link>https://academy.hsoub.com/programming/advanced/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AE%D8%B1%D9%8A%D8%B7%D8%A9-%D9%88%D9%85%D8%AC%D9%85%D9%88%D8%B9%D8%A9-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D9%85%D9%81%D9%87%D8%B1%D8%B3-indexer-r1384/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_11/61a150ad07df9_-----Indexer.png.79d1227c323792f25b3b4414893c3a6a.png" /></p>
<p>
	انتهينا من بناء زاحف الانترنت crawler في مقالة "<a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A3%D8%B3%D9%84%D9%88%D8%A8-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D8%A8%D8%A7%D9%84%D8%B9%D9%85%D9%82-%D8%A3%D9%88%D9%84%D8%A7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%AA%D9%8A%D9%86-iterables-%D9%88iterators-r1383/" rel="">تنفيذ أسلوب البحث بالعمق أولًا باستخدام الواجهتين Iterables و Iterators</a>"، وسننتقل الآن إلى الجزء التالي من تطبيق محرك البحث، وهو الفهرس. يُعدّ الفهرس -في سياق البحث عبر الإنترنت- هيكل بياناتٍ data structure يُسهِّل من العثور على الصفحات التي تحتوي على كلمة معينة، كما يساعدنا على معرفة عدد مرات ظهور الكلمة في كل صفحة، مما يُمكِّننا من تحديد الصفحات الأكثر صلة.
</p>

<p>
	على سبيل المثال، إذا أدخل المُستخدِم كلمتي البحث <a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D9%84%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-java-r599/" rel="">Java</a> و<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">programming</a>، فإننا نبحث عن كلتيهما ونسترجع عدة صفحاتٍ لكل كلمة. ستتضمَّن الصفحات الناتجة عن البحث عن كلمة Java مقالاتٍ عن جزيرة Java، وعن الاسم المستعار للقهوة، وعن لغة البرمجة جافا. في المقابل، ستتضمَّن الصفحات الناتجة عن البحث عن كلمة programming مقالاتٍ عن لغات البرمجة المختلفة، وعن استخداماتٍ أخرى للكلمة.
</p>

<p>
	باختيارنا لكلمات بحث تبحث عن الصفحات التي تحتوي على الكلمتين، سنتطلّع لاستبعاد المقالات التي ليس لها علاقة بكلمات البحث، وفي التركيز على الصفحات التي تتحدث عن البرمجة بلغة جافا.
</p>

<p>
	والآن وقد فهمنا ما يعنيه الفهرس والعمليات التي يُنفذّها، يُمكِننا أن نُصمم هيكل بياناتٍ يُمثِّله.
</p>

<h2>
	اختيار هيكل البيانات
</h2>

<p>
	تتلخص العملية الرئيسية للفهرس في إجراء البحث، فنحن نحتاج إلى إمكانية البحث عن كلمةٍ معيّنةٍ والعثور على جميع الصفحات التي تتضمَّنها. ربما يكون استخدام تجميعة من الصفحات هو الأسلوب الأبسط لتحقيق ذلك، فبتوفّر كلمة بحث معينة، يُمكِننا المرور عبر محتويات الصفحات، وأن نختار من بينها تلك التي تحتوي على كلمة البحث، ولكن زمن التشغيل في تلك الطريقة سيتناسب مع عدد الكلمات الموجودة في جميع الصفحات، مما يَعنِي أن العملية ستكون بطيئةً للغاية.
</p>

<p>
	والطريقة البديلة عن تجميعة الصفحات collection هي الخريطة map، والتي هي عبارة عن هيكل بيانات يتكون من مجموعة من أزواج، حيث يتألف كل منها من مفتاح وقيمة key-value.
</p>

<p>
	تُوفِّر الخريطة طريقةً سريعةً للبحث عن مفتاح معين والعثور على قيمته المقابلة. سنُنشِئ مثلًا الخريطة <code>TermCounter</code>، بحيث تربُط كل كلمة بحث بعدد مرات ظهور تلك الكلمة في كل صفحة، وستُمثِل المفاتيح كلمات البحث، بينما ستُمثِل القيم عدد مرات الظهور (أو تكرار الظهور).
</p>

<p>
	تُوفِّر جافا الواجهة <code>Map</code> التي تُخصِّص التوابع methods المُفترَض توافرها في أيّ خريطة، ومن أهمها ما يلي:
</p>

<ul>
	<li>
		<code>get(key)‎</code>: يبحث هذا التابع عن مفتاح معين ويعيد قيمته المقابلة.
	</li>
	<li>
		<code>put(key, value)‎</code>: يضيف هذا التابع زوجًا جديدًا من أزواج مفتاح/قيمة إلى خريطة من النوع <code>Map</code>، أو يستبدل القيمة المرتبطة بالمفتاح في حالة وجوده بالفعل.
	</li>
</ul>

<p>
	تُوفِّر جافا عدة تنفيذاتٍ للواجهة <code>Map</code>، ومن بينها التنفيذان <code>HashMap</code> و<code>TreeMap</code> اللذان سنناقشهما في مقالات قادمة ونُحلّل أداء كُلٍّ منهما.
</p>

<p>
	بالإضافة إلى الخريطة <code>TermCounter</code> التي تربط كلمات البحث بعدد مرات ظهورها، سنُعرِّف أيضًا الصنف <code>Index</code> الذي يربط كل كلمة بحث بتجميعة الصفحات التي تَظهرَ فيها الكلمة. يقودنا ذلك إلى السؤال التالي: كيف نُمثِل تجميعة الصفحات؟ سنتوصل إلى الإجابة المناسبة إذا فكرنا في العمليات التي ننوي تنفيذها على تلك التجميعة.
</p>

<p>
	سنحتاج في هذا المثال إلى دمج مجموعتين أو أكثر، وإلى العثور على الصفحات التي تظهر الكلمات فيها جميعًا. ويُمكِن النظر إلى ذلك وكأنه عملية تقاطع مجموعتين sets. يتمثَل تقاطع أي مجموعتين بمجموعة العناصر الموجودة في كلتيهما.
</p>

<p>
	تُخصِّص الواجهة <code>Set</code> بلغة جافا العملياتِ التي يُفترَض لأي مجموعة أن تكون قادرةً على تنفيذها، ولكنها لا تُوفِّر عملية تقاطعِ مجموعتين، وإن كانت تُوفِّر توابعَ يُمكِن باستخدامها تنفيذ عملية التقاطع وغيرها بكفاءة. وفيما يلي التوابع الأساسية للواجهة <code>Set</code>:
</p>

<ul>
	<li>
		<code>add(element)‎</code>: يضيف هذا التابع عنصرًا إلى مجموعة. وإذا كان العنصر موجودًا فعليًا ضمن المجموعة، فإنه لا يفعل شيئًا.
	</li>
	<li>
		<code>contains(element)‎</code>: يَفحَص هذا التابع ما إذا كان العنصر المُمرَّر موجودًا في المجموعة.
	</li>
</ul>

<p>
	تُوفِّر جافا عدة تنفيذات للواجهة <code>Set</code>، ومن بينها الصنفان <code>HashSet</code> و<code>TreeSet</code>.
</p>

<p>
	الآن وقد صممنا هياكل البيانات من أعلى لأسفل، فإننا سنُنفِّذها من الداخل إلى الخارج بدءًا من الصنف <code>TermCounter</code>.
</p>

<h2>
	الصنف TermCounter
</h2>

<p>
	يُمثِل الصنف <code>TermCounter</code> ربطًا بين كلمات البحث مع عدد مرات حدوثها في الصفحات، وتَعرِض الشيفرة التالية الجزء الأول من تعريف الصنف:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2484_11" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">TermCounter</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">private</span><span class="pln"> </span><span class="typ">Map</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Integer</span><span class="pun">&gt;</span><span class="pln"> </span><span class="typ">map</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">private</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> label</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">TermCounter</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> label</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">label </span><span class="pun">=</span><span class="pln"> label</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="typ">map</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">HashMap</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Integer</span><span class="pun">&gt;();</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يربط متغير النسخة <code>map</code> الكلمات بعدد مرات حدوثها، بينما يُحدّد المتغير <code>label</code> المستند الذي يحتوي على تلك الكلمات، وسنَستخدِمه لتخزين محددات الموارد الموحدة <a href="https://academy.hsoub.com/marketing/performance-marketing/analytics/%D8%A8%D9%86%D9%8A%D8%A9-%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-url-%D9%88%D8%A3%D9%87%D9%85%D9%8A%D8%AA%D9%87%D8%A7-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%8A%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%88%D9%82%D8%B9-r159/" rel="">URLs</a>.
</p>

<p>
	يُعدّ الصنف <code>HashMap</code> أكثر تنفيذات الواجهة <code>Map</code> شيوعًا، وسنَستخدِمه لتنفيذ عملية الربط، كما سنتناول طريقة عمله ونفهم سبب شيوع استخدامه في المقالات القادمة.
</p>

<p>
	يُوفِّر الصنف <code>TermCounter</code> التابعين <code>put</code> و<code>get</code> المُعرَّفين على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2484_13" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> put</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> term</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> count</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">map</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="pln">term</span><span class="pun">,</span><span class="pln"> count</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Integer</span><span class="pln"> get</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> term</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Integer</span><span class="pln"> count </span><span class="pun">=</span><span class="pln"> </span><span class="typ">map</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">term</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> count </span><span class="pun">==</span><span class="pln"> null </span><span class="pun">?</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> count</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	يَعمَل التابع <code>put</code> بمثابة تابع مُغلِّف، فعندما تستدعيه، سيَستدعِي بدوره التابع <code>put</code> المُعرَّف في الخريطة المُخزَّنة داخله.
</p>

<p>
	من الجهة الأخرى، يقوم التابع <code>get</code> بعمل حقيقيّ، فعندما تَستدعِيه سيَستدعِي التابع <code>get</code> المُعرَّف في الخريطة، ثم يَفحَص النتيجة، فإذا لم تكن الكلمة موجودةً في الخريطة من قبل، فإن التابع <code>TermCounter.get</code> يعيد القيمة 0.
</p>

<p>
	يُساعدنا تعريف التابع <code>get</code> بتلك الطريقة على تعريف التابع <code>incrementTermCount</code> بسهولة، ويَستقبِل ذلك التابع كلمةً ويزيد العدّاد الخاصَّ بها بمقدار 1.
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2484_27" style=""><span class="pln">    public void incrementTermCount</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> term</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        put</span><span class="pun">(</span><span class="pln">term</span><span class="pun">,</span><span class="pln"> get</span><span class="pun">(</span><span class="pln">term</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	إذا لم تكن الكلمة موجودةً ضمن الخريطة، فسيعيد <code>get</code> القيمة 0، ونزيد العداد بمقدار 1، ثم نَستخدِم التابع <code>put</code> لإضافة زوج مفتاح/قيمة key-value جديد إلى الخريطة. في المقابل، إذا كانت الكلمة موجودةً في الخريطة فعلًا، فإننا نسترجع قيمة العداد القديم، ونزيدها بمقدار 1، ثم نُخزِّنها بحيث تَستبدِل القيمة القديمة.
</p>

<p>
	يُعرِّف الصنف <code>TermCounter</code> توابع أخرى للمساعدة على فهرسة صفحات الإنترنت:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2484_25" style=""><span class="pln">    public void processElements</span><span class="pun">(</span><span class="typ">Elements</span><span class="pln"> paragraphs</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Node</span><span class="pln"> node</span><span class="pun">:</span><span class="pln"> paragraphs</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            processTree</span><span class="pun">(</span><span class="pln">node</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    public void processTree</span><span class="pun">(</span><span class="typ">Node</span><span class="pln"> root</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Node</span><span class="pln"> node</span><span class="pun">:</span><span class="pln"> new </span><span class="typ">WikiNodeIterable</span><span class="pun">(</span><span class="pln">root</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">node instanceof </span><span class="typ">TextNode</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                processText</span><span class="pun">(((</span><span class="typ">TextNode</span><span class="pun">)</span><span class="pln"> node</span><span class="pun">).</span><span class="pln">text</span><span class="pun">());</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    public void processText</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> text</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> array </span><span class="pun">=</span><span class="pln"> text</span><span class="pun">.</span><span class="pln">replaceAll</span><span class="pun">(</span><span class="str">"\\pP"</span><span class="pun">,</span><span class="pln"> </span><span class="str">" "</span><span class="pun">).</span><span class="pln">
                              toLowerCase</span><span class="pun">().</span><span class="pln">
                              split</span><span class="pun">(</span><span class="str">"\\s+"</span><span class="pun">);</span><span class="pln">

        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">int i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">array</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">String</span><span class="pln"> term </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
            incrementTermCount</span><span class="pun">(</span><span class="pln">term</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span></pre>

<ul>
	<li>
		<code>processElements</code>: يَستقبِل هذا التابع كائنًا من النوع <code>Elements</code> الذي هو تجميعة من كائنات <code>Element</code>. يمرّ التابع عبر التجميعة ويَستدعِي لكل كائنٍ منها التابع <code>processTree</code>.
	</li>
	<li>
		<code>processTree</code>: يَستقبِل عقدةً تُمثِّل عقدة جذر شجرة DOM، ويَمرّ التابع عبر الشجرة، ليعثر على العقد التي تحتوي على نص، ثم يَستخرِج منها النص ويُمرِّره إلى التابع <code>processText</code>.
	</li>
	<li>
		<code>processText</code>: يَستقبِل سلسلةً نصيةً من النوع <code>String</code> تحتوي على كلمات وفراغات وعلامات ترقيم وغيرها. يَحذِف التابع علامات الترقيم باستبدالها بفراغات، ويُحوِّل الأحرف المتبقية إلى حالتها الصغرى، ثم يُقسِّم النص إلى كلمات. يَمرّ التابع عبر تلك الكلمات، ويَستدِعي التابع <code>incrementTermCount</code> لكُلٍّ منها، ويَستقبِل التابعان <code>replaceAll</code> و<code>split</code> <a href="http://thinkdast.com/regex" rel="external nofollow">تعبيرات نمطية regular expression</a> مثل معاملات.
	</li>
</ul>

<p>
	وأخيرًا، انظر إلى المثال التالي الذي يُوضِّح طريقة استخدام الصنف <code>TermCounter</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2484_23" style=""><span class="pln">    </span><span class="typ">String</span><span class="pln"> url </span><span class="pun">=</span><span class="pln"> </span><span class="str">"http://en.wikipedia.org/wiki/Java_(programming_language)"</span><span class="pun">;</span><span class="pln">
    </span><span class="typ">WikiFetcher</span><span class="pln"> wf </span><span class="pun">=</span><span class="pln"> new </span><span class="typ">WikiFetcher</span><span class="pun">();</span><span class="pln">
    </span><span class="typ">Elements</span><span class="pln"> paragraphs </span><span class="pun">=</span><span class="pln"> wf</span><span class="pun">.</span><span class="pln">fetchWikipedia</span><span class="pun">(</span><span class="pln">url</span><span class="pun">);</span><span class="pln">

    </span><span class="typ">TermCounter</span><span class="pln"> counter </span><span class="pun">=</span><span class="pln"> new </span><span class="typ">TermCounter</span><span class="pun">(</span><span class="pln">url</span><span class="pun">);</span><span class="pln">
    counter</span><span class="pun">.</span><span class="pln">processElements</span><span class="pun">(</span><span class="pln">paragraphs</span><span class="pun">);</span><span class="pln">
    counter</span><span class="pun">.</span><span class="pln">printCounts</span><span class="pun">();</span></pre>

<p>
	يَستخدِم هذا المثال كائنًا من النوع <code>WikiFetcher</code> لتحميل صفحةٍ من موقع ويكيبيديا، ثم يُحلّل النص الرئيسيَّ الموجودَ بها، ويُنشِئ كائنًا من النوع <code>TermCounter</code> ويَستخدِمه لعدّ الكلمات الموجودة في الصفحة.
</p>

<p>
	يُمكِنك تشغيل الشيفرة في القسم التالي، واختبار فهمك لها بإكمال متن التابع غير المكتمل.
</p>

<h2>
	تمرين 6
</h2>

<p>
	ستجد ملفات شيفرة التمرين في <a href="https://github.com/AllenDowney/ThinkDataStructures" rel="external nofollow">مستودع الكتاب</a>:
</p>

<ul>
	<li>
		<code>TermCounter.java</code>: يحتوي على شيفرة القسم السابق.
	</li>
	<li>
		<code>TermCounterTest.java</code>: يحتوي على شيفرة اختبار الملف <code>TermCounter.java</code>.
	</li>
	<li>
		<code>Index.java</code>: يحتوي على تعريف الصنف الخاص بالجزء التالي من التمرين.
	</li>
	<li>
		<code>WikiFetcher.java</code>: يحتوي على الصنف الذي استخدمناه في التمرين السابق لتحميل صفحة إنترنت وتحليلها.
	</li>
	<li>
		<code>WikiNodeIterable.java</code>: يحتوي على الصنف الذي استخدمناه لاجتياز عقد شجرة DOM.
	</li>
</ul>

<p>
	ستَجِد أيضًا ملف البناء <code>build.xml</code>.
</p>

<p>
	نفِّذ الأمر <code>ant build</code> لتصريف ملفات الشيفرة، ثم نفِّذ الأمر <code>ant TermCounter</code> لكي تُشغِّل شيفرة القسم السابق. تَطبَع تلك الشيفرة قائمة بالكلمات وعدد مرات ظهورها، وينبغي أن تحصُل على خرجٍ مشابهٍ لما يلي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2484_31" style=""><span class="pln">genericservlet</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
configurations</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
claimed</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
servletresponse</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
occur</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="typ">Total</span><span class="pln"> of all counts </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span></pre>

<p>
	قد تجد ترتيب ظهور الكلمات مختلفًا عندما تُشغِّل الشيفرة، وينبغي أن يَطبَع السطر الأخير المجموعَ الكلّيَّ لعدد مرات ظهور جميع الكلمات، ولكنه يعيد القيمة -1 في هذا المثال لأن التابع <code>size</code> غير مكتمل. أكمل متن هذا التابع، ثم نفِّذ الأمر <code>ant TermCounter</code> مرةً أخرى، حيث ينبغي أن تحصل على القيمة 4798.
</p>

<p>
	نفِّذ الأمر <code>ant TermCounterTest</code> لكي تتأكَّد من أنك قد أكملت جزء التمرين ذاك بشكلٍ صحيح.
</p>

<p>
	بالنسبة للجزء الثاني من التمرين، فسنُوفِّر تنفيذًا لكائنٍ من النوع <code>Index</code>، وسيكون عليك إكمال متن التابع غيرِ المكتمل. انظر إلى تعريف الصنف:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2484_33" style=""><span class="pln">public </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Index</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    private </span><span class="typ">Map</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Set</span><span class="pun">&lt;</span><span class="typ">TermCounter</span><span class="pun">&gt;&gt;</span><span class="pln"> index </span><span class="pun">=</span><span class="pln"> 
        new </span><span class="typ">HashMap</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Set</span><span class="pun">&lt;</span><span class="typ">TermCounter</span><span class="pun">&gt;&gt;();</span><span class="pln">

    public void add</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> term</span><span class="pun">,</span><span class="pln"> </span><span class="typ">TermCounter</span><span class="pln"> tc</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Set</span><span class="pun">&lt;</span><span class="typ">TermCounter</span><span class="pun">&gt;</span><span class="pln"> set </span><span class="pun">=</span><span class="pln"> get</span><span class="pun">(</span><span class="pln">term</span><span class="pun">);</span><span class="pln">

        </span><span class="pun">//</span><span class="pln"> </span><span class="pun">أنشئ</span><span class="pln"> </span><span class="pun">مجموعةً</span><span class="pln"> </span><span class="pun">جديدةً</span><span class="pln"> </span><span class="pun">إذا</span><span class="pln"> </span><span class="pun">كنت</span><span class="pln"> </span><span class="pun">ترى</span><span class="pln"> </span><span class="pun">الكلمة</span><span class="pln"> </span><span class="pun">للمرة</span><span class="pln"> </span><span class="pun">الأولى</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">set </span><span class="pun">==</span><span class="pln"> null</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            set </span><span class="pun">=</span><span class="pln"> new </span><span class="typ">HashSet</span><span class="pun">&lt;</span><span class="typ">TermCounter</span><span class="pun">&gt;();</span><span class="pln">
            index</span><span class="pun">.</span><span class="pln">put</span><span class="pun">(</span><span class="pln">term</span><span class="pun">,</span><span class="pln"> set</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">//</span><span class="pln"> </span><span class="pun">إذا</span><span class="pln"> </span><span class="pun">كنت</span><span class="pln"> </span><span class="pun">قد</span><span class="pln"> </span><span class="pun">رأيت</span><span class="pln"> </span><span class="pun">الكلمة</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">قبل،</span><span class="pln"> </span><span class="pun">عدِّل</span><span class="pln"> </span><span class="pun">المجموعة</span><span class="pln"> </span><span class="pun">الموجودة</span><span class="pln">
        set</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">tc</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    public </span><span class="typ">Set</span><span class="pun">&lt;</span><span class="typ">TermCounter</span><span class="pun">&gt;</span><span class="pln"> get</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> term</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> index</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">term</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	يُمثِل متغير النسخة <code>index</code> خريطةً map تربط كل كلمة بحثٍ بمجموعةِ كائناتٍ تنتمي إلى النوع <code>TermCounter</code>، ويُمثِّل كل كائنٍ منها صفحةً ظهرت فيها تلك الكلمة.
</p>

<p>
	يضيف التابع <code>add</code> كائنًا جديدًا من النوع <code>TermCounter</code> إلى المجموعة الخاصة بكلمةٍ معينة. وعندما نُفهرس كلمةً لأول مرة، سيكون علينا أن نُنشِئ لها مجموعةً جديدة، أما إذا كنا قد قابلنا الكلمة من قبل، فسنضيف فقط عنصرًا جديدًا إلى مجموعة تلك الكلمة، أي يُعدِّل التابع <code>set.add</code> عندما تكون المجموعة موجودةً بالفعل داخل <code>index</code> ولا يُعدِّل <code>index</code> ذاته، حيث إننا سنضطر إلى تعديل <code>index</code> فقط عند إضافة كلمةٍ جديدة.
</p>

<p>
	وأخيرًا، يستقبل التابع <code>get</code> كلمة بحثٍ، ويعيد مجموعة كائنات الصنف <code>TermCounter</code> المقابلة للكلمة.
</p>

<p>
	يُعَدّ هيكل البيانات هذا مُعقدًا بعض الشيء. ولاختصاره، يمكن القول أن كائن النوع <code>Index</code> يحتوي على خريطةٍ من النوع <code>Map</code> تربط كل كلمة بحثٍ بمجموعةٍ من النوع <code>Set</code>، المكوَّنةٍ من كائناتٍ تنتمي إلى النوع <code>TermCounter</code>، حيث يُمثِل كلّ كائنٍ منها خريطةً تربط كلماتِ البحث بعدد مرات ظهور تلك الكلمات.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="83458" href="https://academy.hsoub.com/uploads/monthly_2021_11/001Index_Structure.PNG.79660b76fa9223cd751a03237b8f2e87.PNG" rel="" data-fileext="PNG"><img alt="001Index_Structure.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="83458" data-unique="jst7yapqc" src="https://academy.hsoub.com/uploads/monthly_2021_11/001Index_Structure.PNG.79660b76fa9223cd751a03237b8f2e87.PNG"></a>
</p>

<p>
	تَعرِض الصورة السابقة رسمًا توضيحيًّا لتلك الكائنات، حيث يحتوي كائن الصنف <code>Index</code> على متغير نسخة اسمه <code>index</code> يشير إلى كائن الصنف <code>Map</code>، الذي يحتوي -في هذا المثال- على سلسلةٍ نصيّةٍ واحدةٍ Java مرتبطةٍ بمجموعةٍ من النوع <code>Set</code> تحتوي على كائنين من النوع <code>TermCounter</code>؛ بحيث يكون واحدًا لكل صفحة قد ظهرت فيها كلمة Java.
</p>

<p>
	يتضمَّن كلّ كائنٍ من النوع <code>TermCounter</code> على متغيرَ النسخة <code>label</code> الذي يُمثِل مُحدّد الموارد الموحد URL الخاص بالصفحة، كما يتضمَّن المتغيرَ <code>map</code> الذي يحتوي على الكلمات الموجودة في الصفحة، وعدد مرات حدوث كلّ كلمةٍ منها.
</p>

<p>
	يُوضِّح التابع <code>printIndex</code> طريقة قراءة هيكل البيانات ذاك:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2484_35" style=""><span class="pln">    public void printIndex</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="pun">//</span><span class="pln"> </span><span class="pun">مرّ</span><span class="pln"> </span><span class="pun">عبر</span><span class="pln"> </span><span class="pun">كلمات</span><span class="pln"> </span><span class="pun">البحث</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">String</span><span class="pln"> term</span><span class="pun">:</span><span class="pln"> keySet</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">term</span><span class="pun">);</span><span class="pln">

            </span><span class="pun">//</span><span class="pln"> </span><span class="pun">لكل</span><span class="pln"> </span><span class="pun">كلمة،</span><span class="pln"> </span><span class="pun">اطبع</span><span class="pln"> </span><span class="pun">الصفحات</span><span class="pln"> </span><span class="pun">التي</span><span class="pln"> </span><span class="pun">ظهرت</span><span class="pln"> </span><span class="pun">فيها</span><span class="pln"> </span><span class="pun">الكلمة</span><span class="pln"> </span><span class="pun">وعدد</span><span class="pln"> </span><span class="pun">مرات</span><span class="pln"> </span><span class="pun">ظهورها</span><span class="pln">
            </span><span class="typ">Set</span><span class="pun">&lt;</span><span class="typ">TermCounter</span><span class="pun">&gt;</span><span class="pln"> tcs </span><span class="pun">=</span><span class="pln"> get</span><span class="pun">(</span><span class="pln">term</span><span class="pun">);</span><span class="pln">
            </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">TermCounter</span><span class="pln"> tc</span><span class="pun">:</span><span class="pln"> tcs</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">Integer</span><span class="pln"> count </span><span class="pun">=</span><span class="pln"> tc</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="pln">term</span><span class="pun">);</span><span class="pln">
                </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"    "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> tc</span><span class="pun">.</span><span class="pln">getLabel</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> count</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	تمرّ حلقة التكرار الخارجية عبر كلمات البحث، بينما تمرّ حلقة التكرار الداخلية عبر كائنات الصنف <code>TermCounter</code>.
</p>

<p>
	نفِّذ الأمر <code>ant build</code> لكي تتأكَّد من تصريف ملفات الشيفرة، ثم نفِّذ الأمر <code>ant Index</code>. سيُحمِّل صفحتين من موقع ويكيبيديا ويُفهرسهما، ثم يَطبَع النتائج، ولكنك لن ترى أي خرجٍ عند تشغيله لأننا تركنا أحد التوابع فارغًا.
</p>

<p>
	دورك الآن هو إكمال التابع <code>indexPage</code> الذي يَستقبِل مُحدّد موارد موحّدًا URL (عبارة عن سلسلةٍ نصيةٍ)، وكائنًا من النوع <code>Elements</code>، ويُحدِّث الفهرس. تُوضِّح التعليقات ما ينبغي أن تفعله:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2484_37" style=""><span class="pln">public void indexPage</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> url</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Elements</span><span class="pln"> paragraphs</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">//</span><span class="pln"> </span><span class="pun">أنشئ</span><span class="pln"> </span><span class="pun">كائنًا</span><span class="pln"> </span><span class="pun">من</span><span class="pln"> </span><span class="pun">النوع‫</span><span class="pln"> </span><span class="typ">TermCounter</span><span class="pln"> </span><span class="pun">وعدّ</span><span class="pln"> </span><span class="pun">الكلمات</span><span class="pln"> </span><span class="pun">بكل</span><span class="pln"> </span><span class="pun">فقرة</span><span class="pln">

    </span><span class="pun">//</span><span class="pln"> </span><span class="pun">لكل</span><span class="pln"> </span><span class="pun">كلمة</span><span class="pln"> </span><span class="pun">في</span><span class="pln"> </span><span class="pun">كائن</span><span class="pln"> </span><span class="pun">النوع‫</span><span class="pln"> </span><span class="typ">TermCounter</span><span class="pun">،</span><span class="pln"> </span><span class="pun">أضفه</span><span class="pln"> </span><span class="pun">إلى</span><span class="pln"> index
</span><span class="pun">}</span></pre>

<p>
	نفِّذ الأمر <code>ant Index</code> . وبعد الانتهاء، إذا كان كل شيء سليمًا، فستحصل على الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2484_41" style=""><span class="pun">...</span><span class="pln">
configurations
    http</span><span class="pun">:</span><span class="com">//en.wikipedia.org/wiki/Programming_language 1</span><span class="pln">
    http</span><span class="pun">:</span><span class="com">//en.wikipedia.org/wiki/Java_(programming_language) 1</span><span class="pln">
claimed
    http</span><span class="pun">:</span><span class="com">//en.wikipedia.org/wiki/Java_(programming_language) 1</span><span class="pln">
servletresponse
    http</span><span class="pun">:</span><span class="com">//en.wikipedia.org/wiki/Java_(programming_language) 2</span><span class="pln">
occur
    http</span><span class="pun">:</span><span class="com">//en.wikipedia.org/wiki/Java_(programming_language) 2</span></pre>

<p>
	ضع في الحسبان أنه عند إجرائك للبحث قد يختلف ترتيب ظهور كلمات البحث.
</p>

<p>
	وأخيرًا، نفِّذ الأمر <code>ant TestIndex</code> لكي تتأكَّد من اكتمال هذا الجزء من التمرين على النحو المطلوب.
</p>

<p>
	ترجمة -بتصرّف- للفصل <a href="https://greenteapress.com/thinkdast/html/thinkdast009.html" rel="external nofollow">Chapter 8: Indexer</a> من كتاب <a href="https://greenteapress.com/thinkdast/html/index.html" rel="external nofollow">Think Data Structures: Algorithms and Information Retrieval in Java</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/java/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A9-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1389/" rel="">تحليل زمن تشغيل الخرائط المنفذة باستخدام مصفوفة في جافا</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A3%D8%B3%D9%84%D9%88%D8%A8-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D8%A8%D8%A7%D9%84%D8%B9%D9%85%D9%82-%D8%A3%D9%88%D9%84%D8%A7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%AA%D9%8A%D9%86-iterables-%D9%88iterators-r1383/" rel="">تنفيذ أسلوب البحث بالعمق أولا باستخدام الواجهتين Iterables وIterators</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D8%A7%D8%B2%D8%AF%D9%88%D8%A7%D8%AC%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B1%D8%A7%D8%A8%D8%B7-r1350/" rel="">تحليل زمن تشغيل القوائم المنفذة باستخدام قائمة ازدواجية الترابط</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%d9%83%d9%8a%d9%81-%d8%aa%d8%aa%d8%b9%d9%84%d9%85-%d8%a7%d9%84%d8%a8%d8%b1%d9%85%d8%ac%d8%a9-r17/" rel="">كيف تتعلم البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D9%88%D9%85%D8%AA%D8%B7%D9%84%D8%A8%D8%A7%D8%AA-%D8%AA%D8%B9%D9%84%D9%85%D9%87%D8%A7%D8%9F-r1279/" rel="">ما هي البرمجة ومتطلبات تعلمها؟</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1384</guid><pubDate>Sun, 28 Nov 2021 16:01:00 +0000</pubDate></item><item><title>&#x62A;&#x646;&#x641;&#x64A;&#x630; &#x623;&#x633;&#x644;&#x648;&#x628; &#x627;&#x644;&#x628;&#x62D;&#x62B; &#x628;&#x627;&#x644;&#x639;&#x645;&#x642; &#x623;&#x648;&#x644;&#x627; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x627;&#x644;&#x648;&#x627;&#x62C;&#x647;&#x62A;&#x64A;&#x646; Iterables &#x648;Iterators</title><link>https://academy.hsoub.com/programming/advanced/%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A3%D8%B3%D9%84%D9%88%D8%A8-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D8%A8%D8%A7%D9%84%D8%B9%D9%85%D9%82-%D8%A3%D9%88%D9%84%D8%A7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%AA%D9%8A%D9%86-iterables-%D9%88iterators-r1383/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_11/61a14e9c54135_-------Iterables--Iterators.png.62f146cb7054050ae72e4d9944d87756.png" /></p>
<p>
	سنبني في هذه المقالة زاحفَ إنترنت crawler يختبر صحة فرضيّة "الطريق إلى مقالة الفلسفة" في موقع ويكيبيديا التي شرحنا معناها في مقالة تنفيذ أسلوب "البحث بالعمق أولًا" تعاوديًا وتكراريًا.
</p>

<h2>
	البداية
</h2>

<p>
	ستجد في <a href="https://github.com/AllenDowney/ThinkDataStructures" rel="external nofollow">مستودع الكتاب</a> ملفات الشيفرة التالية التي ستساعدك على بدء العمل:
</p>

<ol>
	<li>
		<code>WikiNodeExample.java</code>: يحتوي على شيفرة التنفيذ التعاودي recursive والتكراري iterative لتقنية البحث بالعمق أولًا depth-first search.
	</li>
	<li>
		<code>WikiNodeIterable.java</code>: يحتوي على صنف ممتدٍّ من النوع <code>Iterable</code> بإمكانه المرور عبر شجرة DOM.
	</li>
	<li>
		<code>WikiFetcher.java</code>: يحتوي على صنفٍ يُعرِّف أداةً تَستخدِم مكتبة jsoup لتحميل الصفحات من موقع ويكيبيديا. ويضع الصنف حدًّا لسرعة تحميل الصفحات امتثالًا لشروط الخدمة في موقع ويكيبيديا، فإذا طلبت أكثر من صفحة في الثانية الواحدة، فإنه ينتظر قليلًا قبل أن يُحمِّل الصفحة التالية.
	</li>
	<li>
		<code>WikiPhilosophy.java</code>: يحتوي على تصوّرٍ مبدئيٍّ عن الشيفرة التي ينبغي أن تكملها في هذا التمرين، وسنناقشها في الأسفل.
	</li>
</ol>

<p>
	ستجد أيضًا ملف البناء <code>build.xml</code>، حيث ستَعمَل الشيفرة المبدئية إذا نفَّذت الأمر <code>ant WikiPhilosophy</code>.
</p>

<h2>
	الواجهتان Iterables وIterators
</h2>

<p>
	تناولنا في مقالة أسلوب "البحث بالعمق أولًا" تنفيذًا تكراريًا له، وذكرنا وجه تفضيله على التنفيذ التعاودي من جهة سهولة تضمينه في كائنٍ من النوع <code>Iterator</code>. سنناقش في هذا المقال طريقة القيام بذلك.
</p>

<p>
	يُمكِنك القراءة عن الواجهتين <a href="http://thinkdast.com/iterator" rel="external nofollow"><code>Iterator</code></a> و<a href="http://thinkdast.com/iterable" rel="external nofollow"><code>Iterable</code></a> إذا لم تكن على معرفة بهما.
</p>

<p>
	ألقِ نظرةً على محتويات الملف <code>WikiNodeIterable.java</code>. يُنفِّذ الصنف الخارجيُّ <code>WikiNodeIterable</code> الواجهة <code>Iterable&lt;Node&gt;‎</code>، ولذا يُمكِننا أن نَستخدِمه ضمن حلقة تكرار loop على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7527_10" style=""><span class="pln">    </span><span class="typ">Node</span><span class="pln"> root </span><span class="pun">=</span><span class="pln"> </span><span class="pun">...</span><span class="pln">
    </span><span class="typ">Iterable</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;</span><span class="pln"> iter </span><span class="pun">=</span><span class="pln"> new </span><span class="typ">WikiNodeIterable</span><span class="pun">(</span><span class="pln">root</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Node</span><span class="pln"> node</span><span class="pun">:</span><span class="pln"> iter</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        visit</span><span class="pun">(</span><span class="pln">node</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	يشير <code>root</code> إلى جذر الشجرة التي ننوي اجتيازها، بينما يُمثِل <code>visit</code> التابع الذي نرغب في تطبيقه عند مرورنا بعقدةٍ ما.
</p>

<p>
	يَتبِع التنفيذ <code>WikiNodeIterable</code> المعادلة التقليدية:
</p>

<ol>
	<li>
		يَستقبِل الباني constructor مرجعًا إلى عقدة الجذر.
	</li>
	<li>
		يُنشِئ التابع <code>iterator</code> كائنًا من النوع <code>Iterator</code> ويعيده.
	</li>
</ol>

<p>
	انظر إلى شيفرة الصنف:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7527_12" style=""><span class="pln">public </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">WikiNodeIterable</span><span class="pln"> implements </span><span class="typ">Iterable</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    private </span><span class="typ">Node</span><span class="pln"> root</span><span class="pun">;</span><span class="pln">

    public </span><span class="typ">WikiNodeIterable</span><span class="pun">(</span><span class="typ">Node</span><span class="pln"> root</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        this</span><span class="pun">.</span><span class="pln">root </span><span class="pun">=</span><span class="pln"> root</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="lit">@Override</span><span class="pln">
    public </span><span class="typ">Iterator</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;</span><span class="pln"> iterator</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> new </span><span class="typ">WikiNodeIterator</span><span class="pun">(</span><span class="pln">root</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	في المقابل، يُنجِز الصنف الداخلي <code>WikiNodeIterator</code> العمل الفعلي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_7527_14" style=""><span class="pln">    private </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">WikiNodeIterator</span><span class="pln"> implements </span><span class="typ">Iterator</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="typ">Deque</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;</span><span class="pln"> stack</span><span class="pun">;</span><span class="pln">

        public </span><span class="typ">WikiNodeIterator</span><span class="pun">(</span><span class="typ">Node</span><span class="pln"> node</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            stack </span><span class="pun">=</span><span class="pln"> new </span><span class="typ">ArrayDeque</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;();</span><span class="pln">
            stack</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">root</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="lit">@Override</span><span class="pln">
        public boolean hasNext</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">!</span><span class="pln">stack</span><span class="pun">.</span><span class="pln">isEmpty</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">

        </span><span class="lit">@Override</span><span class="pln">
        public </span><span class="typ">Node</span><span class="pln"> next</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">stack</span><span class="pun">.</span><span class="pln">isEmpty</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                throw new </span><span class="typ">NoSuchElementException</span><span class="pun">();</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

            </span><span class="typ">Node</span><span class="pln"> node </span><span class="pun">=</span><span class="pln"> stack</span><span class="pun">.</span><span class="pln">pop</span><span class="pun">();</span><span class="pln">
            </span><span class="typ">List</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;</span><span class="pln"> nodes </span><span class="pun">=</span><span class="pln"> new </span><span class="typ">ArrayList</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;(</span><span class="pln">node</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">());</span><span class="pln">
            </span><span class="typ">Collections</span><span class="pun">.</span><span class="pln">reverse</span><span class="pun">(</span><span class="pln">nodes</span><span class="pun">);</span><span class="pln">
            </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Node</span><span class="pln"> child</span><span class="pun">:</span><span class="pln"> nodes</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                stack</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">child</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> node</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	تتطابق الشيفرة السابقة مع التنفيذ التكراري لأسلوب "البحث بالعمق أولًا" إلى حد كبير، ولكنّها مُقسَّمة الآن على ثلاثة توابع:
</p>

<ol>
	<li>
		يُهيئ الباني المكدس stack (المُنفَّذ باستخدام كائن من النوع <code>ArrayDeque</code>)، ويُضيف إليه عقدة الجذر.
	</li>
	<li>
		<code>isEmpty</code>: يفحص ما إذا كان المكدس فارغًا.
	</li>
	<li>
		<code>next</code>: يَسحَب العقدة التالية من المكدّس، ويضيف أبناءها بترتيبٍ معاكسٍ إلى المكدّس، ثم يعيد العقدة التي سحبها. وفي حال استدعاء التابع <code>next</code> في كائن <code>Iterator</code> فارغٍ، فإنه يُبلِّغ عن اعتراض exception.
	</li>
</ol>

<p>
	ربما تعتقد أن إعادة كتابة تابع جيد فعليًا باستخدام صنفين، وأن خمسة توابع تُعَد فكرةً غير جديرة بالاهتمام. ولكننا وقد فعلنا ذلك الآن، أصبح بإمكاننا أن نَستخدِم الصنف <code>WikiNodeIterable</code> في أي مكانٍ يُمكِننا فيه استخدام النوع <code>Iterable</code>. يُسهِّل ذلك من الفصل بين منطق التنفيذ التكراري (البحث بالعمق أولًا) وبين المعالجة التي نريد إجراءها على العقد.
</p>

<h2>
	الصنف WikiFetcher
</h2>

<p>
	يستطيع زاحف الويب أن يُحمِّل صفحاتٍ كثيرةً بسرعةٍ فائقةٍ، مما قد يؤدي إلى انتهاك شروط الخدمة للخادم الذي يُحمِّل منه تلك الصفحات. ولكي نتجنَّب ذلك، وفَّرنا الصنف <code>WikiFetcher</code> الذي يقوم بما يلي:
</p>

<ol>
	<li>
		يُغلِّف الشيفرة التي تناولناها بمقالة "البحث بالعمق أولًا"، أي تلك التي تُحمِّل الصفحات من موقع ويكيبيديا، وتُحلِّل <a href="https://wiki.hsoub.com/HTML" rel="external">HTML</a>، وتختار المحتوى النصي.
	</li>
	<li>
		يقيس الزمن المُنقضِي بين طلبات الاتصال، فإذا لم يَكن كافيًا، فإنه ينتظر حتى تمرّ فترةٌ معقولة. وقد ضبطنا تلك الفترة لتكون ثانيةً واحدةً بشكلٍ افتراضيّ.
	</li>
</ol>

<p>
	انظر فيما يلي إلى تعريف الصنف <code>WikiFetcher</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7527_16" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">WikiFetcher</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> lastRequestTime </span><span class="pun">=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">long</span><span class="pln"> minInterval </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">;</span><span class="pln">

    </span><span class="com">/**
     * حمِّل صفحة محدد موارد موحد وحللها
     * أعد قائمة تحتوي على عناصر تُمثِل الفقرات
     *
     * @param url
     * @return
     * @throws IOException
     */</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Elements</span><span class="pln"> fetchWikipedia</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> url</span><span class="pun">)</span><span class="pln"> throws </span><span class="typ">IOException</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        sleepIfNeeded</span><span class="pun">();</span><span class="pln">

        </span><span class="typ">Connection</span><span class="pln"> conn </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Jsoup</span><span class="pun">.</span><span class="pln">connect</span><span class="pun">(</span><span class="pln">url</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">Document</span><span class="pln"> doc </span><span class="pun">=</span><span class="pln"> conn</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">();</span><span class="pln">
        </span><span class="typ">Element</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> doc</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"mw-content-text"</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">Elements</span><span class="pln"> paragraphs </span><span class="pun">=</span><span class="pln"> content</span><span class="pun">.</span><span class="pln">select</span><span class="pun">(</span><span class="str">"p"</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> paragraphs</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> sleepIfNeeded</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">lastRequestTime </span><span class="pun">!=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">long</span><span class="pln"> currentTime </span><span class="pun">=</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="pln">currentTimeMillis</span><span class="pun">();</span><span class="pln">
            </span><span class="kwd">long</span><span class="pln"> nextRequestTime </span><span class="pun">=</span><span class="pln"> lastRequestTime </span><span class="pun">+</span><span class="pln"> minInterval</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">currentTime </span><span class="pun">&lt;</span><span class="pln"> nextRequestTime</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">try</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="typ">Thread</span><span class="pun">.</span><span class="pln">sleep</span><span class="pun">(</span><span class="pln">nextRequestTime </span><span class="pun">-</span><span class="pln"> currentTime</span><span class="pun">);</span><span class="pln">
                </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">catch</span><span class="pln"> </span><span class="pun">(</span><span class="typ">InterruptedException</span><span class="pln"> e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="typ">System</span><span class="pun">.</span><span class="pln">err</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">
                        </span><span class="str">"Warning: sleep interrupted in fetchWikipedia."</span><span class="pun">);</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        lastRequestTime </span><span class="pun">=</span><span class="pln"> </span><span class="typ">System</span><span class="pun">.</span><span class="pln">currentTimeMillis</span><span class="pun">();</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُعدّ <code>fetchWikipedia</code> هو التابع الوحيد المُعرَّف باستخدام المُعدِّل public ضمن ذلك الصنف. يَستقبِل هذا التابع سلسلةً نصيّةً من النوع <code>String</code> وتُمثِل مُحدّد موارد موحّدًا URL، ويعيد تجميعةً من النوع التي <code>Elements</code> تحتوي على عنصر DOM لكل فقرةٍ ضمن المحتوى النصيّ. يُفترَض أن تكون تلك الشيفرة مألوفةً بالنسبة لك.
</p>

<p>
	تقع الشيفرة الجديدة ضمن التابع <code>sleepIfNeeded</code> الذي يفحص الزمنَ المنقضيَ منذ آخر طلبٍ، وينتظر إذا كان الزمن أقلّ من القيمة الدنيا <code>minInterval</code> والمقدّرة بوحدة الميلي ثانية.
</p>

<p>
	هذا هو كل ما يفعله الصنف <code>WikiFetcher</code>. وتُوضِّح الشيفرة التالية طريقة استخدامه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7527_21" style=""><span class="pln">    </span><span class="typ">WikiFetcher</span><span class="pln"> wf </span><span class="pun">=</span><span class="pln"> new </span><span class="typ">WikiFetcher</span><span class="pun">();</span><span class="pln">

    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">String</span><span class="pln"> url</span><span class="pun">:</span><span class="pln"> urlList</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Elements</span><span class="pln"> paragraphs </span><span class="pun">=</span><span class="pln"> wf</span><span class="pun">.</span><span class="pln">fetchWikipedia</span><span class="pun">(</span><span class="pln">url</span><span class="pun">);</span><span class="pln">
        processParagraphs</span><span class="pun">(</span><span class="pln">paragraphs</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	افترضنا في هذا المثال أن <code>urlList</code> عبارة عن تجميعة تحتوي على سلاسلَ نصيّة من النوع <code>String</code> وأن التابع <code>processParagraphs</code> يُعالِج بطريقةٍ ما كائن الصنف <code>Elements</code> الذي أعاده التابع <code>fetchWikipedia</code>.
</p>

<p>
	يُوضِّح هذا المثال شيئًا مهمًا، حيث ينبغي أن تُنشِئ كائنًا واحدًا فقط من النوع <code>WikiFetcher</code> وأن تَستخدِمه لمعالجة جميع الطلبات؛ فلو كانت لديك عدة نسخ instances من الصنف <code>WikiFetcher</code>، فإنها لن تتمكَّن من فرض الزمن الأدنى اللازم بين كل طلب والطلب الذي يليه.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<strong>ملحوظة</strong>: تنفيذنا للصنف <code>WikiFetcher</code> بسيطٌ للغاية، ولكن من السهل إساءة استخدامه بإنشاء عدة نسخٍ منه. يُمكِنك أن تتجنب تلك المشكلة بجعل الصنف <code>WikiFetcher</code> <a href="http://thinkdast.com/singleton" rel="external nofollow">مُتفرِّدًا singleton</a>.
	</p>
</blockquote>

<h2>
	تمرين 5
</h2>

<p>
	ستجد في الملف <code>WikiPhilosophy.java</code> تابع <code>main</code> بسيطًا يُوضِّح طريقة استخدام أجزاءٍ من تلك الشيفرة. وبدءًا منه، ستكون وظيفتك هي كتابةُ زاحفٍ يقوم بما يلي:
</p>

<ol>
	<li>
		يَستقبِل مُحدّد موارد موحّدًا <a href="https://academy.hsoub.com/marketing/performance-marketing/analytics/%D8%A8%D9%86%D9%8A%D8%A9-%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-url-%D9%88%D8%A3%D9%87%D9%85%D9%8A%D8%AA%D9%87%D8%A7-%D9%81%D9%8A-%D8%B9%D9%85%D9%84%D9%8A%D8%A9-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%8A%D8%A7%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%88%D9%82%D8%B9-r159/" rel="">URL</a> لصفحةٍ من موقع ويكيبيديا، ويُحمِّلها ويُحلِّلها.
	</li>
	<li>
		يجتاز شجرة DOM الناتجة ويعثر على أول رابطٍ صالحٍ. وسنشرح المقصود بكلمة "صالح" في الأسفل.
	</li>
	<li>
		إذا لم تحتوِ الصفحة على أية روابطَ أو كنا قد زرنا أوّل رابطٍ من قبل، فعندئذٍ ينبغي أن ينتهي البرنامج مشيرًا إلى فشله.
	</li>
	<li>
		إذا كان مُحدّد الموارد الموحد يشير إلى مقالة ويكيبيديا عن الفلسفة، فينبغي أن ينتهي البرنامج مشيرًا إلى نجاحه.
	</li>
	<li>
		وفيما عدا ذلك، يعود إلى الخطوة رقم 1.
	</li>
</ol>

<p>
	ينبغي أن يُنشِئ البرنامج قائمةً من النوع <code>List</code> تحتوي على جميع مُحدّدات الموارد التي زارها، ويَعرِض النتائج عند انتهائه، سواءٌ أكانت النتيجة الفشل أم النجاح.
</p>

<p>
	والآن، ما الذي نعنيه برابط "صالح"؟ في الحقيقة لدينا بعض الخيارات، إذ تَستخدِم النسخ المختلفة من نظرية "الوصول إلى مقالة ويكيبيديا عن الفلسفة" قواعدَ مختلفةً نَستعرِض بعضًا منها هنا:
</p>

<ol>
	<li>
		ينبغي أن يكون الرابط ضمن المحتوى النصي للصفحة وليس في شريط التنقل الجانبي أو خارجَ الصندوق.
	</li>
	<li>
		لا ينبغي أن يكون الرابطُ مكتوبًا بخطٍّ مائلٍ أو بين أقواس.
	</li>
	<li>
		ينبغي أن تتجاهل الروابط الخارجيّة والروابط التي تشير إلى الصفحة الحالية والروابط الحمراء.
	</li>
	<li>
		ينبغي أن تتجاهل الرابط إذا كان بادئًا بحرفٍ كبير.
	</li>
</ol>

<p>
	ليس من الضروري أن تتقيد بكل تلك القواعد، ولكن يُمكِنك على الأقل معالجة الأقواس والخطوط المائلة والروابط التي تشير إلى الصفحة الحالية.
</p>

<p>
	إذا كنت تظن أن لديك المعلومات الكافية لتبدأ، فابدأ الآن، ولكن لا بأس قبل ذلك بقراءة التلميحات التالية:
</p>

<ol>
	<li>
		ستحتاج إلى معالجة نوعين من العقد بينما تجتاز الشجرة، هما الصنفان <code>TextNode</code> و<code>Element</code>. إذا قابلت كائنًا من النوع <code>Element</code>، فلربما قد تضطّر إلى تحويل نوعه typecast لكي تتمكَّن من استرجاع الوسم وغيره من المعلومات.
	</li>
	<li>
		عندما تقابل كائنًا من النوع <code>Element</code> يحتوي على رابط، فعندها يُمكِنك اختبار ما إذا كان مكتوبًا بخطٍ مائلٍ باتباع روابط عقد الأب أعلى الشجرة، فإذا وجدت بينها الوسم <code>&lt;i&gt;</code> أو الوسم <code>&lt;em&gt;</code>، فهذا يَعني أن الرابط مكتوبٌ بخطٍّ مائل.
	</li>
	<li>
		لكي تفحص ما إذا كان الرابط مكتوبًا بين أقواس، ستضطّر إلى فحص النص أثناء اجتياز الشجرة لكي تتعقب أقواس الفتح والغلق (سيكون مثاليًا لو استطاع الحل الخاص بك معالجة الأقواس المتداخلة (مثل تلك)).
	</li>
	<li>
		إذا بدأت من مقالة ويكيبيديا عن جافا، فينبغي أن تصل إلى مقالة الفلسفة بعد اتباع 7 روابط لو لم يحدث تغيير في صفحات ويكيبيديا منذ لحظة بدئنا بتشغيل الشيفرة.
	</li>
</ol>

<p>
	الآن وقد حصلت على كل المساعدة الممكنة، يُمكِنك أن تبدأ في العمل.
</p>

<p>
	ترجمة -بتصرّف- للفصل <a href="https://greenteapress.com/thinkdast/html/thinkdast008.html" rel="external nofollow">Chapter 7: Getting to Philosophy</a> من كتاب <a href="https://greenteapress.com/thinkdast/html/index.html" rel="external nofollow">Think Data Structures: Algorithms and Information Retrieval in Java</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AE%D8%B1%D9%8A%D8%B7%D8%A9-%D9%88%D9%85%D8%AC%D9%85%D9%88%D8%B9%D8%A9-%D9%84%D8%A8%D9%86%D8%A7%D8%A1-%D9%85%D9%81%D9%87%D8%B1%D8%B3-indexer-r1384/" rel="">استخدام خريطة ومجموعة لبناء مفهرس Indexer</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A3%D8%B3%D9%84%D9%88%D8%A8-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D8%A8%D8%A7%D9%84%D8%B9%D9%85%D9%82-%D8%A3%D9%88%D9%84%D8%A7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B7%D8%B1%D9%8A%D9%82%D8%AA%D9%8A-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF-%D9%88%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1377/" rel="">تنفيذ أسلوب البحث بالعمق أولا باستخدام طريقتي التعاود والتكرار في جافا</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF-recursion-%D9%88%D8%A7%D9%84%D9%85%D9%83%D8%AF%D8%B3-stack-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r870/" rel="">التعاود recursion والمكدس stack في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/java/%D8%B7%D8%B1%D9%8A%D9%82%D8%A9-%D8%B9%D9%85%D9%84-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-r1344/" rel="">طريقة عمل الواجهات في لغة جافا</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1383</guid><pubDate>Sun, 21 Nov 2021 16:00:00 +0000</pubDate></item><item><title>&#x62A;&#x646;&#x641;&#x64A;&#x630; &#x623;&#x633;&#x644;&#x648;&#x628; &#x627;&#x644;&#x628;&#x62D;&#x62B; &#x628;&#x627;&#x644;&#x639;&#x645;&#x642; &#x623;&#x648;&#x644;&#x627; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x637;&#x631;&#x64A;&#x642;&#x62A;&#x64A; &#x627;&#x644;&#x62A;&#x639;&#x627;&#x648;&#x62F; &#x648;&#x627;&#x644;&#x62A;&#x643;&#x631;&#x627;&#x631; &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;</title><link>https://academy.hsoub.com/programming/advanced/%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A3%D8%B3%D9%84%D9%88%D8%A8-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D8%A8%D8%A7%D9%84%D8%B9%D9%85%D9%82-%D8%A3%D9%88%D9%84%D8%A7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B7%D8%B1%D9%8A%D9%82%D8%AA%D9%8A-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF-%D9%88%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1377/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_11/619d54cae7f26_------.png.094a0699a6d35283851ce0eaca84de8d.png" /></p>
<p>
	سنتناول في هذه المقالة مقدمةً سريعةً عن تطبيق محرك البحث الذي ننوي بناءه، حيث سنَصِف مكوِّناته ونشرح أُولاها، وهي عبارة عن زاحف ويب crawler يُحمِّل صفحات موقع ويكيبيديا ويُحلِّلها. سنتناول أيضًا تنفيذًا تعاوديًا recursive لأسلوب البحث بالعمق أولًا depth-first وكذلك تنفيذًا تكراريًا للمُكدِّس stack (الداخل آخرًا، يخرج أولًا LIFO) باستخدام <code>Deque</code>.
</p>

<h2>
	محركات البحث
</h2>

<p>
	تستقبل محركات البحث -مثل محرك جوجل وبينغ- مجموعةً من كلمات البحث، وتعيد قائمةً بصفحات الإنترنت المرتبطة بتلك الكلمات (سنناقش ما تعنيه كلمة مرتبطة لاحقًا). يُمكِنك قراءة المزيد عن <a href="https://academy.hsoub.com/marketing/search-engine-optimisation/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%B9%D9%85%D9%84-%D9%85%D8%AD%D8%B1%D9%83%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D9%88%D8%AA%D8%B1%D8%AA%D9%8A%D8%A8-%D8%AC%D9%88%D8%AC%D9%84-%D9%84%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%85%D9%88%D9%82%D8%B9-%D8%A7%D9%84%D8%A5%D9%84%D9%83%D8%AA%D8%B1%D9%88%D9%86%D9%8A-r491/" rel="">محركات البحث</a>، ولكننا سنشرح هنا كل ما قد تحتاج إليه.
</p>

<p>
	يتكوّن أي محرك بحث من عدة مكوناتٍ أساسيةٍ نستعرضها فيما يلي:
</p>

<ul>
	<li>
		الزحف crawling: برنامج بإمكانه تحميل صفحة إنترنت وتحليلها واستخراج النص وأي روابط إلى صفحات أخرى.
	</li>
	<li>
		الفهرسة indexing: هيكل بيانات data structure بإمكانه البحث عن كلمةٍ والعثور على الصفحات التي تحتوي على تلك الكلمة.
	</li>
	<li>
		الاسترجاع retrieval: طريقة لتجميع نتائج المُفهرِس واختيار الصفحات الأكثر صلةً بكلمات البحث.
	</li>
</ul>

<p>
	سنبدأ بالزاحف، والذي تتلخص مهمته في اكتشاف مجموعة من <a href="https://academy.hsoub.com/programming/html/%D8%A7%D9%84%D8%AA%D8%AD%D9%82%D9%82-%D9%85%D9%86-%D8%B3%D9%87%D9%88%D9%84%D8%A9-%D8%A7%D9%84%D9%88%D8%B5%D9%88%D9%84-%D9%84%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r1328/" rel="">صفحات الويب</a> وتحميلها، في حين تهدف محركات البحث مثل جوجل وبينغ إلى العثور على جميع صفحات الإنترنت، لكن المعتاد أيضًا أن يكون الزاحف مقتصرًا على نطاق أصغر. وفي حالتنا هذه، سنقتصر على صفحات موقع ويكيبيديا فقط.
</p>

<p>
	في البداية، سنبني زاحفًا يقرأ صفحةً من موقع ويكيبيديا، ويبحث عن أول رابطٍ ضمن الصفحة، وينتقل إلى الصفحة التي يشير إليها الرابط، ثم يكرر الأمر. سنَستخدِم ذلك الزاحف لاختبار صحة فرضيّة فرضيّة الطريق إلى الفلسفة، الموجودة في صفحات ويكيبيديا والتي تنصّ على ما يلي:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		إذا نقرت على أول رابطٍ مكتوبٍ بأحرفٍ صغيرةٍ في أي مقالةٍ في موقع ويكيبيديا، وكرَّرت ذلك على المقالات التالية، فسينتهي بك المطاف إلى مقالة الفلسفة في موقع ويكيبيديا.
	</p>
</blockquote>

<p>
	سيسمح لنا اختبار تلك الفرضيّة ببناء القطع الأساسية للزاحف بدون الحاجة إلى الزحف عبر الإنترنت بأكمله أو حتى عبر كل صفحات موقع ويكيبيديا، كما أن هذا التمرين ممتعٌ نوعًا ما.
</p>

<p>
	أمّا المُفهرس والمُسترجِع فسنبني كلًّا منهما في مقال مستقلّ لاحقًا.
</p>

<h2>
	تحليل مستند HTML
</h2>

<p>
	عندما تُحمِّل صفحة إنترنت، فإن محتوياتها تكون مكتوبةً <a href="https://wiki.hsoub.com/HTML" rel="external">بلغة ترميز النص الفائق</a> HyperText Markup Language، التي تُختصَر عادةً إلى <a href="https://academy.hsoub.com/programming/html/" rel="">HTML</a>. على سبيل المثال، انظر إلى مستند HTML التالي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_5657_14" style=""><span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln">
</span><span class="tag">&lt;html&gt;</span><span class="pln">
  </span><span class="tag">&lt;head&gt;</span><span class="pln">
    </span><span class="tag">&lt;title&gt;</span><span class="pln">This is a title</span><span class="tag">&lt;/title&gt;</span><span class="pln">
  </span><span class="tag">&lt;/head&gt;</span><span class="pln">
  </span><span class="tag">&lt;body&gt;</span><span class="pln">
    </span><span class="tag">&lt;p&gt;</span><span class="pln">Hello world!</span><span class="tag">&lt;/p&gt;</span><span class="pln">
  </span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

<p>
	تُمثِّل العبارات "This is a title" و"Hello world!‎" النصَّ الفعليَّ المعروض في الصفحة، أما بقية العناصر فهي عبارة عن وسوم tags تشير إلى الكيفية التي ستُعرَض بها تلك النصوص.
</p>

<p>
	بعد أن يُحمِّل الزاحف صفحة إنترنت، يُحلِّل محتوياتها المكتوبة بلغة HTML ليتمكَّن من استخراج النص وإيجاد الروابط. سنَستخدِم مكتبة jsoup مفتوحة المصدر من <a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D9%84%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-java-r599/" rel="">لغة جافا</a> لإجراء ذلك، حيث تستطيع تلك المكتبة تحميل صفحات HTML وتحليلها.
</p>

<p>
	ينتج عن تحليل مستندات HTML شجرة نموذج كائن المستند Document Object Model التي تُختصرُ إلى <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-dom-r644/" rel="">DOM</a>، حيث تحتوي تلك الشجرة على ما يتضمنه المستند من عناصر بما في ذلك النصوص والوسوم، تمثِّل هيكل بياناتٍ مترابطًا linked يتألف من عقد nodes تُمثِّلُ كلًا من النصوص والوسوم والعناصر الأخرى.
</p>

<p>
	تُحدِّد بنية المستند العلاقات بين العقد. يُعدّ الوسم <code>&lt;html&gt;</code> -في المثال المُوضَّح في الأعلى مثلًا، العقدة الأولى التي يُطلَق عليها اسم الجذر root، وتحتوي تلك العقدة على روابط تشير إلى العقد التي تتضمنها وفي حالتنا هما العقدتان <code>&lt;head&gt;</code> و<code>&lt;body&gt;</code>، وتُعدّ كلٌّ منهما ابنًا للعقدة الجذر.
</p>

<p>
	تملك العقدة <code>&lt;head&gt;</code> ابنًا واحدًا هو العقدة <code>&lt;title&gt;</code>، وبالمثل، تملك العقدة <code>&lt;body&gt;</code> ابنًا واحدًا هو العقدة <code>&lt;p&gt;</code> (اختصارًا لكلمة paragraph). تُوضِّح الصورة التالية تلك الشجرة بيانيًا.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="83282" href="https://academy.hsoub.com/uploads/monthly_2021_11/001HTML_DOM.PNG.a09b76b6dbc0fef215279f29468862f9.PNG" rel="" data-fileext="PNG"><img alt="001HTML_DOM.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="83282" data-unique="3efo3tde7" src="https://academy.hsoub.com/uploads/monthly_2021_11/001HTML_DOM.PNG.a09b76b6dbc0fef215279f29468862f9.PNG"></a>
</p>

<p>
	تحتوي كلّ عقدة على روابط إلى عقد الأبناء، كما تحتوي على رابط إلى عقدة الأب الخاصة بها، وبالتالي يُمكِننا أن نبدأ من أي عقدة في الشجرة، ثم نتنقّل إلى أعلاها أو أسفلها. عادةً ما تكون<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%A8%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%B4%D8%AC%D8%B1%D9%8A%D8%A9-%D9%84%D9%80-dom-r646/" rel=""> أشجار DOM</a> المُمثِلة للصفحات الحقيقية أعقدَ بكثيرٍ من هذا المثال.
</p>

<p>
	تُوفِّر غالبية متصفحات الإنترنت أدوات للتحقّق من نموذج DOM الخاص بالصفحة المعروضة. ففي متصفح كروم مثلًا، يُمكِنك النقر بزر الفأرة الأيمن على أي مكان من الصفحة، واختيار "Inspect" من القائمة؛ أما في متصفح فايرفوكس، فيُمكِنك أيضًا النقر بزر الفأرة الأيمن على أي مكان، واختيار "Inspect Element" من القائمة. يُمكِنك القراءة عن <a href="http://thinkdast.com/safari" rel="external nofollow">أداة Web Inspector</a> التي يُوفِّرها متصفح سفاري أو قراءة التعليمات الخاصة بمتصفح <a href="http://thinkdast.com/explorer" rel="external nofollow">إنترنت إكسبلورر</a>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="83283" href="https://academy.hsoub.com/uploads/monthly_2021_11/002Chrome_Inspector.PNG.ddb2366d06f06bd1941f61ec3d16082f.PNG" rel="" data-fileext="PNG"><img alt="002Chrome_Inspector.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="83283" data-unique="6b0rlud4o" src="https://academy.hsoub.com/uploads/monthly_2021_11/002Chrome_Inspector.PNG.ddb2366d06f06bd1941f61ec3d16082f.PNG"></a>
</p>

<p>
	تعرض الصورة السابقة لقطة شاشة لنموذج DOM الخاص بـ<a href="http://thinkdast.com/java" rel="external nofollow">مقالة ويكيبيديا عن لغة جافا</a>، حيث يُمثِّلُ العنصر المظلل أول فقرة في النص الرئيسي من المقالة. لاحِظ أن الفقرة تقع داخل عنصر <code>&lt;div&gt;</code> الذي يملك السمة <code>id="mw-content-text"</code>، والتي سنَستخدِمها للعثور على النص الرئيسي في أي مقالةٍ نُحمِّلها.
</p>

<h2>
	استخدام مكتبة jsoup
</h2>

<p>
	تُسهِّل مكتبة jsoup من تحميل صفحات الإنترنت وتحليلها، وكذلك التنقُل عبر شجرة DOM. انظر إلى المثال التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5657_23" style=""><span class="pln">    </span><span class="typ">String</span><span class="pln"> url </span><span class="pun">=</span><span class="pln"> </span><span class="str">"http://en.wikipedia.org/wiki/Java_(programming_language)"</span><span class="pun">;</span><span class="pln">

    </span><span class="com">// حمِّل المستند وحلّله</span><span class="pln">
    </span><span class="typ">Connection</span><span class="pln"> conn </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Jsoup</span><span class="pun">.</span><span class="pln">connect</span><span class="pun">(</span><span class="pln">url</span><span class="pun">);</span><span class="pln">
    </span><span class="typ">Document</span><span class="pln"> doc </span><span class="pun">=</span><span class="pln"> conn</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">();</span><span class="pln">

    </span><span class="com">// اختر المحتوى النصي واسترجع الفقرات</span><span class="pln">
    </span><span class="typ">Element</span><span class="pln"> content </span><span class="pun">=</span><span class="pln"> doc</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"mw-content-text"</span><span class="pun">);</span><span class="pln">
    </span><span class="typ">Elements</span><span class="pln"> paragraphs </span><span class="pun">=</span><span class="pln"> content</span><span class="pun">.</span><span class="pln">select</span><span class="pun">(</span><span class="str">"p"</span><span class="pun">);</span></pre>

<p>
	يَستقبِل التابع <code>Jsoup.connect</code> مُحدِّد موارد موحدًا URL من النوع <code>String</code>، ويُنشِئ اتصالًا مع خادم الويب. بعد ذلك يُحمِّل التابع <code>get</code> مستند HTML ويُحلِّله، ويعيد كائنًا من النوع <code>Document</code> يُمثِل شجرة DOM.
</p>

<p>
	يُوفِّر الصنف <code>Document</code> توابعًا للتنقل عبر الشجرة واختيار العقد. في الواقع، إنه يُوفِّر توابع كثيرةً جدًا لدرجة تُصيبَك بالحيرة. وسيَعرِض المثال التالي طريقتين لاختيار العقد:
</p>

<ul>
	<li>
		<code>getElementById</code>: يستقبِل سلسلةً نصيةً من النوع <code>String</code>، ويبحث ضمن الشجرة عن عنصرٍ يملك نفس قيمة حقل id المُمرَّرة. يختار التابع في هذا المثال العقدة <code>&lt;div id="mw-content-text" lang="en" dir="ltr" class="mw-content-ltr"‎&gt;</code> التي تَظهَر في أيّ مقالةٍ من موقع ويكيبيديا لكي تُميّز عنصر <code>&lt;div&gt;</code> المُتضمِّن للنص الرئيسي للصفحة، عن شريط التنقل الجانبي والعناصر الأخرى. يعيد التابع <code>getElementById</code> كائنًا من النوع <code>Element</code> يُمثِل عنصر <code>&lt;div&gt;</code> ذاك، ويحتوي على العناصر الموجودة داخله بهيئة أبناءٍ وأحفادٍ وغيرها.
	</li>
	<li>
		<code>select</code>: يستقبل سلسلةً نصيّةً من النوع <code>String</code>، ويتنقّل عبر الشجرة، ثم يُعيد جميع العناصر التي يتوافق الوسم tag الخاص بها مع تلك السلسلة النصية. يعيد التابع في هذا المثال جميع وسوم الفقرات الموجودة في الكائن <code>content</code>. تكون القيمة المعادة عبارة عن كائن من النوع <code>Elements</code>.
	</li>
</ul>

<p>
	قبل أن تُكمِل القراءة، يُفضَّل أن تلقي نظرةً على توثيق كلٍّ من الأصناف المذكورة لكي تتعرف على إمكانيات كلٍّ منها. تجدر الإشارة إلى أنّ الأصناف <a href="http://thinkdast.com/jsoupelt" rel="external nofollow">Element</a> و <a href="http://thinkdast.com/jsoupelts" rel="external nofollow">Elements</a> و <a href="http://thinkdast.com/jsoupnode" rel="external nofollow">Node</a> هي الأصناف الأهمّ.
</p>

<p>
	يُمثِل الصنف <code>Node</code> عقدةً في شجرة DOM. وتمتد منه أصنافٌ فرعيةٌ subclasses كثيرةٌ مثل <code>Element</code> و<code>TextNode</code> و<code>DataNode</code> و<code>Comment</code>. يُعدّ الصنف <code>Elements</code> تجميعةً من النوع <code>Collection</code> التي تحتوي على كائناتٍ من النوع <code>Element</code>.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="83281" href="https://academy.hsoub.com/uploads/monthly_2021_11/003UML_Diagram.PNG.0151da3662adc19bb23092ac899ad8df.PNG" rel="" data-fileext="PNG"><img alt="003UML_Diagram.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="83281" data-unique="w2eaimwt8" src="https://academy.hsoub.com/uploads/monthly_2021_11/003UML_Diagram.PNG.0151da3662adc19bb23092ac899ad8df.PNG"></a>
</p>

<p>
	تحتوي الصورة السابقة على مخطط UML يُوضّح العلاقة بين تلك الأصناف. يشير الخط ذو الرأس الأجوف إلى أن هناك صنفًا يمتد من صنفٍ آخر، إذ يمتد الصنف <code>Elements</code> مثلًا، من الصنف <code>ArrayList</code>. وسنعود لاحقًا للحديث عن <a href="https://academy.hsoub.com/programming/workflow/%D9%85%D8%AE%D8%B7%D8%B7%D8%A7%D8%AA-%D8%A7%D9%84%D9%81%D8%A6%D8%A7%D8%AA-class-diagram-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D9%86%D9%85%D8%B0%D8%AC%D8%A9-%D8%A7%D9%84%D9%85%D9%88%D8%AD%D8%AF%D8%A9-uml-r307/" rel="">مخططات UML</a>.
</p>

<h2>
	اجتياز شجرة DOM
</h2>

<p>
	يَسمَح لك الصنف <code>WikiNodeIterable</code> -الذي كتبه المؤلف- بالمرور عبر عقد شجرة DOM. انظر إلى المثال التالي الذي يبين طريقة استخدامه:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5657_26" style=""><span class="pln">    </span><span class="typ">Elements</span><span class="pln"> paragraphs </span><span class="pun">=</span><span class="pln"> content</span><span class="pun">.</span><span class="pln">select</span><span class="pun">(</span><span class="str">"p"</span><span class="pun">);</span><span class="pln">
    </span><span class="typ">Element</span><span class="pln"> firstPara </span><span class="pun">=</span><span class="pln"> paragraphs</span><span class="pun">.</span><span class="pln">get</span><span class="pun">(</span><span class="lit">0</span><span class="pun">);</span><span class="pln">

    </span><span class="typ">Iterable</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;</span><span class="pln"> iter </span><span class="pun">=</span><span class="pln"> new </span><span class="typ">WikiNodeIterable</span><span class="pun">(</span><span class="pln">firstPara</span><span class="pun">);</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Node</span><span class="pln"> node</span><span class="pun">:</span><span class="pln"> iter</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">node instanceof </span><span class="typ">TextNode</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">node</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	يُكمِل هذا المثال ما وصلنا إليه في المثال السابق، فهو يختار الفقرة الأولى في الكائن <code>paragraphs</code> أولًا، ثم يُنشِئ كائنًا من النوع <code>WikiNodeIterable</code> ليُنفِّذ الواجهة <code>Iterable&lt;Node&gt;‎</code>. يُجرِي <code>WikiNodeIterable</code> بحثًا بتقنية العمق أولًا depth-first، ويُولِّد العقد بنفس ترتيب ظهورها بالصفحة.
</p>

<p>
	تَطبَع الشيفرةُ العقدَ إذا كانت من النوع <code>TextNode</code> وتتجاهلها إذا كانت من أي نوع آخر، والتي تُمثِل وسومًا من الصنف <code>Element</code> في هذا المثال. ينتج عن ذلك طباعة نص الفقرة بدون أيّ ترميزات. وقد كان الخرج في هذا المثال كما يلي:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false" style="    direction: ltr;    text-align: left;">
		Java is a general-purpose computer programming language that is concurrent, class-based, object-oriented,[13] and specifically designed …
	</p>
</blockquote>

<h2>
	البحث بالعمق أولا Depth-first search
</h2>

<p>
	تتوفَّر العديد من الطرائق لاجتياز الأشجار، ويتلاءم كلٌّ منها مع أنواعٍ مختلفةٍ من التطبيقات. سنبدأ بطريقة البحث بالعمق أولًا DFS. تبدأ تلك الطريقة من جذر الشجرة، ثم تختار الابن الأول للجذر. إذا كان لديه أبناء، فإنها ستختار الابن الأول، وتستمر في ذلك حتى تصل إلى عقدةٍ ليس لها أبناء، أين تبدأ بالتراجع عندها والتحرك لأعلى إلى عقدة الأب، لتختار منها الابن التالي إن كان موجودًا، وفي حالة عدم وجوده، فإنها تتراجع للوراء مجددًا. عندما تنتهي من البحث في الابن الأخير لعقدة الجذر، فإنها تكون قد انتهت.
</p>

<p>
	هناك طريقتان شائعتان لتنفيذ DFS، وذلك إما <a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF-recursion-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1361/" rel="">بالتعاود recursion</a>، أو بالتكرار. يُعدّ <a href="https://wiki.hsoub.com/Algorithms#.D8.A7.D9.84.D8.AA.D8.B9.D8.A7.D9.88.D8.AF" rel="external">التنفيذ بالتعاود</a> هو الطريقة الأبسط:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5657_12" style=""><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> recursiveDFS</span><span class="pun">(</span><span class="typ">Node</span><span class="pln"> node</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">node instanceof </span><span class="typ">TextNode</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">node</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Node</span><span class="pln"> child</span><span class="pun">:</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        recursiveDFS</span><span class="pun">(</span><span class="pln">child</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُستدعَى التابع السابق من أجل كل عقدةٍ ضمن الشجرة بدايةً من الجذر. إذا كانت العقدة المُمرَّرة من النوع <code>TextNode</code>، ويطبع التابع محتوياتِها، ثم يفحص إذا كان للعقدة أي أبناء. فإذا كان لها أبناء، فإنه سيَستدعِي <code>recursiveDFS</code> -أي ذاته- لجميع عقد الأبناء على التوالي.
</p>

<p>
	في هذا المثال، طَبَعَنا محتويات العقد التي تنتمي إلى النوع <code>TextNode</code> قبل أن ننتقل إلى الأبناء، وهو ما يُعدّ مثالًا على الاجتياز ذي الترتيب السابق. يُمكِنك القراءة عن الاجتيازات ذات <a href="http://thinkdast.com/treetrav" rel="external nofollow">الترتيب السابق pre-order والترتيب اللاحق post-order وفي الترتيب in-order</a>. لا يُشكّل ترتيب الاجتياز في تطبيقنا هذا أي فارق.
</p>

<p>
	نظرًا لأن التابع <code>recursiveDFS</code> يَستدعِي ذاته تعاوديًا، فقد كان بإمكانه استخدام <a href="http://thinkdast.com/callstack" rel="external nofollow">مُكدِّس الاستدعاءات</a> للاحتفاظ بالعقد الأبناء، ومعالجتها بالترتيب المناسب، لكننا بدلًا من ذلك يُمكِننا أن نَستخدِم مُكدِّسًا صريحًا للاحتفاظ بالعقد، وفي تلك الحالة لن نحتاج إلى التعاود، حيث سنتمكَّن من اجتياز الشجرة عبر حلقة تكراريّة.
</p>

<h2>
	المكدسات Stacks في جافا
</h2>

<p>
	قبل أن نشرح التنفيذ التكراري لتقنية DFS، سنناقش أولًا هيكل بياناتٍ يُعرَف باسم المُكدّس. سنبدأ بالفكرة العامة للمُكدِّس، ثم سنتحدث عن واجهتين interfaces بلغة جافا تُعرِّفان توابع المُكدِّس، وهما <code>Stack</code> و<code>Deque</code>.
</p>

<p>
	يُعدّ المُكدِّس هيكل بياناتٍ مشابهًا للقائمة، فهو عبارة عن تجميعة تتذكر ترتيب العناصر. ويتمثل الفرق بين المكدّس والقائمة في أن المُكدِّس يوفِّر توابعَ أقل، وأنه عادةً ما يُوفِّر المُكدِّس التوابع التالية:
</p>

<ul>
	<li>
		<code>push</code>: يضيف عنصرًا إلى أعلى المُكدِّس.
	</li>
	<li>
		<code>pop</code>: يحذِف العنصر الموجود أعلى المُكدِّس ويعيده.
	</li>
	<li>
		<code>peek</code>: يعيد العنصر الموجود أعلى المُكدِّس دون حذفه.
	</li>
	<li>
		<code>isEmpty</code>: يشير إلى ما إذا كان المُكدِّس فارغًا.
	</li>
</ul>

<p>
	نظرًا لأن التابع <code>pop</code> يسترجع العنصر الموجود في أعلى المكدّسِ دائمًا، يُشار إلى المكدّساتِ باستخدام كلمة LIFO، والتي تُعدّ اختصارًا لعبارة "الداخل آخرًا، يخرج أولًا". في المقابل، تُعدّ الأرتال queue بديلًا للمكدّساتِ، ولكنها تُعيد العناصر بنفس ترتيب إضافتها، ولذلك، يُشار إليها عادةً باستخدام كلمة FIFO أي "الداخل أولًا، يخرج أولًا".
</p>

<p>
	قد لا تكون أهمية المُكدِّسات والأرتال واضحةً بالنسبة لك، فهما لا يوفران أي إمكانياتٍ إضافيةً عن تلك الموجودة في القوائم lists. بل يوفران إمكانيات أقل، لذلك قد تتساءل لم لا نكتفي باستخدام القوائم؟ والإجابة هي أن هناك سببان:
</p>

<ol>
	<li>
		إذا ألزمت نفسك بعدد أقل من التوابع، أي بواجهة تطوير <a href="https://academy.hsoub.com/programming/general/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A9-api-r1314/" rel="">تطبيقات <abbr title="Application Programming Interface | واجهة برمجية"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr></a> أصغر، فعادةً ما تصبح الشيفرة مقروءةً أكثر، كما تقل احتمالية احتوائها على أخطاء. على سبيل المثال، إذا استخدمت قائمةً لتمثيل مُكدِّس، فقد تَحذِف -عن طريق الخطأ- عنصرًا بترتيب خاطئ. في المقابل، إذا استخدمت واجهة تطوير التطبيقات المُخصَّصة للمُكدِّس، فسيستحيل أن تقع في مثل هذا الخطأ، ولهذا فالطريقة الأفضل لتجنُّب الأخطاء هي بأن تجعلها مستحيلة.
	</li>
	<li>
		إذا كانت واجهة تطوير التطبيقات التي يُوفِّرها هيكل البيانات صغيرةً، فسيكون تنفيذها بكفاءةٍ أسهل. على سبيل المثال، يُمكِننا أن نَستخدِم قائمةً مترابطةً linked list أحادية الترابط لتنفيذ المُكدِّس بسهولة، وعندما نضع عنصرًا في المُكدِّس، فعلينا أن نضيفه إلى بداية القائمة؛ أما عندما نسحب عنصرًا منها، فعلينا أن نَحذفه من بدايتها. ونظرًا لأن عمليتي إضافة العناصر وحذفها من بداية القوائم المترابطة تستغرق زمنًا ثابتًا، فإننا نكون قد حصلنا على تنفيذٍ ذي كفاءةٍ عالية. في المقابل، يَصعُب تنفيذ واجهات التطوير الكبيرة بكفاءة.
	</li>
</ol>

<p>
	لديك ثلاثة خيارات لتنفيذ مُكدِّسٍ <a href="https://academy.hsoub.com/programming/java/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A8%D9%84%D8%BA%D8%A9-java-%D9%85%D8%A7-%D9%87%D9%8A-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9%D8%9F-r371/" rel="">بلغة جافا</a>:
</p>

<ol>
	<li>
		اِستخدِم الصنف <code>ArrayList</code> أو الصنف <code>LinkedList</code>. إذا اِستخدَمت الصنف <code>ArrayList</code>، تأكَّد من إجراء عمليتي الإضافة والحذف من نهاية القائمة لأنهما بذلك سيستغرِقان زمنًا ثابتًا، وانتبه من إضافة العناصر في مكانٍ خاطئٍ أو تحذفها بترتيبٍ خاطئ.
	</li>
	<li>
		تُوفِّر جافا الصنف <code>Stack</code> الذي يحتوي على التوابع الأساسية للمُكدِّسات، ولكنه يُعدّ جزءًا قديمًا من لغة جافا، فهو غير متوافق مع إطار عمل جافا للتجميعات Java Collections Framework الذي أُضيفَ لاحقًا.
	</li>
	<li>
		ربما الخيار الأفضل هو استخدام إحدى تنفيذات الواجهة <code>Deque</code> مثل الصنف <code>ArrayDeque</code>.
	</li>
</ol>

<p>
	إن كلمة Deque هي اختصار للتسمية رتل ذو نهايتين double-ended queue، والتي يُفترَض أن تُلفَظ deck، ولكنها تُلفَظ أحيانًا deek. تُوفِّر واجهة <code>Deque</code> بلغة جافا التوابع <code>push</code> و<code>pop</code> و<code>peek</code> و<code>isEmpty</code>، لذلك يُمكِنك أن تَستخدِم كائنًا من النوع <code>Deque</code> كمُكدِّس، كما أنها تُوفِّر <a href="http://thinkdast.com/deque" rel="external nofollow">توابع أخرى</a> ولكننا لن نَستخدِمها حاليًا.
</p>

<h2>
	التنفيذ التكراري لتقنية البحث بالعمق أولا
</h2>

<p>
	انظر إلى التنفيذ التكراري لأسلوب "البحث بالعمق أولًا". يَستخدِم ذلك التنفيذ كائنًا من النوع <code>ArrayDeque</code> ليُمثِل مُكدِّسًا يحتوي على كائنات تنتمي إلى النوع <code>Node</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5657_32" style=""><span class="pln">    </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> iterativeDFS</span><span class="pun">(</span><span class="typ">Node</span><span class="pln"> root</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Deque</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;</span><span class="pln"> </span><span class="typ">stack</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">ArrayDeque</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;();</span><span class="pln">
        </span><span class="typ">stack</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">root</span><span class="pun">);</span><span class="pln">

        </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(!</span><span class="typ">stack</span><span class="pun">.</span><span class="pln">isEmpty</span><span class="pun">())</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Node</span><span class="pln"> node </span><span class="pun">=</span><span class="pln"> </span><span class="typ">stack</span><span class="pun">.</span><span class="pln">pop</span><span class="pun">();</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">node instanceof </span><span class="typ">TextNode</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln">node</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

            </span><span class="typ">List</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;</span><span class="pln"> nodes </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">ArrayList</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;(</span><span class="pln">node</span><span class="pun">.</span><span class="pln">childNodes</span><span class="pun">());</span><span class="pln">
            </span><span class="typ">Collections</span><span class="pun">.</span><span class="pln">reverse</span><span class="pun">(</span><span class="pln">nodes</span><span class="pun">);</span><span class="pln">

            </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Node</span><span class="pln"> child</span><span class="pun">:</span><span class="pln"> nodes</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">stack</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">child</span><span class="pun">);</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	يُمثِل المعامل <code>root</code> جذر الشجرة التي نريد أن نجتازها، حيث سنُنشِئ المُكدِّس ونضيف الجذر إليه.
</p>

<p>
	تستمر الحلقة loop بالعمل إلى أن يُصبِح المُكدِّس فارغًا. يَسحَب كل تكرار ضمن الحلقة عقدةً من المُكدِّس، فإذا كانت العقدة من النوع <code>TextNode</code>، فإنه يَطبَعُ محتوياتِها ثم يضيف أبناءها إلى المُكدِّس. ينبغي أن نضيف الأبناء إلى المُكدِّس بترتيبٍ معاكسٍ لكي نتمكَّن من معالجتها بالترتيب الصحيح، ولذلك سنَنَسخ الأبناء أولًا إلى قائمة من النوع <code>ArrayList</code>، ثم نعكس ترتيب العناصر فيها، وفي النهاية سنمرّ عبر القائمة المعكوسة.
</p>

<p>
	من السهل كتابة التنفيذ التكراري لتقنيةِ البحث بالعمق أولًا باستخدام كائن من النوع <code>Iterator</code>، وسترى ذلك في المقالة التالية.
</p>

<p>
	في ملاحظة أخيرة عن الواجهة <code>Deque</code>، بالإضافة إلى الصنف <code>ArrayDeque</code>، تُوفِّر جافا تنفيذًا آخرًا لتلك الواجهة، هو الصنف <code>LinkedList</code> الذي يُنفِّذ الواجهتين <code>List</code> و<code>Deque</code>، وتعتمد الواجهة التي تحصل عليها على الطريقة التي تَستخدِمه بها. على سبيل المثال، إذا أسندت كائنًا من النوع <code>LinkedList</code> إلى متغيرٍ من النوع <code>Deque</code> كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5657_35" style=""><span class="typ">Deqeue</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;</span><span class="pln"> deque </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">LinkedList</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;();</span></pre>

<p>
	فسيكون في إمكانك استخدام التوابع المُعرَّفة بالواجهة <code>Deque</code>، لا توابع الواجهةِ <code>List</code>. وفي المقابل، إذا أسندته إلى متغيرٍ من النوع <code>List</code>، كالتالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5657_37" style=""><span class="typ">List</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;</span><span class="pln"> deque </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">LinkedList</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;();</span></pre>

<p>
	فسيكون في إمكانك استخدام التوابع المُعرَّفة بالواجهة <code>List</code> لا توابع الواجهة <code>Deque</code>؛ أما إذا أسندته على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5657_39" style=""><span class="typ">LinkedList</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;</span><span class="pln"> deque </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">LinkedList</span><span class="pun">&lt;</span><span class="typ">Node</span><span class="pun">&gt;();</span></pre>

<p>
	فسيكون بإمكانك استخدام جميع التوابع، ولكن الذي يحدث عند دمج توابع من واجهاتٍ مختلفةٍ، هو أن الشيفرة ستصبح أصعب قراءةً وأكثر عرضةً لاحتواء الأخطاء.
</p>

<p>
	ترجمة -بتصرّف- للفصل <a href="https://greenteapress.com/thinkdast/html/thinkdast007.html" rel="external nofollow">Chapter 6: Tree traversal</a> من كتاب <a href="https://greenteapress.com/thinkdast/html/index.html" rel="external nofollow">Think Data Structures: Algorithms and Information Retrieval in Java</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي<span>: <a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A3%D8%B3%D9%84%D9%88%D8%A8-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D8%A8%D8%A7%D9%84%D8%B9%D9%85%D9%82-%D8%A3%D9%88%D9%84%D8%A7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%AA%D9%8A%D9%86-iterables-%D9%88iterators-r1383/" rel="">تنفيذ أسلوب البحث بالعمق أولا باستخدام الواجهتين Iterables وIterators</a></span>
	</li>
	<li>
		<span>المقال السابق: </span><a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D8%A7%D8%B2%D8%AF%D9%88%D8%A7%D8%AC%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B1%D8%A7%D8%A8%D8%B7-r1350/" rel="">تحليل زمن تشغيل القوائم المنفذة باستخدام قائمة ازدواجية الترابط</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF-recursion-%D9%88%D8%A7%D9%84%D9%85%D9%83%D8%AF%D8%B3-stack-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r870/" rel="">التعاود recursion والمكدس stack في جافاسكربت</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/java/%D8%B7%D8%B1%D9%8A%D9%82%D8%A9-%D8%B9%D9%85%D9%84-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-r1344/" rel="">طريقة عمل الواجهات في لغة جافا</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1377</guid><pubDate>Sun, 14 Nov 2021 16:00:00 +0000</pubDate></item><item><title>&#x62E;&#x648;&#x627;&#x631;&#x632;&#x645;&#x64A;&#x627;&#x62A; &#x62A;&#x62D;&#x644;&#x64A;&#x644; &#x627;&#x644;&#x645;&#x633;&#x627;&#x631;&#x627;&#x62A; &#x641;&#x64A; &#x627;&#x644;&#x623;&#x634;&#x62C;&#x627;&#x631;</title><link>https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1%D8%A7%D8%AA-%D9%81%D9%8A-%D8%A7%D9%84%D8%A3%D8%B4%D8%AC%D8%A7%D8%B1-r1373/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_11/6193498674903_-01.jpg.c2185806d5eab5f12900b8172677f996.jpg" /></p>
<p>
	نستعرض في هذا المقال بعض أشهر <a href="https://wiki.hsoub.com/Algorithms" rel="external">الخوارزميات </a>المستخدمة لتحليل المسارات في الأشجار، مثل خوارزمية بْرِم Prim وخوارزمية فلويد-وورشال Floyd-Warshall وخوارِزمية بلمان-فورد Bellman-Ford.
</p>

<h2>
	خوارزمية برم Prim's Algorithm
</h2>

<p>
	لنفترض أنّ لدينا 8 منازل، ونريد إعداد خطوط هاتفية بينها بأقل تكلفة ممكنة. لأجل ذلك سننشئ شجرةً حروفها تمثل المنازل، وأضلَاعها تمثّل تكلفة توصيل الخط الهاتفي بين منزلين.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82508" href="https://academy.hsoub.com/uploads/monthly_2021_11/DAoCJ.png.44e56a6f8ff26d558e62fc149533be89.png" rel="" data-fileext="png"><img alt="DAoCJ.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82508" data-unique="zubvrnt6h" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_11/DAoCJ.png.44e56a6f8ff26d558e62fc149533be89.png"></a>
</p>

<p>
	سنحاول وصل الخطوط بين جميع المنازل بأقل كلفة ممكنة، ولتحقيق ذلك سنستخدم <a href="https://wiki.hsoub.com/Algorithms/Prim_MST" rel="external">خوارزمية برم</a> Prim، وهي خوارزمية شرهة تبحث عن أصغر شجرة ممتدة spanning tree في مخطط موزون غير موجّه undirected weighted graph. وهذا يعني أنها تبحث عن مجموعة من الأضلاع التي تشكل شجرة تتضمّن كل العقد، بحيث يكون الوزن الإجمالي لجميع أضلاع الشجرة أقل ما يمكن.
</p>

<p>
	طُوِّرت هذه الخوارزمية عام 1930 من قبل عالم الرياضيات التشيكي Vojtěch Jarník، ثم أعاد عالم الحوسبة روبرت كلاي بْرِم اكتشافها ونشرها في عام 1957، وكذلك <a href="https://ar.wikipedia.org/wiki/%D8%A5%D8%AF%D8%B3%D8%AE%D8%B1_%D8%AF%D9%8A%D9%83%D8%B3%D8%AA%D8%B1%D8%A7" rel="external nofollow">إيدجر ديكسترا </a> في عام 1959. تُعرف أيضًا باسم خوارزمية DJP وخوارزمية Jarnik وخوارزمية Prim-Jarnik وخوارزمية Prim-Dijsktra.
</p>

<p>
	إذا كانت G مخططًا غير موجّه، فنقول أنّ المخطط S هو مخطط فرعي subgraph من G إذا كانت جميع حروفه وأضلَاعه تنتمي إلى G.
</p>

<p>
	ونقول أنّ S شجرة ممتدة فقط إذا كانت:
</p>

<ul>
	<li>
		تحتوي جميع عقد G.
	</li>
	<li>
		وكانت شجرة، أي أنّها لا تحتوي أيّ دورة cycle، وجميع عقدها متصلة.
	</li>
	<li>
		تحتوى (n-1) ضلعًا، حيث n يمثّل عدد العقد في G.
	</li>
</ul>

<p>
	يمكن أن يكون لمخطط ما أكثر من شجرة ممتدة واحدة، والشجرة الممتدة الصغرى لمخطط موزون غير موجّه هي شجرة مجموع أوزان أضلاعها أقل ما يمكن. سنستخدم خوارزمية Prim لإيجاد الشجرة الممتدة الصغرى، وسيساعدنا هذا على حل مشكلة الخطوط الهاتفية في المثال أعلاه.
</p>

<p>
	أولاً، سنختار عقدةً ما لتكون العقدة المصدرية source node، ولتكن العقدة 1 مثلًا. سنضيف الآن الضلع الذي ينطلق من 1 وله أقل كلفة إلى المخطط الفرعي، ونلوّن الأضلاع التي أضفناها إلى المخطط الفرعي باللون الأزرق. وسيكون الضلع 1-5 في مثالنا هو الضلع الذي له أقل كلفة.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82517" href="https://academy.hsoub.com/uploads/monthly_2021_11/Vc4qL.png.e6b08712448522db6cf279ca98ead9c5.png" rel="" data-fileext="png"><img alt="Vc4qL.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82517" data-unique="al0u8gef2" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_11/Vc4qL.png.e6b08712448522db6cf279ca98ead9c5.png"></a>
</p>

<p>
	الآن، سنأخذ الضلع الأقل كلفة من بين جميع الأضلاع المُنطلِقة من العقدة 1 أو العقدة 5. وبما أنّنا لوّنّا 1-5 سلفًا، فالضلع المرشّح الثاني هو الضلع 1-2.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82513" href="https://academy.hsoub.com/uploads/monthly_2021_11/N85Jm.png.742ff42704e873582e52ca450c59c366.png" rel="" data-fileext="png"><img alt="N85Jm.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82513" data-unique="3xkmywe5r" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_11/N85Jm.png.742ff42704e873582e52ca450c59c366.png"></a>
</p>

<p>
	نأخذ هذه المرة الضلع الأقل كلفةً من بين جميع الأضلاع (غير المُلوّنة) المُنطلقة من العقدة 1 أو العقدة 2 أو العقدة 5، والذي هو في حالتنا 5-4.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82520" href="https://academy.hsoub.com/uploads/monthly_2021_11/wyzXK.png.0fa6036e88684a3b97415c9c2f77d7fd.png" rel="" data-fileext="png"><img alt="wyzXK.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82520" data-unique="d1md3jdlz" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_11/wyzXK.png.0fa6036e88684a3b97415c9c2f77d7fd.png"></a>
</p>

<p>
	تحتاج الخطوة التالية إلى تركيز، وفيها سنحاول أن نفعل ما فعلناه سابقا، ونختار من بين جميع الأضلاع (غير المُلوّنة) التي تنطلق من العقدة 1 أو 2 أو 5 أو 4 الضلع الذي له أقل كلفة، وهو 2-4. ولكن انتبه إلى أنّه في حال اختيار هذا الضلع، فسنخلُق دورةً cycle في المخطط الفرعي، ذلك أنّ العقدتين 2 و4 موجودتان سلفًا فيه، لذا فإنّ أخذ الضلع 2-4 ليس الخيار الصحيح. وبدلًا من ذلك سنختار الضلع 4-8.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82521" href="https://academy.hsoub.com/uploads/monthly_2021_11/XOQT3.png.6263d6c4eb9dffeffc839cc27b3d07ff.png" rel="" data-fileext="png"><img alt="XOQT3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82521" data-unique="doklr4jo1" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_11/XOQT3.png.6263d6c4eb9dffeffc839cc27b3d07ff.png"></a>
</p>

<p>
	إذا واصلنا على هذا النحو فسنختَار الأضلاع 8-6 و6-7 و4-3، وسيبدو المخطط الفرعي النهائي هكذا:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82516" href="https://academy.hsoub.com/uploads/monthly_2021_11/uco0u.png.c16a201f3df983a5eab1138af1e4779f.png" rel="" data-fileext="png"><img alt="uco0u.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82516" data-unique="pixtxfh5s" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_11/uco0u.png.c16a201f3df983a5eab1138af1e4779f.png"></a>
</p>

<p>
	إذا أزلنا الأضلاع التي لم نَخترها (غير المُلوّنة)، فسنحصل على:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82519" href="https://academy.hsoub.com/uploads/monthly_2021_11/WTz3O.png.5a9fb451726fcdd2c498da318086360d.png" rel="" data-fileext="png"><img alt="WTz3O.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82519" data-unique="iudznd2m6" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_11/WTz3O.png.5a9fb451726fcdd2c498da318086360d.png"></a>
</p>

<p>
	هذه هي الشجرة الممتدة الصغرى MST التي نبحث عنها، ونستنتج منها أنّ تكلفة إعداد خطوط الهاتف هي: 4 + 2 + 5 + 11 + 9 + 2 + 1 = 34.
</p>

<p>
	يمكن أن تكون هناك عدة أشجار ممتدة صغرى للمخطط نفسه بحسب العقدة المصدرية التي اخترناها. انظر شيفرة توضيحية لهذه الخوارزمية، حيث تمثل <code>Graph</code> مخططًا فارغًا متصلًا غير موزون، وتمثل <code>Vnew</code> مخططًا فرعيًا جديدًا عقدته المصدرية هي <code>x</code>:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9955_9" style=""><span class="typ">Procedure</span><span class="pln"> </span><span class="typ">PrimsMST</span><span class="pun">(</span><span class="typ">Graph</span><span class="pun">):</span><span class="pln">     
</span><span class="typ">Vnew</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln">x</span><span class="pun">}</span><span class="pln">                   
</span><span class="typ">Enew</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="typ">Vnew</span><span class="pln"> is </span><span class="kwd">not</span><span class="pln"> equal to V
   u </span><span class="pun">-&gt;</span><span class="pln"> a node from </span><span class="typ">Vnew</span><span class="pln">
   v </span><span class="pun">-&gt;</span><span class="pln"> a node that is </span><span class="kwd">not</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> </span><span class="typ">Vnew</span><span class="pln"> such that edge u</span><span class="pun">-</span><span class="pln">v has the minimum cost
                              </span><span class="pun">//</span><span class="pln"> </span><span class="pun">إذا</span><span class="pln"> </span><span class="pun">كان</span><span class="pln"> </span><span class="pun">لعقدتين</span><span class="pln"> </span><span class="pun">الوزن</span><span class="pln"> </span><span class="pun">نفسه،</span><span class="pln"> </span><span class="pun">فاختر</span><span class="pln"> </span><span class="pun">أيًّا</span><span class="pln"> </span><span class="pun">منهما</span><span class="pln">
   add v to </span><span class="typ">Vnew</span><span class="pln">
   add edge </span><span class="pun">(</span><span class="pln">u</span><span class="pun">,</span><span class="pln"> v</span><span class="pun">)</span><span class="pln"> to </span><span class="typ">Enew</span><span class="pln">
</span><span class="kwd">end</span><span class="pln"> </span><span class="kwd">while</span><span class="pln">
</span><span class="typ">Return</span><span class="pln"> </span><span class="typ">Vnew</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> </span><span class="typ">Enew</span></pre>

<h3>
	التعقيد
</h3>

<p>
	التعقيد الزمني للمنظور البسيط أعلاه هو ( O (V <sup>2‎</sup>، يمكننا تقليل التعقيد باستخدام <a href="https://wiki.hsoub.com/Algorithms/queues" rel="external">طابور</a> أولويات priority queue، فإذا أضفنا عقدةً جديدةً إلى المخطط الفرعي الجديد <code>Vnew</code>، فيمكننا إضافة أضلاعها المجاورة إلى رتل الأولويات، ثم إخراج الضلع الموزون ذو الكلفة الأدنى منه. وحينئذ يصبح التعقيد مساويًا للقيمة O (ElogE)‎‎، حيث يمثّل E عدد الأضلاع. يمكنك أيضًا إنشاء <a href="https://ar.wikipedia.org/wiki/%D8%A7%D9%84%D9%83%D9%88%D9%85%D8%A9_(%D8%A8%D9%86%D9%8A%D8%A9_%D9%85%D8%B9%D8%B7%D9%8A%D8%A7%D8%AA)" rel="external nofollow">كَومة</a> ثنائية Binary Heap لتخفيض التعقيد إلى O (ElogV)‎‎.
</p>

<p>
	هذه شيفرة توضيحية تستخدم طابور الأولويات:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9955_13" style=""><span class="typ">Procedure</span><span class="pln"> </span><span class="typ">MSTPrim</span><span class="pun">(</span><span class="typ">Graph</span><span class="pun">,</span><span class="pln"> source</span><span class="pun">):</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> each u in V
   key</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> inf
   parent</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> NULL
end </span><span class="kwd">for</span><span class="pln">
key</span><span class="pun">[</span><span class="pln">source</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
Q </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Priority_Queue</span><span class="pun">()</span><span class="pln">
Q </span><span class="pun">=</span><span class="pln"> V
</span><span class="kwd">while</span><span class="pln"> Q is not empty
   u </span><span class="pun">-&gt;</span><span class="pln"> Q</span><span class="pun">.</span><span class="pln">pop
   </span><span class="kwd">for</span><span class="pln"> each v adjacent to i
       </span><span class="kwd">if</span><span class="pln"> v belongs to Q and </span><span class="typ">Edge</span><span class="pun">(</span><span class="pln">u</span><span class="pun">,</span><span class="pln">v</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> key</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln">    </span><span class="com">// edge(u, v) كلفة Edge(u, v) تمثل</span><span class="pln">
           parent</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> u
           key</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">Edge</span><span class="pun">(</span><span class="pln">u</span><span class="pun">,</span><span class="pln"> v</span><span class="pun">)</span><span class="pln">
       end </span><span class="kwd">if</span><span class="pln">
   end </span><span class="kwd">for</span><span class="pln">
end </span><span class="kwd">while</span></pre>

<p>
	تخزّن <code>key[]‎‎</code> الكلفة الأقل لعبور العقدة v، فيما تُستخدم <code>parent[]‎‎</code> لتخزين العقدة الأصلية parent node، وهذا مفيد لتسلّق الشجرة وطباعتها. فيما يلي برنامج بسيط بلغة Java:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9955_15" style=""><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">util</span><span class="pun">.*;</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Graph</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> infinite </span><span class="pun">=</span><span class="pln"> </span><span class="lit">9999999</span><span class="pun">;</span><span class="pln">
  </span><span class="typ">int</span><span class="pun">[][]</span><span class="pln">  </span><span class="typ">LinkCost</span><span class="pun">;</span><span class="pln">
  </span><span class="typ">int</span><span class="pln">      </span><span class="typ">NNodes</span><span class="pun">;</span><span class="pln">
  </span><span class="typ">Graph</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[][]</span><span class="pln"> mat</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
     </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> j</span><span class="pun">;</span><span class="pln">
     </span><span class="typ">NNodes</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> mat</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln">
     </span><span class="typ">LinkCost</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[</span><span class="typ">NNodes</span><span class="pun">][</span><span class="typ">NNodes</span><span class="pun">];</span><span class="pln">
     </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">NNodes</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln">
     </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> j</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">NNodes</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">++)</span><span class="pln">
        </span><span class="pun">{</span><span class="pln">
           </span><span class="typ">LinkCost</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> mat</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">];</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="typ">LinkCost</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
              </span><span class="typ">LinkCost</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> infinite</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">
     </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">NNodes</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln">
     </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> j</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">NNodes</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">++)</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="typ">LinkCost</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> infinite </span><span class="pun">)</span><span class="pln">
              </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="typ">LinkCost</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln">
              </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">" * "</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> unReached</span><span class="pun">(</span><span class="pln">boolean</span><span class="pun">[]</span><span class="pln"> r</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
     boolean done </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
     </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> r</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> r</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
           </span><span class="kwd">return</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
     </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> </span><span class="typ">Prim</span><span class="pun">(</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
     </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> j</span><span class="pun">,</span><span class="pln"> k</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">;</span><span class="pln">
     boolean</span><span class="pun">[]</span><span class="pln"> </span><span class="typ">Reached</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> boolean</span><span class="pun">[</span><span class="typ">NNodes</span><span class="pun">];</span><span class="pln">
     </span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> predNode </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[</span><span class="typ">NNodes</span><span class="pun">];</span><span class="pln">
     </span><span class="typ">Reached</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
     </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> k </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> k </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">NNodes</span><span class="pun">;</span><span class="pln"> k</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
     </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Reached</span><span class="pun">[</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">
     predNode</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
     printReachSet</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Reached</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
     </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">k </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> k </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">NNodes</span><span class="pun">;</span><span class="pln"> k</span><span class="pun">++)</span><span class="pln">
     </span><span class="pun">{</span><span class="pln">
        x </span><span class="pun">=</span><span class="pln"> y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">NNodes</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
           </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">NNodes</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="typ">Reached</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="pun">!</span><span class="typ">Reached</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln">
                    </span><span class="typ">LinkCost</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">LinkCost</span><span class="pun">[</span><span class="pln">x</span><span class="pun">][</span><span class="pln">y</span><span class="pun">]</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
               </span><span class="pun">{</span><span class="pln">
                  x </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
                  y </span><span class="pun">=</span><span class="pln"> j</span><span class="pun">;</span><span class="pln">
               </span><span class="pun">}</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Min cost edge: ("</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
                               </span><span class="pun">+</span><span class="pln"> x </span><span class="pun">+</span><span class="pln"> </span><span class="str">","</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
                               </span><span class="pun">+</span><span class="pln"> y </span><span class="pun">+</span><span class="pln"> </span><span class="str">")"</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
                               </span><span class="str">"cost = "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="typ">LinkCost</span><span class="pun">[</span><span class="pln">x</span><span class="pun">][</span><span class="pln">y</span><span class="pun">]);</span><span class="pln">
        predNode</span><span class="pun">[</span><span class="pln">y</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">;</span><span class="pln">
        </span><span class="typ">Reached</span><span class="pun">[</span><span class="pln">y</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
        printReachSet</span><span class="pun">(</span><span class="pln"> </span><span class="typ">Reached</span><span class="pln"> </span><span class="pun">);</span><span class="pln">
        </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">();</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">
     </span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> a</span><span class="pun">=</span><span class="pln"> predNode</span><span class="pun">;</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">NNodes</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
         </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln"> a</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">" --&gt; "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> i </span><span class="pun">);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
  </span><span class="kwd">void</span><span class="pln"> printReachSet</span><span class="pun">(</span><span class="pln">boolean</span><span class="pun">[]</span><span class="pln"> </span><span class="typ">Reached</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
     </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="str">"ReachSet = "</span><span class="pun">);</span><span class="pln">
     </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">Reached</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="typ">Reached</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">)</span><span class="pln">
          </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">print</span><span class="pun">(</span><span class="pln"> i </span><span class="pun">+</span><span class="pln"> </span><span class="str">" "</span><span class="pun">);</span><span class="pln">
     </span><span class="com">//System.out.println();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">{</span><span class="pln">
     </span><span class="typ">int</span><span class="pun">[][]</span><span class="pln"> conn </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{{</span><span class="lit">0</span><span class="pun">,</span><span class="lit">3</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">4</span><span class="pun">},</span><span class="pln">  </span><span class="com">// 0</span><span class="pln">
                     </span><span class="pun">{</span><span class="lit">3</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">4</span><span class="pun">,</span><span class="lit">0</span><span class="pun">},</span><span class="pln">  </span><span class="com">// 1</span><span class="pln">
                     </span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">6</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">0</span><span class="pun">},</span><span class="pln">  </span><span class="com">// 2</span><span class="pln">
                     </span><span class="pun">{</span><span class="lit">2</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">6</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">},</span><span class="pln">  </span><span class="com">// 3</span><span class="pln">
                     </span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">8</span><span class="pun">},</span><span class="pln">  </span><span class="com">// 4</span><span class="pln">
                     </span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">1</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">8</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">},</span><span class="pln">  </span><span class="com">// 5</span><span class="pln">
                     </span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">8</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">},</span><span class="pln">  </span><span class="com">// 6</span><span class="pln">
                     </span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="lit">4</span><span class="pun">,</span><span class="lit">2</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">},</span><span class="pln">  </span><span class="com">// 7</span><span class="pln">
                     </span><span class="pun">{</span><span class="lit">4</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">8</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">}</span><span class="pln">   </span><span class="com">// 8</span><span class="pln">
                    </span><span class="pun">};</span><span class="pln">
     </span><span class="typ">Graph</span><span class="pln"> G </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Graph</span><span class="pun">(</span><span class="pln">conn</span><span class="pun">);</span><span class="pln">
     G</span><span class="pun">.</span><span class="typ">Prim</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	صرّف الشيفرة أعلاه باستخدام التعليمة <code>‎javac Graph.java‎</code>، وسيكون الخرج الناتج كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9955_17" style=""><span class="pln">$ java </span><span class="typ">Graph</span><span class="pln">
</span><span class="pun">*</span><span class="pln">    </span><span class="lit">3</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="lit">2</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="lit">4</span><span class="pln">
</span><span class="lit">3</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">*</span><span class="pln">
</span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="lit">1</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="lit">2</span><span class="pln">    </span><span class="pun">*</span><span class="pln">
</span><span class="lit">2</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="lit">1</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">
</span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="lit">1</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="lit">8</span><span class="pln">
</span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="lit">1</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="lit">8</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">
</span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="lit">8</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">
</span><span class="pun">*</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="lit">2</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">
</span><span class="lit">4</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="lit">8</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">    </span><span class="pun">*</span><span class="pln">
</span><span class="typ">ReachSet</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="typ">Min</span><span class="pln"> cost edge</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">3</span><span class="pun">)</span><span class="pln">cost </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="typ">ReachSet</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="typ">Min</span><span class="pln"> cost edge</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="lit">3</span><span class="pun">,</span><span class="lit">4</span><span class="pun">)</span><span class="pln">cost </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="typ">ReachSet</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="lit">4</span><span class="pln">
</span><span class="typ">Min</span><span class="pln"> cost edge</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">1</span><span class="pun">)</span><span class="pln">cost </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="typ">ReachSet</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="lit">4</span><span class="pln">
</span><span class="typ">Min</span><span class="pln"> cost edge</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">8</span><span class="pun">)</span><span class="pln">cost </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4</span><span class="pln">
</span><span class="typ">ReachSet</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="lit">8</span><span class="pln">
</span><span class="typ">Min</span><span class="pln"> cost edge</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">7</span><span class="pun">)</span><span class="pln">cost </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4</span><span class="pln">
</span><span class="typ">ReachSet</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="lit">7</span><span class="pln"> </span><span class="lit">8</span><span class="pln">
</span><span class="typ">Min</span><span class="pln"> cost edge</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="lit">7</span><span class="pun">,</span><span class="lit">2</span><span class="pun">)</span><span class="pln">cost </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="typ">ReachSet</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="lit">7</span><span class="pln"> </span><span class="lit">8</span><span class="pln">
</span><span class="typ">Min</span><span class="pln"> cost edge</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="lit">5</span><span class="pun">)</span><span class="pln">cost </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="typ">ReachSet</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="lit">7</span><span class="pln"> </span><span class="lit">8</span><span class="pln">
</span><span class="typ">Min</span><span class="pln"> cost edge</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="lit">6</span><span class="pun">)</span><span class="pln">cost </span><span class="pun">=</span><span class="pln"> </span><span class="lit">8</span><span class="pln">
</span><span class="typ">ReachSet</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="lit">6</span><span class="pln"> </span><span class="lit">7</span><span class="pln"> </span><span class="lit">8</span><span class="pln">
</span><span class="lit">0</span><span class="pln"> </span><span class="pun">--&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="lit">0</span><span class="pln"> </span><span class="pun">--&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="lit">7</span><span class="pln"> </span><span class="pun">--&gt;</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="lit">0</span><span class="pln"> </span><span class="pun">--&gt;</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="lit">3</span><span class="pln"> </span><span class="pun">--&gt;</span><span class="pln"> </span><span class="lit">4</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> </span><span class="pun">--&gt;</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="lit">5</span><span class="pln"> </span><span class="pun">--&gt;</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
</span><span class="lit">1</span><span class="pln"> </span><span class="pun">--&gt;</span><span class="pln"> </span><span class="lit">7</span><span class="pln">
</span><span class="lit">0</span><span class="pln"> </span><span class="pun">--&gt;</span><span class="pln"> </span><span class="lit">8</span></pre>

<h2>
	خوارزمية بلمان- فورد Bellman–Ford
</h2>

<p>
	<a href="https://wiki.hsoub.com/Algorithms/Bellman_Ford" rel="external">خوارزمية بِلمان - فورد</a> ‏Bellman–Ford هي خوارزمية تحاول حساب أقصر المسارات من رأس مصدري source vertex إلى جميع الحروف الأخرى في مخطط موجّه موزون، ورغم أنّ هذه الخوارزمية أبطأ من خوارزمية Dijkstra، إلا أنها تعمل في الحالات التي تكون فيها أوزان الأضلاع سالبة، كما أنّها قادرة على العثور على الدورات ذات الوزن السالب في المخطط، على خلاف خوارزمية Dijkstra التي لا تعمل في حال كانت هناك دورة سالبة، إذ ستستمر في المرور عبر الدورة مرارًا وتكرارًا، وتستمر أيضًا في تقليل المسافة بين الرأسيْن.
</p>

<p>
	تتمثل فكرة هذه الخوارزمية في المرور عبر جميع أضلاع المخطط واحدًا تلو الآخر بترتيب عشوائي، شرط أن يحقق الترتيب المعادلة التالية:
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<div class="ipsQuote_contents ipsClearfix" data-gramm="false">
		<p>
			لكل u وv، لدينا u &lt; v، فقط إذا كان (هناك ضلع من u إلى v)
		</p>
	</div>
</blockquote>

<p>
	بعد تحديد الترتيب، <a href="https://stackoverflow.com/questions/12782431/relaxation-of-an-edge-in-dijkstras-algorithm" rel="external nofollow">سنخفّف الضلع</a> -تخفيف الضلع هو تخفيض تكلفة الوصول إلى رأس معيّن عبر استخدام رأس آخر وسيط- وفقًا لصيغة التخفيف التالية.
</p>

<p>
	لكل ضلع u-v من u إلى v:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9955_19" style=""><span class="kwd">if</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln">
    d</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span></pre>

<p>
	بمعنى أنّه إذا كانت المسافة من المصدر إلى أيّ رأس u + وزن الضلع u-v &lt; المسافة من المصدر إلى رأس ٍآخر v، فسنحدّث المسافة من المصدر إلى v.
</p>

<p>
	نحتاج إلى تخفيف الأضلاع (V-1) مرّة على الأكثر، حيث V هو عدد الأضلاع في المخطط. سنشرح لاحقًا لماذا اخترنا العدد (V-1)، ونخزّن أيضًا الرأس الأب parent vertex الخاص بكل الرأس، ونكتب ما يلي في كل مرّة نخفّف ضلعًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9955_21" style=""><span class="pln">parent</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> u</span></pre>

<p>
	هذا يعني أننا وجدنا مسارًا آخر أقصر للوصول إلى v عبر u. سنحتاج أيضًا هذه القيمة المُخزّنة لاحقًا لطباعة أقصر مسار من المصدر إلى الرأس المنشود.
</p>

<p>
	انظر المثال التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82515" href="https://academy.hsoub.com/uploads/monthly_2021_11/qIriI.png.ed1f1a85dfd0d371f515e07958c77e91.png" rel="" data-fileext="png"><img alt="qIriI.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82515" data-unique="lb8cgi3ox" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_11/qIriI.png.ed1f1a85dfd0d371f515e07958c77e91.png"></a>
</p>

<p>
	لقد اخترنا 1 ليكون الرأس المصدري، والآن نريد العثور على أقصر مسار من هذا المصدر إلى جميع الحروف الأخرى.
</p>

<p>
	نكتب في البداية <code>d[1] = 0‎‎</code>، لأنّ 1 هو المصدر؛ أما البقيّة فستساوي اللانهاية لأنّنا لا نعرف مسافاتها بعد. سنخفّف الأضلاع في هذا التسلسل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2368_9" style=""><span class="pun">+--------+--------+--------+--------+--------+--------+--------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="pun">التسلسل</span><span class="pln">  </span><span class="pun">|</span><span class="pln">    </span><span class="lit">1</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">3</span><span class="pln">    </span><span class="pun">|</span><span class="pln">   </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">   </span><span class="pun">|</span><span class="pln">      </span><span class="lit">6</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------+--------+--------+--------+--------+--------+--------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="pun">الضلع</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pun">-&gt;</span><span class="lit">5</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pun">-&gt;</span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pun">-&gt;</span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pun">-&gt;</span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">   </span><span class="lit">4</span><span class="pun">-&gt;</span><span class="lit">6</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pun">-&gt;</span><span class="lit">3</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------+--------+--------+--------+--------+--------+--------+</span></pre>

<p>
	يمكنك أن تختار أيّ تسلسل تريد، إذا خفّفنا الأضلاع مرّةً واحدة، فسنحصل على المسافات من المصدر إلى جميع الرؤوس الأخرى للمسار الذي يستخدم ضلعًا واحدًا على الأكثر.
</p>

<p>
	لنخفّف الآن الأضلاع ونحدث قيم d[]‎‎:
</p>

<ol>
	<li>
		d[4] + cost[4][5] = inﬁnity + 7 = inﬁnity. لا يمكننا تحديث هذا.
	</li>
	<li>
		d[2] + cost[3][4] = inﬁnity. لا يمكننا تحديث هذا.
	</li>
	<li>
		d[1] + cost[1][3] = 0 + 2 = 2 &lt; d[2]‎‎ إذًا d[3] = 2 و parent[1] = 1.
	</li>
	<li>
		d[1] + cost[1][4] = 4. إذن d[4] = 4 &lt; d[4]. parent[4] = 1.
	</li>
	<li>
		d[4] + cost[4][6] = 9. d[6] = 9 &lt; d[6]. parent[6] = 4.
	</li>
	<li>
		d[2] + cost[2][3] = inﬁnity لا يمكننا تحديث هذا.
	</li>
</ol>

<p>
	تعذّر تحديث بعض الرؤوس نتيجة عدم تحقّق الشرط <code>‎d[u‎]</code><code> + cost[u‎]</code><code>[v] &lt; d[v]‎</code>. وكما قلنا سابقًا، فقد حصلنا على المسارات من المصدر إلى العقد الأخرى باستخدام ضلع واحد على الأكثر.
</p>

<p style="text-align: center;">
	<img alt="Pkhx2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82514" data-unique="7f7xsis7p" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_11/Pkhx2.png.073ef491fdd4d30e5386bcf432375ae1.png"> 
</p>

<p>
	سيزوّدنا التكرار الثاني بمسار يستخدم عقدتين:
</p>

<ol>
	<li>
		d[4] + cost[4][5] = 12 &lt; d[5]. d[5] = 12. parent[5] = 4.
	</li>
	<li>
		d[3] + cost[3][4] = 1 &lt; d[4]. d[4] = 1. parent[4] = 3
	</li>
	<li>
		d[3] تبقى بلا تغيير.
	</li>
	<li>
		d[4] تبقى بلا تغيير
	</li>
	<li>
		d[4] + cost[4][6] = 6 &lt; d[6]. d[6] = 6. parent[6] = 4.
	</li>
	<li>
		d[3] تبقى بلا تغيير.
	</li>
</ol>

<p>
	هكذا سيبدو المخطط:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82511" href="https://academy.hsoub.com/uploads/monthly_2021_11/hX168.png.ac66dcd00ca1e7cbc07a58e38bedb3d6.png" rel="" data-fileext="png"><img alt="hX168.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82511" data-unique="zy9pfvoq0" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_11/hX168.png.ac66dcd00ca1e7cbc07a58e38bedb3d6.png"></a>
</p>

<p>
	التكرار الثالث سيحدّث الرأس 5 فقط، حيث سيضع القيمة 8 في d[5]‎‎. وسيبدو المخطط هكذا:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82507" href="https://academy.hsoub.com/uploads/monthly_2021_11/CUtPh.png.89a63ea0505a77d655b7129d58c0e7b5.png" rel="" data-fileext="png"><img alt="CUtPh.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82507" data-unique="zynyn3kja" style="width: 500px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_11/CUtPh.png.89a63ea0505a77d655b7129d58c0e7b5.png"></a>
</p>

<p>
	بعد هذا، ستبقى المسافة كما هي مهما زِدنا من التكرارات، لذلك سنخزّن راية ﬂag للتحقق من وقوع أيّ تحديث أم لا، فإذا لم يقع أيّ تحديث، أوقفنا حلقة التكرار.
</p>

<p>
	هذه شيفرة توضيحية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7323_21" style=""><span class="typ">Procedure</span><span class="pln"> </span><span class="typ">Bellman</span><span class="pun">-</span><span class="typ">Ford</span><span class="pun">(</span><span class="typ">Graph</span><span class="pun">,</span><span class="pln"> source</span><span class="pun">):</span><span class="pln">
n </span><span class="pun">:=</span><span class="pln"> number of vertices in </span><span class="typ">Graph</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i from </span><span class="lit">1</span><span class="pln"> to n
   d</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> infinity
   parent</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> NULL
end </span><span class="kwd">for</span><span class="pln">
d</span><span class="pun">[</span><span class="pln">source</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i from </span><span class="lit">1</span><span class="pln"> to n</span><span class="pun">-</span><span class="lit">1</span><span class="pln">
   flag </span><span class="pun">:=</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> all edges from </span><span class="pun">(</span><span class="pln">u</span><span class="pun">,</span><span class="pln">v</span><span class="pun">)</span><span class="pln"> in </span><span class="typ">Graph</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln">
           d</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span><span class="pln">
           parent</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> u
           flag </span><span class="pun">:=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
       end </span><span class="kwd">if</span><span class="pln">
   end </span><span class="kwd">for</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> flag </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
       </span><span class="kwd">break</span><span class="pln">
end </span><span class="kwd">for</span><span class="pln">
</span><span class="typ">Return</span><span class="pln"> d</span></pre>

<p>
	لتتبع الدورات السالبة، سنعدّل الشيفرة كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7323_23" style=""><span class="typ">Procedure</span><span class="pln"> </span><span class="typ">Bellman</span><span class="pun">-</span><span class="typ">Ford</span><span class="pun">-</span><span class="typ">With</span><span class="pun">-</span><span class="typ">Negative</span><span class="pun">-</span><span class="typ">Cycle</span><span class="pun">-</span><span class="typ">Detection</span><span class="pun">(</span><span class="typ">Graph</span><span class="pun">,</span><span class="pln"> source</span><span class="pun">):</span><span class="pln">
n </span><span class="pun">:=</span><span class="pln"> number of vertices in </span><span class="typ">Graph</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i from </span><span class="lit">1</span><span class="pln"> to n
   d</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> infinity
   parent</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> NULL
end </span><span class="kwd">for</span><span class="pln">
d</span><span class="pun">[</span><span class="pln">source</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i from </span><span class="lit">1</span><span class="pln"> to n</span><span class="pun">-</span><span class="lit">1</span><span class="pln">
   flag </span><span class="pun">:=</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> all edges from </span><span class="pun">(</span><span class="pln">u</span><span class="pun">,</span><span class="pln">v</span><span class="pun">)</span><span class="pln"> in </span><span class="typ">Graph</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln">
           d</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span><span class="pln">
           parent</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> u
           flag </span><span class="pun">:=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
       end </span><span class="kwd">if</span><span class="pln">
   end </span><span class="kwd">for</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> flag </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
       </span><span class="kwd">break</span><span class="pln">
end </span><span class="kwd">for</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> all edges from </span><span class="pun">(</span><span class="pln">u</span><span class="pun">,</span><span class="pln">v</span><span class="pun">)</span><span class="pln"> in </span><span class="typ">Graph</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln">
       </span><span class="typ">Return</span><span class="pln"> </span><span class="str">"Negative Cycle Detected"</span><span class="pln">
   end </span><span class="kwd">if</span><span class="pln">
end </span><span class="kwd">for</span><span class="pln">
</span><span class="typ">Return</span><span class="pln"> d</span></pre>

<p>
	لأجل طباعة أقصر مسار إلى رأس معين، سنكّرر خلفيًا إلى الأب parent إلى أن نعثر على القيمة المعدومة <code>NULL</code>، ثمّ نطبع الحروف.
</p>

<p>
	انظر الشيفرة التوضيحية التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7323_25" style=""><span class="typ">Procedure</span><span class="pln"> </span><span class="typ">PathPrinting</span><span class="pun">(</span><span class="pln">u</span><span class="pun">)</span><span class="pln">
v </span><span class="pun">:=</span><span class="pln"> parent</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln">
</span><span class="kwd">if</span><span class="pln"> v </span><span class="pun">==</span><span class="pln"> NULL
     </span><span class="kwd">return</span><span class="pln">
</span><span class="typ">PathPrinting</span><span class="pun">(</span><span class="pln">v</span><span class="pun">)</span><span class="pln">
print </span><span class="pun">-&gt;</span><span class="pln"> u</span></pre>

<p>
	سيساوي التعقيد الزمني لهذه الخوارزمية O (V * E)‎‎ إن استخدمنا قائمة تجاور adjacency list بما أننا سنحتاج إلى تخفيف الأضلاع بحد أقصى (V-1) مرة، حيث تشير E إلى عدد الأضلاع؛ أما إن استخدمنا <a href="https://ar.wikipedia.org/wiki/%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A9_%D8%A7%D9%84%D9%85%D8%AC%D8%A7%D9%88%D8%B1%D8%A9" rel="external nofollow">مصفوفة تجاور</a> لتمثيل المخطط، فسيكون التعقيد الزمني O (V ^ 3‎‎)‎‎، ذلك أننا سنستطيع التكرار على جميع الأضلاع عند استخدام قائمة التجاور خلال زمن قدره O(E)‎‎، بينما نستغرق زمنًا قدره O (V ^ 2) ‎‎ إن استخدمنا مصفوفة التجاور.
</p>

<h3>
	رصد الدورات السالبة في المخططات
</h3>

<p>
	نستطيع رصد أي دورة سالبة في المخطط باستخدام خوارزمية بِلمَن-فورد Bellman-Ford. ونحن نعرف أنه يجب تخفيف جميع أضلاع المخطط عدد (V-1) مرة من أجل العثور على أقصر مسار، حيث تمثل V عدد الرؤوس في المخطط، وقد رأينا أنه لا يمكن تحديث d[]‎‎ مهما كان عدد التكرارات التي أجريناها.
</p>

<p>
	إذا كانت هناك دورة سالبة في المخطط، فسيمكننا تحديث d[]‎‎ حتى بعد التكرار (V-1)، ذلك أن كل تكرار، سيقلل العبور خلال دورة سالبة تكلفةَ المسار الأقصر، وهذا سبب أن خوارزمية بِلمَن فورد تحد عدد التكرارات بـ (V-1) مرة، لأننا سنعلق داخل حلقة أبدية لا تنتهي إن استخدمنا خوارزمية ديكسترا. سنركز الآن على كيفية إيجاد دورة سالبة، انظر المخطط التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82506" href="https://academy.hsoub.com/uploads/monthly_2021_11/AMKuZ.png.6285ee9c88f5ec8070323b94eda8a9dd.png" rel="" data-fileext="png"><img alt="AMKuZ.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82506" data-unique="abd0rnybc" src="https://academy.hsoub.com/uploads/monthly_2021_11/AMKuZ.png.6285ee9c88f5ec8070323b94eda8a9dd.png"></a>
</p>

<p>
	لنختر الرأس1 ليكون المصدر، بعد تطبيق خوارزمية بلمان-فورد لأقصر مسار ذي مصدر وحيد على المخطط، سنجد المسافات التي تفصل المصدر عن جميع الرؤوس الأخرى. انظر:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82505" href="https://academy.hsoub.com/uploads/monthly_2021_11/2P5k7.png.44e50a86adf4074c8e5e44d40671b6d3.png" rel="" data-fileext="png"><img alt="2P5k7.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82505" data-unique="9fli1d4on" src="https://academy.hsoub.com/uploads/monthly_2021_11/2P5k7.png.44e50a86adf4074c8e5e44d40671b6d3.png"></a>
</p>

<p>
	هكذا سيبدو المخطط بعد ‎‎(V-1) = 3 تكرار، وينبغي أن تكون هذه هي النتيجة الصحيحة، لأنّنا سنحتاج 3 تكرارات على الأكثر للعثور على أقصر مسار ما دامت هناك 4 أضلاع في المخطط، لذا إمّا أنّ هذه هي الإجابة الصحيحة، وإمّا أنّ هناك دورة ذات وزن سالب في المخطط. ولنعرف ذلك، سنضيف تكرارًا جديدًا بعد التكرار (V-1)، فإذا استمرت المسافة في الانخفاض، فذلك يعني أنّ هناك دورة سالبة في المخطط.
</p>

<p>
	ولهذا المثال فإنه بالنسبة للضلع 2-3، تكون نتيجة d[2] + cost [2] [3]‎‎ مساوية لـ 1، وهو ‎‎ أقل من d[3]‎‎، لذا يمكننا أن نستنتج أنّ هناك دورةً سالبةً في المخطط. والسؤال الآن هو كيف نجد هذه الدورة السالبة؟
</p>

<p>
	سنجري تعديلًا بسيطًا على خوارزمية Bellman-Ford للعثور على الدورة السالبة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7323_28" style=""><span class="typ">Procedure</span><span class="pln"> </span><span class="typ">NegativeCycleDetector</span><span class="pun">(</span><span class="typ">Graph</span><span class="pun">,</span><span class="pln"> source</span><span class="pun">):</span><span class="pln">
n </span><span class="pun">:=</span><span class="pln"> number of vertices in </span><span class="typ">Graph</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i from </span><span class="lit">1</span><span class="pln"> to n
   d</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> infinity
end </span><span class="kwd">for</span><span class="pln">
d</span><span class="pun">[</span><span class="pln">source</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i from </span><span class="lit">1</span><span class="pln"> to n</span><span class="pun">-</span><span class="lit">1</span><span class="pln">
   flag </span><span class="pun">:=</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> all edges from </span><span class="pun">(</span><span class="pln">u</span><span class="pun">,</span><span class="pln">v</span><span class="pun">)</span><span class="pln"> in </span><span class="typ">Graph</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln">
           d</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span><span class="pln">
           flag </span><span class="pun">:=</span><span class="pln"> </span><span class="kwd">true</span><span class="pln">
       end </span><span class="kwd">if</span><span class="pln">
   end </span><span class="kwd">for</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> flag </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
       </span><span class="kwd">break</span><span class="pln">
end </span><span class="kwd">for</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> all edges from </span><span class="pun">(</span><span class="pln">u</span><span class="pun">,</span><span class="pln">v</span><span class="pun">)</span><span class="pln"> in </span><span class="typ">Graph</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln">
       </span><span class="typ">Return</span><span class="pln"> </span><span class="str">"Negative Cycle Detected"</span><span class="pln">
   end </span><span class="kwd">if</span><span class="pln">
end </span><span class="kwd">for</span><span class="pln">
</span><span class="typ">Return</span><span class="pln"> </span><span class="str">"No Negative Cycle"</span></pre>

<p>
	بهذه الطريقة نستطيع التحقق مما إذا كانت هناك أيّ دورة سالبة في المخطط، كذلك نستطيع تعديل خوارزمية Bellman-Ford لتخزين الدورات السالبة وحفظ سجل لها.
</p>

<h3>
	لماذا نحتاج إلى تخفيف جميع الأضلاع بحد أقصى (V-1) مرة
</h3>

<p>
	نحتاج إلى تخفيف جميع أضلاع المخطط في خوارزمية Bellman-Ford للعثور على أقصر مسار، وتُكرّر هذه العملية (V-1) مرّةً بحد أقصى، حيث يمثل V عدد الرؤوس في المخطط. ويعتمد عدد التكرارات اللازمة للعثور على أقصر مسار من المصدر إلى جميع الرؤوس الأخرى على الترتيب الذي اخترناه لتخفيف الأضلاع. انظر المثال التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82518" href="https://academy.hsoub.com/uploads/monthly_2021_11/vunss.png.2f9b1200bc4250cdfb32b6671bdc7580.png" rel="" data-fileext="png"><img alt="vunss.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82518" data-unique="wouk91nal" src="https://academy.hsoub.com/uploads/monthly_2021_11/vunss.png.2f9b1200bc4250cdfb32b6671bdc7580.png"></a>
</p>

<p>
	لقد اخترنا الرأس 1 ليكون المصدر، سنبحث عن أقصر مسافة تفصل بين المصدر وجميع الحروف الأخرى. ونستطيع رؤية أننا سنحتاج في أسوأ الأحوال إلى (V-1) ضلع للوصول إلى الرأس 4، ووفقًا للترتيب الذي اكتُشفت من خلاله الأضلاع، فقد نحتاج إلى (V-1) مرة.
</p>

<p>
	للتوضيح، سنستخدم خوارزمية Bellman-Ford في مثال توضيحي للعثور على أقصر مسار.
</p>

<p>
	انظر التسلسل التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2368_11" style=""><span class="pun">+--------+--------+--------+------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="pun">التسلسل</span><span class="pln"> </span><span class="pun">|</span><span class="pln">    </span><span class="lit">1</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">      </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------+--------+--------+------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="pun">الضلع</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pun">-&gt;</span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pun">-&gt;</span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pun">-&gt;</span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------+--------+--------+------+</span></pre>

<p>
	في التكرار الأول:
</p>

<ol>
	<li>
		d[3] + cost[3][4]‎‎ = inﬁnity لن يحدث أيّ تغيير.
	</li>
	<li>
		d[2] + cost[2][3]‎‎ = inﬁnity لن يحدث أيّ تغيير.
	</li>
	<li>
		d[1] + cost[1][2] = 2 &lt; d[2]. d[2] = 2. parent[2] = 1.
	</li>
</ol>

<p>
	لاحظ أنّ عملية التخفيف لم تغيّر إلا قيمة d[2]‎‎ فقط. سيبدو المخطط خاصتنا هكذا:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82509" href="https://academy.hsoub.com/uploads/monthly_2021_11/ePGvK.png.1171706b4d91b74f11c0f6059a8a9c19.png" rel="" data-fileext="png"><img alt="ePGvK.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82509" data-unique="fk4kfvccn" src="https://academy.hsoub.com/uploads/monthly_2021_11/ePGvK.png.1171706b4d91b74f11c0f6059a8a9c19.png"></a>
</p>

<p>
	التكرار الثاني:
</p>

<ol>
	<li>
		d[3] + cost[3][4]‎‎ = inﬁnity لن يحدث أيّ تغيير.
	</li>
	<li>
		d[2] + cost[2][3] = 5 &lt; d[3]. d[3] = 5. parent[3] = 2.
	</li>
	<li>
		لن يحدث أيّ تغيير.
	</li>
</ol>

<p>
	غيّرت عمليةُ التخفيف قيمةَ d[3]‎‎ في هذه المرّة. وسيبدو المخطط هكذا:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82512" href="https://academy.hsoub.com/uploads/monthly_2021_11/jAH0f.png.0b2d446f6c79cf10b6a1664f3a0b9a73.png" rel="" data-fileext="png"><img alt="jAH0f.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82512" data-unique="s3q6cz22g" src="https://academy.hsoub.com/uploads/monthly_2021_11/jAH0f.png.0b2d446f6c79cf10b6a1664f3a0b9a73.png"></a>
</p>

<p>
	التكرار الثالث:
</p>

<ol>
	<li>
		d[3] + cost[3][4] = 7 &lt; d[4] . d[4] = 7 . parent[4] = 3 .
	</li>
	<li>
		لن يحدث أيّ تغيير.
	</li>
	<li>
		لن يحدث أيّ تغيير.
	</li>
</ol>

<p>
	وجدنا في التكرار الثالث أقصر مسار إلى 4 من المصدر 1، حيث سيبدو المخطط هكذا:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82504" href="https://academy.hsoub.com/uploads/monthly_2021_11/0CsqX.png.0819c0cf0590a6122bbff5f976089eaa.png" rel="" data-fileext="png"><img alt="0CsqX.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82504" data-unique="qb9j2o5bz" src="https://academy.hsoub.com/uploads/monthly_2021_11/0CsqX.png.0819c0cf0590a6122bbff5f976089eaa.png"></a>
</p>

<p>
	احتجنا إلى 3 تكرارات للعثور على أقصر مسار. ستظل قيمة d[]‎‎ كما هي بعد ذلك مهما حاولنا تخفيف الأضلاع. إليك تسلسلًا آخر:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2368_13" style=""><span class="pun">+--------+--------+--------+------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">    </span><span class="pun">التسلسل</span><span class="pln"> </span><span class="pun">|</span><span class="pln">   </span><span class="lit">1</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------+--------+--------+------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="pun">الضلع</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pun">-&gt;</span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pun">-&gt;</span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pun">-&gt;</span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------+--------+--------+------+</span></pre>

<p>
	سنحصل على:
</p>

<ol>
	<li>
		d[1] + cost[1][2] = 2 &lt; d[2] . d[2] = 2 .
	</li>
	<li>
		d[2] + cost[2][3] = 5 &lt; d[3]. d[3] = 5.
	</li>
	<li>
		d[3] + cost[3][4] = 7 &lt; d[4]. d[4] = 5.
	</li>
</ol>

<p>
	وجدنا أقصر مسار من المصدر إلى جميع العقد الأخرى منذ التكرار الأول، يمكننا إجراء التسلسلات الإضافية 1-&gt; 2 و3-&gt; 4 و 2-&gt; 3، والتي ستعطينا أقصر مسار بعد تكرارين. يقودنا هذا إلى استنتاج أنه مهما كان ترتيب التسلسل، فلن نحتاج أكثر من 3 تكرارات للعثور على أقصر مسار من المصدر.
</p>

<p>
	نستنتج أيضًا أننا قد لا نحتاج في بعض الحالات إلّا إلى تكرار واحد فقط للعثور على أقصر مسار من المصدر. وسنحتاج في أسوأ الحالات إلى (V-1) تكرار. أرجو أن تكون قد فهمت الآن لماذا ينبغي أن نكرّر عملية التخفيف (V-1) مرّة.
</p>

<h2>
	خوارزمية فلويد وورشال Floyd-Warshall
</h2>

<p>
	تُستخدم <a href="https://wiki.hsoub.com/Algorithms/Floyd_Warshall" rel="external">خوارزمية فلويد وورشال</a> Floyd-Warsha ll لإيجاد أقصر المسارات في مخطط موزون قد تكون أوزان أضلاعه موجبة أو سالبة.
</p>

<p>
	عند تنفيذ الخوارزمية مرّةً واحدة، سنحصل على أطوال -مجاميع أوزان- أقصر المسارات بين كل أزواج الرؤوس، ويمكنها -بقليل من التعديل- طباعة أقصر مسار، كما يمكنها رصد الدورات السالبة في المخطط. وخوارزمية Floyd- Warshall هي من خوارزميات البرمجة الديناميكية. لنطبق هذه الخوارزمية على المخطط التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82510" href="https://academy.hsoub.com/uploads/monthly_2021_11/heaAS.png.68b637ce1b719c096c323a6dde1fe16e.png" rel="" data-fileext="png"><img alt="heaAS.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82510" data-unique="akh6xcfg9" src="https://academy.hsoub.com/uploads/monthly_2021_11/heaAS.png.68b637ce1b719c096c323a6dde1fe16e.png"></a>
</p>

<p>
	أول شيء نفعله هو أخذ مصفوفتين ثنائيتَي الأبعاد لتكونا مصفُوفتي تجاور adjacency matrices يساوي حجماهما العدد الإجمالي للرؤوس. وفي مثالنا، سنأخذ مصفوفتين من الحجم 4*4، الأولى هي مصفوفة المسافات Distance Matrix، وسنخزّن فيها أقصر مسافة عثرنا عليها حتى الآن بين رأسين.
</p>

<p>
	بدايةً، إذا كان هناك ضلع بين u-v وكانت المسافة / الوزن = w، فإننا نضع <code>‎distance[u‎]</code><code>[v] = w‎</code>، وسنضع قيمة ما لا نهاية للأضلاغ غير الموجودة.
</p>

<p>
	المصفوفة الثانية هي مصفوفة المسارات Path Matrix، ونستخدمها لتوليد أقصر مسار بين رأسين، لذا إذا كان هناك مسار بين u وv، فسنضع <code>‎path[u‎]</code><code>[v] = u‎</code>، وهذا يعني أنّ أفضل طريقة للوصول إلى الرأس v انطلاقًا من u هو باستخدام الضلع الذي يربط v بـ u، وإذا لم يكن هناك مسار بين الرأسين، فسنعطيه القيمة N كناية على عدم وجود مسار متاح حاليًا. سيبدو جدولا المخطط كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2368_15" style=""><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">            </span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">            </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">            </span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">6</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">15</span><span class="pln"> </span><span class="pun">|</span><span class="pln">            </span><span class="pun">|</span><span class="pln">   </span><span class="lit">1</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  N  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">            </span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> inf </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> inf </span><span class="pun">|</span><span class="pln">            </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  N  </span><span class="pun">|</span><span class="pln">  N  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  N  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">            </span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> inf </span><span class="pun">|</span><span class="pln"> inf </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">            </span><span class="pun">|</span><span class="pln">   </span><span class="lit">3</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  N  </span><span class="pun">|</span><span class="pln">  N  </span><span class="pun">|</span><span class="pln">  N  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">            </span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> inf </span><span class="pun">|</span><span class="pln"> inf </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln">            </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  N  </span><span class="pun">|</span><span class="pln">  N  </span><span class="pun">|</span><span class="pln">  N  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">            </span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">المسار</span><span class="pln">                                       </span><span class="pun">المسافة</span></pre>

<p>
	وقد وضعنا الرأس N في المواضع القطرية diagonals في مصفوفة المسارات نظرًا لعدم وجود حلقة loop، ولما كانت المسافة من كل رأس إلى نفسه تساوي 0، فقد وضعنا القيمة 0 في المواضع القطرية في مصفوفة المسافات.
</p>

<p>
	سنختار رأسًا وسطيًا k لأجل تطبيق خوارزمية Floyd-Warshall، وسنتحق بعد ذلك لكلّ رأس i مما إن كنا نستطيع الانتقال من i إلى k ثم من k إلى j، حيث j يمثّل رأسًا آخر، لتقليل تكلفة الانتقال من i إلى j.
</p>

<p>
	إذا كانت المسافة distance [j]‎‎ أكبر من المسافة distance [k] + distance[k] [j]‎‎، فسنحدّث قيمة distance [j]، ونضع فيها مجموع هاتين المسافتين، كما سنحدّث path [j]‎‎ ونعطيها القيمة path[k] [j]‎‎، لأنّ الانتقال من i إلى k، ثم من k إلى j أفضل. كما ستٌختار جميع الرؤوس بنفس طريقة اختيار k. وهكذا نحصل على 3 حلقات متداخلة:
</p>

<ul>
	<li>
		k من 1 إلى 4.
		<ul>
			<li>
				i من 1 إلى 4.
				<ul>
					<li>
						j من 1 إلى 4.
					</li>
				</ul>
			</li>
		</ul>
	</li>
</ul>

<p>
	هذه شيفرة توضيحية لذلك:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7323_36" style=""><span class="kwd">if</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">k</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln">
    distance</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">k</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln">
    path</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> path</span><span class="pun">[</span><span class="pln">k</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln">
end </span><span class="kwd">if</span></pre>

<p>
	السؤال الآن هو: لكل زوج u,v من الرؤوس، هل يوجد رأس يمكن أن نمرّ عبره لتقصير المسافة بين u وv؟
</p>

<p>
	سيكون العدد الإجمالي لعمليات المخطط هو 4 * 4 * 4 = 64. وهذا يعني أنّنا سنجري هذا الاختبار 64 مرة، لنلقي نظرةً على بعض هذه الحالات:
</p>

<ul>
	<li>
		إذا كانت k = 1 وi = 2 وj = 3، فإن [distance [j ستساوي -2، وهي ليست أكبر من distance [k] + distance[k] [j] = -2 + 0 = -2‎‎، لذلك ستبقى دون تغيير.
	</li>
	<li>
		ومرةً أخرى، إذا كانت k = 1 وi = 4 وj = 2، فستكون distance [j] = inﬁnity‎‎، وهي أكبر من distance [k] + distance[k] [j] = 1 + 3 = 4‎‎‎‎‎‎، لذا نضع distance [j] = 4‎‎، وpath [j] = path[k] [j] = 1‎‎. وهذا يعني أنّه للانتقال من الرأس 4 إلى 2، فإنّ المسار 4-&gt; 1-&gt; 2 يكون أقصر من المسار الحالي.
	</li>
</ul>

<p>
	انظر هذا <a href="https://imgur.com/a/NU6Hg" rel="external nofollow">الرابط الأجنبي</a> للاطلاع على حسابات كل خطوة، وستبدو مصفوفتنا كما يلي بعد إجراء التعديلات اللازمة.
</p>

<p>
	بعد إجراء التغييرات اللازمة، ستبدو المصفوفتان كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_2368_17" style=""><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">            </span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">            </span><span class="pun">|</span><span class="pln">     </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">            </span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">            </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  N  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">            </span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="pun">-</span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln">            </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  N  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">            </span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">6</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">            </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  N  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">3</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">            </span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln">            </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">4</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">1</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  N  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">            </span><span class="pun">+-----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">المسار</span><span class="pln">                                       </span><span class="pun">المسافة</span></pre>

<p>
	وهكذا نكون قد حصلنا على مصفوفةِ أقصر المسافات، فمثلًا، تكون أقصر مسافة من 1 إلى 4 هي 3، وأقصر مسافة من 4 إلى 3 هي 2. انظر إلى الشيفرة التوضيحية التالية، حيث تمثل V عدد الرؤوس:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7323_40" style=""><span class="typ">Procedure</span><span class="pln"> </span><span class="typ">Floyd</span><span class="pun">-</span><span class="typ">Warshall</span><span class="pun">(</span><span class="typ">Graph</span><span class="pun">):</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> k from </span><span class="lit">1</span><span class="pln"> to V     
 </span><span class="kwd">for</span><span class="pln"> i from </span><span class="lit">1</span><span class="pln"> to V
 </span><span class="kwd">for</span><span class="pln"> j from </span><span class="lit">1</span><span class="pln"> to V
 </span><span class="kwd">if</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">k</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln">
               distance</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">k</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">k</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln">
               path</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">:=</span><span class="pln"> path</span><span class="pun">[</span><span class="pln">k</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln">
           end </span><span class="kwd">if</span><span class="pln">
       end </span><span class="kwd">for</span><span class="pln">
    end </span><span class="kwd">for</span><span class="pln">
end </span><span class="kwd">for</span></pre>

<p>
	سنتحقق من مصفوفة المسارات Path من أجل طباعة المسار، ولطباعة المسار من u إلى v، سنبدأ من path<code>[u‎]</code> [v]‎‎. ثمّ نستمر في تغيير v = path[u‎] [v]‎‎ إلى أن نحصل على path[u‎] [v] = u‎‎، وندفع كل قيم path[u‎] [v]‎‎ إلى <a href="https://wiki.hsoub.com/Algorithms/stacks" rel="external">مكدّس</a>.
</p>

<p>
	بعد العثور على الرأس u، سنطبع u ونبدأ بإخراج العناصر من المكدّس وطباعتها. هذا الأمر ممكن لأنّ مصفوفة المسارات تخزّن قيمة الرأس الذي يشارك في أقصر مسار إلى v انطلاقًا من أيّ عقدة أخرى.
</p>

<p>
	انظر إلى الشيفرة التوضيحية لذلك:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7323_42" style=""><span class="typ">Procedure</span><span class="pln"> </span><span class="typ">PrintPath</span><span class="pun">(</span><span class="pln">source</span><span class="pun">,</span><span class="pln"> destination</span><span class="pun">):</span><span class="pln">
s </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Stack</span><span class="pun">()</span><span class="pln">
S</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">destination</span><span class="pun">)</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">[</span><span class="pln">source</span><span class="pun">][</span><span class="pln">destination</span><span class="pun">]</span><span class="pln"> is not equal to source
    S</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="typ">Path</span><span class="pun">[</span><span class="pln">source</span><span class="pun">][</span><span class="pln">destination</span><span class="pun">])</span><span class="pln">
    destination </span><span class="pun">:=</span><span class="pln"> </span><span class="typ">Path</span><span class="pun">[</span><span class="pln">source</span><span class="pun">][</span><span class="pln">destination</span><span class="pun">]</span><span class="pln">
end </span><span class="kwd">while</span><span class="pln">
print </span><span class="pun">-&gt;</span><span class="pln"> source
</span><span class="kwd">while</span><span class="pln"> S is not empty
    print </span><span class="pun">-&gt;</span><span class="pln"> S</span><span class="pun">.</span><span class="pln">pop
end </span><span class="kwd">while</span></pre>

<p>
	من أجل التحقق من وجود دورة سالبة، سيكون علينا التحقق من القطر diagonal الرئيسي لمصفوفة المسافات، وإذا كانت أيٌّ من القيم القطرية diagonal سالبة، فهذا يعني وجود دورة سالبة في المخطط.
</p>

<p>
	إن تعقيد خوارزمية فلويد-وورشال Floyd-Warshall هو O (V<sup>3</sup>)‎‎، وتعقيد المساحة هو: O (V<sup>2</sup>)‎‎.
</p>

<p>
	ترجمة -بتصرّف- للفصول 19 و20 و22 من كتاب <a href="https://goalkicker.com/AlgorithmsBook/" rel="external nofollow">Algorithms Notes for Professionals</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D9%87%D8%A9-r1372/" rel="">تطبيقات الخوارزميات الشرهة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA/" rel="">المرجع الشامل إلى تعلم الخوارزميات للمبتدئين</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AF%D9%84%D9%8A%D9%84-%D8%B4%D8%A7%D9%85%D9%84-%D8%B9%D9%86-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%AA%D8%B9%D9%82%D9%8A%D8%AF-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-r1247/" rel="">دليل شامل عن تحليل تعقيد الخوارزمية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1282/" rel="">مدخل إلى الخوارزميات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-%D8%AA%D8%AD%D8%AF%D9%8A%D8%AF-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1-%D8%A7%D9%84%D9%86%D8%AC%D9%85%D9%8A%D8%A9-a-path%EF%AC%81nding-r1363/" rel="">خوارزمية تحديد المسار النجمية A* Pathﬁnding</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-%D8%AF%D9%8A%D9%83%D8%B3%D8%AA%D8%B1%D8%A7-dijkstra%E2%80%99s-algorithm-r1336/" rel="">خوارزمية ديكسترا Dijkstra’s Algorithm</a><em><em><em><em><em><em><em><em><em><em> </em></em></em></em></em></em></em></em></em></em>
	</li>
</ul>
]]></description><guid isPermaLink="false">1373</guid><pubDate>Wed, 10 Nov 2021 16:00:00 +0000</pubDate></item><item><title>&#x62A;&#x62D;&#x644;&#x64A;&#x644; &#x632;&#x645;&#x646; &#x62A;&#x634;&#x63A;&#x64A;&#x644; &#x627;&#x644;&#x642;&#x648;&#x627;&#x626;&#x645; &#x627;&#x644;&#x645;&#x646;&#x641;&#x630;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x645;&#x635;&#x641;&#x648;&#x641;&#x629;</title><link>https://academy.hsoub.com/programming/advanced/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A9-r1348/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/6173052bf0f50_------.png.e58fe5a3c44fc20863f3c9577551ae11.png" /></p>
<p>
	تضرب هذه المقالة عصفورين بحجرٍ واحدٍ، حيث سنحل فيها تمرين المقالة السابقة <a href="https://academy.hsoub.com/programming/advance/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1345/" rel="">مدخل إلى تحليل الخوارزميات</a>، وسنتطرق لوسيلة نصنّف من خلالها الخوارزميات باستخدام ما يسمّى التحليل بالتسديد amortized analysis.
</p>

<h2 id="تصنيف-توابع-الصنف-myarraylist">
	تصنيف توابع الصنف MyArrayList
</h2>

<p>
	يُمكِننا تحديد ترتيب نمو order of growth غالبية التوابع بالنظر إلى شيفرتها. على سبيل المثال، انظر إلى تنفيذ التابع <code>get</code> المُعرَّف بالصنف <code>MyArrayList</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_7" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> E get</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> index</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">index </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> index </span><span class="pun">&gt;=</span><span class="pln"> size</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">IndexOutOfBoundsException</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">index</span><span class="pun">];</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	تستغرِق كل تعليمةٍ من تعليمات التابع <code>get</code> زمنًا ثابتًا، وبناءً على ذلك يستغرِق التابع <code>get</code> في المجمل زمنًا ثابتًا.
</p>

<p>
	الآن وقد صنّفنا التابع <code>get</code>، يمكننا بنفس الطريقة أن نصنّف التابع <code>set</code> الذي يَستخدِمه. انظر إلى تنفيذ التابع <code>set</code> من التمرين السابق الذي مرّ بنا في الفصل الثاني:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_9" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> E </span><span class="typ">set</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> index</span><span class="pun">,</span><span class="pln"> E element</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        E old </span><span class="pun">=</span><span class="pln"> get</span><span class="pun">(</span><span class="pln">index</span><span class="pun">);</span><span class="pln">
        array</span><span class="pun">[</span><span class="pln">index</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> old</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	ربما لاحظت أن التابع <code>set</code> لا يفحص نطاق المصفوفة صراحةً، فهو يعتمد في ذلك على استدعائه للتابع <code>get</code> الذي يُبلِّغ عن اعتراض exception عندما لا يكون الفهرس صالحًا.
</p>

<p>
	تَستغرق كل تعليمة من تعليمات التابع <code>set</code> -بما في ذلك استدعاؤه للتابع <code>get</code>- زمنًا ثابتًا، وعليه يُعدّ التابع <code>set</code> ثابت الزمن أيضًا.
</p>

<p>
	ولننتقل الآن إلى بعض التوابع الخطيّة. انظر مثلاً إلى تنفيذنا للتابع <code>indexOf</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_11" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> indexOf</span><span class="pun">(</span><span class="typ">Object</span><span class="pln"> target</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">size</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">equals</span><span class="pun">(</span><span class="pln">target</span><span class="pun">,</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">return</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	يحتوي التابع <code>indexOf</code> على حلقة تكرارية كما نرى، وفي كل مرورٍ تكراريٍّ في تلك الحلقة يستدعي التابعَ<code>equals</code>. علينا إذًا أن نُصنّف التابع <code>equals</code> أولًا لنتمكن من تصنيف التابع<code>indexOf</code>. لننظر إلى تعريف ذلك التابع:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_13" style=""><span class="pln">    </span><span class="kwd">private</span><span class="pln"> boolean equals</span><span class="pun">(</span><span class="typ">Object</span><span class="pln"> target</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Object</span><span class="pln"> element</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">target </span><span class="pun">==</span><span class="pln"> null</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> element </span><span class="pun">==</span><span class="pln"> null</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> target</span><span class="pun">.</span><span class="pln">equals</span><span class="pun">(</span><span class="pln">element</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	يستدعي التابعُ السابق التابعَ <code>target.equals</code> الذي يعتمد زمن تنفيذه على حجم المتغير <code>target</code> و<code>element</code>، ولكنه لا يعتمد على حجم المصفوفة، ولذلك سنَعُدّه ثابت الزمن لكي نُكمِل تحليل التابع <code>indexOf</code>.
</p>

<p>
	لنعُد الآنَ إلى التابع <code>indexOf</code>. تَستغرق كل تعليمة ضمن الحلقة زمنًا ثابتًا، مما يقودنا إلى السؤال التالي: كم عدد مرات تنفيذ الحلقة؟
</p>

<p>
	إذا حالفنا الحظ، قد نجد الكائن المطلوب مباشرةً ونعود بعد اختبار عنصر واحد فقط؛ أما إذا لم نكن محظوظين، فقد نضطرّ لاختبار جميع العناصر. لنقلْ إننا سنحتاج وسطيًّا إلى اختبار نصف عدد العناصر، ومن ثم يمكن القول بأن هذا التابع يصنّف بأنه تابع خطّيٌ أيضًا باستثناء الحالة الأقل احتمالًا، والتي يكون فيها العنصر المطلوب هو أول عنصر في المصفوفة.
</p>

<p>
	وهكذا يتشابه تحليل التابع <code>remove</code> مع التابع السابق. وفيما يلي تنفيذه:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_15" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> E remove</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> index</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        E element </span><span class="pun">=</span><span class="pln"> get</span><span class="pun">(</span><span class="pln">index</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="pln">index</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">size</span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">+</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        size</span><span class="pun">--;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> element</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	يَستدعِي التابعُ السابق التابعَ <code>get</code> ذا الزمن الثابت، ثم يُمرّ عبر عناصر المصفوفة بدايةً من الفهرس <code>index</code>. وإذا حذفنا العنصر الموجود في نهاية القائمة، فلن يُنفِّذ التابع حلقة التكرار على الإطلاق، وسيستغرِق التابع عندئذٍ زمنًا ثابتًا. في المقابل، إذا حذفنا العنصر الأول فسيمرّ التابع عبر جميع العناصر المتبقية، وبالتالي سيستغرِق التابع زمنًا خطيًا. لذلك يُمكِننا أن نَعُدّ التابع خطيًا في المجمل، باستثناء الحالة الخاصة التي يكون خلالها العنصر المطلوب حذفه واقعًا في نهاية المصفوفة أو على بعد مسافةٍ ثابتةٍ من نهايتها.
</p>

<h2 id="تصنيف-التابع-add">
	تصنيف التابع add
</h2>

<p>
	تستقبل النسخة التالية من التابع <code>add</code> فهرسًا وعنصرًا كمعاملات parameters:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_17" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> add</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> index</span><span class="pun">,</span><span class="pln"> E element</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">index </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> index </span><span class="pun">&gt;</span><span class="pln"> size</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">IndexOutOfBoundsException</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="com">// أضف عنصرًا للتأكّد من ضبط حجم المصفوفة</span><span class="pln">
        add</span><span class="pun">(</span><span class="pln">element</span><span class="pun">);</span><span class="pln">
        
        </span><span class="com">// حرك العناصر الأخرى</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="pln">size</span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&gt;</span><span class="pln">index</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">--)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="com">// ضع العنصر الجديد في المكان الصحيح</span><span class="pln">
        array</span><span class="pun">[</span><span class="pln">index</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	تستدعي النسخةُ ذات المعاملين <code>add(int, E)‎</code> النسخةَ ذات المعامل الواحد <code>add(E)‎</code> أولًا لكي تضع العنصر الجديد في نهاية المصفوفة، وبعد ذلك تُحرِّك العناصر الأخرى إلى اليمين، وتضع العنصر الجديد في المكان الصحيح.
</p>

<p>
	سنُحلّل أولًا زمن النسخة ذات المعامل الواحد <code>add(E)‎</code> قبل أن ننتقل إلى تحليل النسخة ذات المعاملين <code>add(int, E)‎</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_19" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> boolean add</span><span class="pun">(</span><span class="pln">E element</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">size </span><span class="pun">&gt;=</span><span class="pln"> array</span><span class="pun">.</span><span class="pln">length</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="com">// أنشئ مصفوفة أكبر وانسخ العناصر إليها</span><span class="pln">
            E</span><span class="pun">[]</span><span class="pln"> bigger </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">E</span><span class="pun">[])</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">[</span><span class="pln">array</span><span class="pun">.</span><span class="pln">length </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pun">];</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">arraycopy</span><span class="pun">(</span><span class="pln">array</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> bigger</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> array</span><span class="pun">.</span><span class="pln">length</span><span class="pun">);</span><span class="pln">
            array </span><span class="pun">=</span><span class="pln"> bigger</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln"> 
        array</span><span class="pun">[</span><span class="pln">size</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">;</span><span class="pln">
        size</span><span class="pun">++;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	تتضح لنا هنا صعوبة تحليل زمن النسخة ذات المعامل الواحد؛ لأنه لو كانت هناك مساحة غير مُستخدَمةٍ في المصفوفة، فسيستغرِق التابع زمنًا ثابتًا؛ أما لو اضطرّرنا لإعادة ضبط حجم المصفوفة، فسيستغرِق التابع زمنًا خطيًا؛ لأن التابع <code>System.arraycopy</code> يستغرِق بدوره زمنًا يتناسب مع حجم المصفوفة.
</p>

<p>
	إذاً فهل هذا التابع ثابت أم خطي؟ يُمكِننا أن نُصنِّفه بالتفكير في متوسط عدد العمليات التي تتطلَّبها عملية الإضافة خلال عدد من الإضافات مقداره n. وسنفترض للتبسيط بأن لدينا مصفوفةً بإمكانها تخزين عنصرين فقط.
</p>

<ul>
	<li>
		في المرة الأولى التي سنستدعي خلالها <code>add</code>، سيجد التابع مساحةً شاغرةً في المصفوفة، وسيُخزِّن عنصرًا واحدًا.
	</li>
	<li>
		في المرة الثانية، سيجد التابع مساحةً شاغرةً في المصفوفة، وسيُخزِّن عنصرًا واحدًا.
	</li>
	<li>
		في المرة الثالثة، سيعيد التابع ضبط حجم المصفوفة، وينسخ العنصرين السابقين، ثم يخزن العنصر الجديد وهو الثالث، وسيُصبِح بإمكان المصفوفة تخزين 4 عناصر في المجمل.
	</li>
	<li>
		ستخُزِّن المرة الرابعة عنصرًا واحدًا.
	</li>
	<li>
		ستعيد المرة الخامسة ضبط حجم المصفوفة، وتنسخ أربعة العناصر السابقة، وتخزّن عنصرًا جديدًا وهو الخامس، وسيكون في إمكان المصفوفة تخزين ثمانية عناصر إجمالًا.
	</li>
	<li>
		ستُخزِّن المرات الثلاث التالية ثلاثة عناصر.
	</li>
	<li>
		ستنسخ المرة التالية ثمانية العناصر السابقة وتُخزِّن عنصرًا جديدًا وهو التاسع، وسيُصبِح بإمكان المصفوفة تخزين ستة عشر عنصرًا.
	</li>
	<li>
		ستُخزِّن سبعُ المرات التالية سبعةَ عناصر. وهكذا دواليك.
	</li>
</ul>

<p>
	وإذا أردنا أن نلخص ما سبق:
</p>

<ul>
	<li>
		فإننا بعد 4 إضافات، سنكون قد خزَّنا 4 عناصر ونسخنا عنصرين.
	</li>
	<li>
		بعد 8 إضافات، سنكون قد خزَّنا 8 عناصر ونسخنا 6 عناصر.
	</li>
	<li>
		بعد 16 إضافةً، سنكون قد خزَّنا 16 عنصرًا ونسخنا 14 عنصرًا.
	</li>
</ul>

<p>
	يُفترَض أن تكون قد استقرأت سير العملية وحصلت على ما يلي: لكي نُضيف عدد مقداره n من العناصر، سنضطرّ إلى تخزين عدد n من العناصر ونسخ عدد n-2 من العناصر، وبالتالي يكون عدد العمليات الإجمالي هو n+n-2 أي 2n-2.
</p>

<p>
	لكي نحسب متوسط عدد العمليات المطلوبة لعملية الإضافة، ينبغي أن نقسِّم العدد الكلي للعمليات على عدد الإضافات n، وبذلك ستكون النتيجة هي 2‎-2/n. لاحِظ أنه كلما ازدادت قيمة n، ستقل قيمة الجزء الثاني 2‎/n. ونظراً لأن ما يهمنا هنا هو الأسّ الأكبر للأساس n، فيُمكِننا أن نَعُدّ التابع <code>add</code> ثابت الزمن.
</p>

<p>
	قد يبدو من الغريب لخوارزمية تحتاج إلى زمن خطي أحيانًا أن تكون ثابتة الزمن في المتوسط. والفكرة هي أننا نضاعف طول المصفوفة في كل مرة نضطرّ فيها إلى إعادة ضبط حجمها. يُقلِّل ذلك عدد المرات التي نَنَسَخ خلالها جميع العناصر، أما لو كنا نضيف مقدارًا ثابتًا إلى طول المصفوفة بدلًا من مضاعفتها بمقدارٍ ثابت، فإنّ هذا التحليل لا يصلح.
</p>

<p>
	يُطلَق على تصنيف الخوارزميات وفقًا لتلك الطريقة -أي بحساب متوسط الزمن الذي تستغرقه متتالية من الاستدعاءات- باسم التحليل بالتسديد. الآن وقد عرفنا أنّ التابع <code>add(E)‎</code> ثابت الزمن، ماذا عن التابع <code>add(int, E)‎</code>؟ يُنفِّذ التابع <code>add(int, E)‎</code> -بعد استدعائه للتابع <code>add(E)‎</code>- حلقةً تمُرّ عبر جزءٍ من عناصر المصفوفة وتُحرِّكها. تستغرِق تلك الحلقة زمنًا خطيًا باستثناء الحالة التي نضيف خلالها عنصرًا إلى نهاية المصفوفة، وعليه يكون التابع <code>add(int, E)‎</code> بدوره خطيًا.
</p>

<h2 id="حجم-المشكلة">
	حجم المشكلة
</h2>

<p>
	ولننتقل الآن إلى المثال الأخير في هذا المقال. انظر فيما يلي إلى تنفيذ التابع <code>removeAll</code> ضمن الصنف <code>MyArrayList</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_21" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> boolean removeAll</span><span class="pun">(</span><span class="typ">Collection</span><span class="pun">&lt;?&gt;</span><span class="pln"> collection</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        boolean flag </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Object</span><span class="pln"> obj</span><span class="pun">:</span><span class="pln"> collection</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            flag </span><span class="pun">&amp;=</span><span class="pln"> remove</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> flag</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	يستدعِي التابع <code>removeAll</code> في كلّ تكرارٍ ضمن الحلقة التابعَ <code>remove</code> الذي يستغرِق زمنًا خطّيًّا. قد يدفعك ذلك إلى الظن بأنّ التابعَ <code>removeAll</code> تربيعي، ولكن ليس بالضرورة أن يكون كذلك.
</p>

<p>
	يُنفِّذ التابع <code>removeAll</code> الحلقة مرةً واحدةً لكل عنصر في المتغير <code>collection</code>. فإذا كان المتغير يحتوي على عدد m من العناصر، وكانت القائمة التي نحذِف منها العنصر مكوَّنةً من عدد n من العناصر، فإن هذا التابع ينتمي إلى المجموعة O(nm)‎. لو افترضنا أن حجم <code>collection</code> ثابت، فسيكون التابع <code>removeAll</code> خطيًا بالنسبة لـ n، ولكن إذا كان حجم <code>collection</code> متناسبًا مع n، فسيكون التابع <code>removeAll</code> تربيعيًا. على سبيل المثال، إذا كان <code>collection</code> يحتوي دائمًا على 100 عنصر أو أقل، فإن التابع <code>removeAll</code> يستغرِق زمنًا خطيًا؛ أما إذا كان <code>collection</code> يحتوي في العموم على 1% من عناصر القائمة، فإن التابع <code>removeAll</code> يستغرِق زمنًا تربيعيًا.
</p>

<p>
	عند الحديث عن حجم المشكلة، ينبغي أن ننتبه إلى ماهية الحجم أو الأحجام التي نحن بصددها. يبين هذا المثال إحدى مشاكل تحليل الخوارزميات، وهي الاختصار المغري الناجم عن عدّ الحلقات، ففي حالة وجود حلقة واحدة، غالبًا ما تكون الخوارزمية خطية، وفي حالة وجود حلقتين متداخلتين، فغالبًا ما تكون الخوارزمية تربيعية، ولكن انتبه وفكر أولًا في عدد مرات تنفيذ كل حلقة، فإذا كان عددها يتناسب مع n لجميع الحلقات، فيمكنك الاكتفاء بعدّ الحلقات؛ أما إذا لم يكن عددها متناسبًا دائمًا مع n -كما هو الحال في هذا المثال- فعليك أن تتريث وتمنح الأمر مزيدًا من التفكير.
</p>

<h2 id="هياكل-البيانات-المترابطة-linked-data-structures">
	هياكل البيانات المترابطة linked data structures
</h2>

<p>
	سنقدم في التمرين التالي تنفيذًا جزئيًا للواجهة <code>List</code>. يَستخدِم هذا التنفيذ <a href="https://ar.wikipedia.org/wiki/%D9%82%D8%A7%D8%A6%D9%85%D8%A9_%D9%85%D8%AA%D8%B5%D9%84%D8%A9" rel="external nofollow">قائمةً متصلةً linked list</a> لتخزين العناصر.
</p>

<p>
	يُعدّ هيكل البيانات مترابطًا إذا كان مُؤلفًا من كائنات يُطلَق عليها عادةً اسم عُقد nodes، حيث تحتوي العقد على مراجع references تشير إلى عقد أخرى. وفي القوائم المترابطة، تحتوي كل عقدة على مرجع إلى العقدة التالية في القائمة. قد تحتوي العقد في أنواعٍ أخرى من هياكل البيانات المترابطة على مراجع تشير إلى عدة عقد، مثل الأشجار trees والشُعب graphs.
</p>

<p>
	تعرض الشيفرة التالية تنفيذًا بسيطًا لصنف عقدة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_23" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">ListNode</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Object</span><span class="pln"> data</span><span class="pun">;</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">ListNode</span><span class="pln"> next</span><span class="pun">;</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">ListNode</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data </span><span class="pun">=</span><span class="pln"> null</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> null</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">ListNode</span><span class="pun">(</span><span class="typ">Object</span><span class="pln"> data</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> null</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">ListNode</span><span class="pun">(</span><span class="typ">Object</span><span class="pln"> data</span><span class="pun">,</span><span class="pln"> </span><span class="typ">ListNode</span><span class="pln"> next</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> next</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> toString</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"ListNode("</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> data</span><span class="pun">.</span><span class="pln">toString</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="str">")"</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يتضمَّن الصنف <code>ListNode</code> متغيري نسخة هما: <code>data</code> و<code>next</code>. يحتوي <code>data</code> على مرجعٍ يشير إلى كائن ما من النوع <code>Object</code>، بينما يحتوي <code>next</code> على مرجع يشير إلى العقدة التالية في القائمة. ويحتوي <code>next</code> في العقدة الأخيرة من القائمة على القيمة الفارغة <code>null</code> كما هو متعارف عليه.
</p>

<p>
	يُعرِّف الصنف <code>ListNode</code> مجموعةً من <a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%A8%D9%88%D8%A7%D9%86%D9%8A-%D9%88%D8%AA%D9%87%D9%8A%D8%A6%D8%A9-%D8%A7%D9%84%D9%83%D8%A7%D8%A6%D9%86%D8%A7%D8%AA-object-initialization-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1109/" rel="">البواني constructors</a> التي تُمكِّنك من تمرير قيمٍ مبدئيةٍ للمتغيرين <code>data</code> و<code>next</code>، أو تمكّنك من مجرد تهيئتهما إلى القيمة الافتراضية <code>null</code>. ويُمكِنك أن تُفكِر في عقدةٍ واحدةٍ من النوع <code>ListNode</code> كما لو أنها قائمةٌ مُكوَّنةٌ من عنصرٍ واحدٍ، ولكن على العموم، يُمكِن لأي قائمة أن تحتوي على أي عدد من العقد.
</p>

<p>
	هناك الكثير من الطرق المستخدمة لإنشاء قائمة جديدة، وتتكوَّن إحداها من إنشاء مجموعة من كائنات الصنف <code>ListNode</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_25" style=""><span class="pln">        </span><span class="typ">ListNode</span><span class="pln"> node1 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">ListNode</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">ListNode</span><span class="pln"> node2 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">ListNode</span><span class="pun">(</span><span class="lit">2</span><span class="pun">);</span><span class="pln">
        </span><span class="typ">ListNode</span><span class="pln"> node3 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">ListNode</span><span class="pun">(</span><span class="lit">3</span><span class="pun">);</span></pre>

<p>
	ثم ربطها ببعض:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_27" style=""><span class="pln">        node1</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> node2</span><span class="pun">;</span><span class="pln">
        node2</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> node3</span><span class="pun">;</span><span class="pln">
        node3</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> null</span><span class="pun">;</span></pre>

<p>
	وهناك طريقة أخرى هي أن تُنشِئ عقدةً وتربطها في نفس الوقت. على سبيل المثال، إذا أردت أن تضيف عقدةً جديدةً إلى بداية قائمة، يُمكِنك كتابة ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_29" style=""><span class="pln">        </span><span class="typ">ListNode</span><span class="pln"> node0 </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">ListNode</span><span class="pun">(</span><span class="lit">0</span><span class="pun">،</span><span class="pln"> node1</span><span class="pun">);</span></pre>

<p>
	والآن، بعد تنفيذ سلسلة التعليمات السابقة، أصبح لدينا أربعةُ عقدٍ تحتوي على الأعداد الصحيحة 0 و1 و2 و3 مثل بيانات، ومربوطةٌ معًا بترتيب تصاعدي. لاحِظ أن قيمة <code>next</code> في العقدة الأخيرة تحتوي على القيمة الفارغة <code>null</code>.
</p>

<p style="text-align: center;">
	<img alt="001Linked_List.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="80444" data-unique="sr1xj5oqt" style="" src="https://academy.hsoub.com/uploads/monthly_2021_10/001Linked_List.PNG.dc6838a1f586147266a199e546cbab59.PNG">
</p>

<p>
	الرسمة التوضيحية السابقة هي رسم بيانيٌّ لكائنٍ يُوضِّح المتغيرات والكائنات التي تشير إليها تلك المتغيرات. تَظهَر المتغيرات بهيئة أسماءٍ داخل صناديقَ مع أسهمٍ تُوضِّح ما تشير إليه المتغيرات، بينما تَظهَر الكائنات بهيئة صناديق تَجِد خارجها النوع الذي تنتمي إليه (مثل <code>ListNode</code> و<code>Integer</code>)، وداخلها متغيرات النسخ المُعرَّفة بها.
</p>

<h2 id="تمرين-3">
	تمرين 3
</h2>

<p>
	ستجد ملفات الشيفرة المطلوبة لهذا التمرين في <a href="https://github.com/AllenDowney/ThinkDataStructures" rel="external nofollow">مستودع الكتاب</a>.
</p>

<ul>
	<li>
		<code>MyLinkedList.java</code>: يحتوي على تنفيذ جزئي للواجهة <code>List</code>، ويَستخدِم قائمةً مترابطةً لتخزين العناصر.
	</li>
	<li>
		<code>MyLinkedListTest.java</code>: يحتوي على اختبارات JUnit للصنف <code>MyLinkedList</code>.
	</li>
</ul>

<p>
	نفِّذ الأمر <code>ant MyArrayList</code> لتشغيل <code>MyArrayList.java</code> الذي يحتوي على عدة اختبارات بسيطة.
</p>

<p>
	ثم نفِّذ <code>ant MyArrayListTest</code> لتشغيل اختبارات JUnit التي سيفشل البعض منها. إذا نظرت إلى الشيفرة، ستجد ثلاثة تعليقات <code>TODO</code> للإشارة إلى التوابع التي ينبغي عليك إكمالها.
</p>

<p>
	لننظر إلى بعض أجزاء الشيفرة قبل أن تبدأ. انظر إلى المتغيرات والبواني المُعرَّفة في الصنف <code>MyLinkedList</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_31" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">MyLinkedList</span><span class="pun">&lt;</span><span class="pln">E</span><span class="pun">&gt;</span><span class="pln"> implements </span><span class="typ">List</span><span class="pun">&lt;</span><span class="pln">E</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">private</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> size</span><span class="pun">;</span><span class="pln">            </span><span class="com">// احتفظ بعدد العناصر</span><span class="pln">
    </span><span class="kwd">private</span><span class="pln"> </span><span class="typ">Node</span><span class="pln"> head</span><span class="pun">;</span><span class="pln">           </span><span class="com">// مرجع إلى العقدة الأولى</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">MyLinkedList</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        head </span><span class="pun">=</span><span class="pln"> null</span><span class="pun">;</span><span class="pln">
        size </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يحتفظ المتغير <code>size</code> -كما يُوضِّح التعليق- بعدد العناصر التي يَحمِلها كائن من النوع <code>MyLinkedList</code>، بينما يشير المتغير <code>head</code> إلى العقدة الأولى في القائمة أو يحمل القيمة الفارغة <code>null</code> إذا كانت القائمة فارغة.
</p>

<p>
	ليس من الضروري تخزين عدد العناصر. ولا يُعدّ الاحتفاظ بمعلوماتٍ إضافية في العموم أمرًا جيدًا؛ والسبب هو أن المعلومات الإضافية تحمّلنا عبء التحديث المستمر لها، ما قد يتسبَّب في وقوع أخطاء، كما أنها تحتل حيزًا إضافيًا من الذاكرة.
</p>

<p>
	لكننا لو خزَّنا <code>size</code> صراحةً، فإننا سنتمكَّن من كتابة تنفيذٍ للتابع <code>size</code>، بحيث يَستغرِق تنفيذه زمنًا ثابتًا؛ أما لو لم نفعل ذلك، فسنضطرّ إلى المرور عبر القائمة وعدّ عناصرها في كل مرة، وهذا يتطلَّب زمنًا خطيًا.
</p>

<p>
	من جهة أخرى، نظرًا لأننا نُخزِّن <code>size</code> صراحةً، فإننا سنضطرّ إلى تحديثه في كل مرة نضيف فيها عنصرًا إلى القائمة أو نحذفه منها. يؤدي ذلك إلى إبطاء تلك التوابع نوعًا ما، ولكنه لن يُؤثر على ترتيب النمو الخاص بها، ولذلك فلربما الأمر يستحق.
</p>

<p>
	يضبُط الباني قيمة <code>head</code> إلى <code>null</code>، مما يشير إلى كون القائمة فارغة، كما يضبُط <code>size</code> إلى صفر، ويَستخدِم هذا الصنف معامل نوع type parameter اسمه <code>E</code> لتخصيص نوع العناصر. ويَظهَر معامل النوع أيضًا بتعريف الصنف <code>Node</code> المُضمَّن داخل الصنف <code>MyLinkedList</code>. انظر تعريفه:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_33" style=""><span class="pln">    </span><span class="kwd">private</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Node</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">public</span><span class="pln"> E data</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Node</span><span class="pln"> next</span><span class="pun">;</span><span class="pln">

        </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Node</span><span class="pun">(</span><span class="pln">E data</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Node</span><span class="pln"> next</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data </span><span class="pun">=</span><span class="pln"> data</span><span class="pun">;</span><span class="pln">
            </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> next</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	أضف إلى هذا أن الصنف <code>Node</code> مشابهٌ تمامًا للصنف <code>ListNode</code> في الأعلى.
</p>

<p>
	والآن، انظر إلى تنفيذ التابع <code>add</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_35" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> boolean add</span><span class="pun">(</span><span class="pln">E element</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">head </span><span class="pun">==</span><span class="pln"> null</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            head </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Node</span><span class="pun">(</span><span class="pln">element</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Node</span><span class="pln"> node </span><span class="pun">=</span><span class="pln"> head</span><span class="pun">;</span><span class="pln">
            </span><span class="com">// نفذ الحلقة حتى تصل إلى العقدة الأخيرة</span><span class="pln">
            </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln"> </span><span class="pun">;</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">next </span><span class="pun">!=</span><span class="pln"> null</span><span class="pun">;</span><span class="pln"> node </span><span class="pun">=</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">next</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
            node</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Node</span><span class="pun">(</span><span class="pln">element</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        size</span><span class="pun">++;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	يُوضِّح هذا المثال نمطين ستحتاج لمعرفتهما لإكمال حل التمرين:
</p>

<ol start="">
	<li>
		في كثير من التوابع، عادةً ما نضطرّ إلى معالجة أول عنصرٍ في القائمة بطريقةٍ خاصة. وفي هذا المثال، إذا كنا نضيف العنصر الأول الى القائمة، فعلينا أن نُعدِّل قيمة <code>head</code>، أما في الحالات الأخرى، فعلينا أن نجتاز القائمة، حتى نصل إلى نهايتها، ثم نضيف العقدة الجديدة.
	</li>
	<li>
		يُبيّن ذلك التابع طريقة استخدام حلقة التكرار <code>for</code> من أجل اجتياز العقد الموجودة في القائمة. في مثالنا هذا لدينا حلقة واحدة. ولكن في الواقع قد تحتاج إلى كتابة نسخٍ عديدةٍ من تلك الحلقة ضمن الحلول الخاصة بك. من جهة أخرى، لاحِظ كيف صرّحنا عن <code>node</code> قبل بداية الحلقة؛ والهدف من ذلك هو أن نتمكَّن من استرجاعها بعد انتهاء الحلقة.
	</li>
</ol>

<p>
	والآن حان دورك، أكمل متن التابع <code>indexOf</code>. ويجب أن تقرأ توثيق <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html#indexOf(java.lang.Object)" rel="external nofollow">List indexOf</a> لكي تعرف ما ينبغي عليك القيام به. انتبه تحديدًا للطريقة التي يُفترَض له معالجة القيمة الفارغة <code>null</code> بها.
</p>

<p>
	كما هو الحال في تمرين مقالة تحليل الخوارزميات، وفَّرنا التابع المساعد <code>equals</code> للموازنة بين قيمة عنصرٍ ضمن المصفوفة وبين قيمةٍ معينةٍ أخرى، وفَحْص ما إذا كانت القيمتان متساويتين. يُعالِج التابع القيمة الفارغة معالجةً سليمة. لاحِظ أن التابع مُعرَّفٌ باستخدام المُعدِّل <code>private</code>؛ لأنه ليس جزءًا من الواجهة <code>List</code>، ويُستخدَم فقط داخل الصنف.
</p>

<p>
	شغِّل الاختبارات مرةً أخرى عندما تنتهي. ينبغي أن ينجح الاختبار <code>testIndexOf</code> وكذلك الاختبارات الأخرى التي تعتمد عليه.
</p>

<p>
	والآن، عليك أن تكمل نسخة التابع <code>add</code> ذات المعاملين. تَستقبِل تلك النسخة فهرسًا وتُخزِّن القيمة الجديدة في الفهرس المُمرَّر. وبالمثل، اقرأ أولًا <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html#add(int%20E)" rel="external nofollow">التوثيق List add</a> ثم نفِّذ التابع، وأخيرًا، شغِّل الاختبارات لكي تتأكّد من أنك نفّذتها بشكل سليم.
</p>

<p>
	لننتقل الآن إلى التابع الأخير: أكمل متن التابع <code>remove</code>. اقرأ <a href="https://docs.oracle.com/javase/8/docs/api/java/util/List.html#remove(int)" rel="external nofollow">توثيق التابع List remove</a>. بعدما تنتهي من إكمال هذا التابع، ينبغي أن تنجح جميع الاختبارات.
</p>

<p>
	بعد أن تُنهِي جميع التوابع وتتأكَّد من أنها تَعمَل بكفاءة، يُمكِنك مقابتها مع النسخ المتاحة في مجلد <code>solution</code> في <a href="https://github.com/AllenDowney/ThinkDataStructures" rel="external nofollow">مستودع الكتاب ThinkDataStructures</a> على GitHub.
</p>

<h2 id="ملحوظة-متعلقة-بكنس-المهملات-garbage-collection">
	ملحوظة متعلقة بكنس المهملات garbage collection
</h2>

<p>
	تنمو المصفوفة في الصنف <code>MyArrayList</code> -من التمرين المشار إليه- عند الضرورة، ولكنها لا تتقلص أبدًا، وبالتالي لا تُكنَس المصفوفة ولا يُكنَس أي من عناصرها حتى يحين موعد تدمير القائمة ذاتها. في المقابل، تتقلص القائمة المترابطة عند حذف العناصر منها، كما تُكنَس العقد غير المُستخدَمة مباشرةً، وهو ما يُمثِل واحدةً من مميزات هذا النوع من هياكل البيانات.
</p>

<p>
	انظر إلى تنفيذ التابع <code>clear</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_6685_37" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> clear</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        head </span><span class="pun">=</span><span class="pln"> null</span><span class="pun">;</span><span class="pln">
        size </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	عندما نضبُط قيمة الرأس <code>head</code> بالقيمة <code>null</code>، فإننا نحذف المرجع إلى العقدة الأولى. إذا لم تكن هناك أي مراجع أخرى إلى ذلك الكائن (من المفترض ألا يكون هناك أي مراجع أخرى)، فسيُكنَس الكائن مباشرةً. في تلك اللحظة، سيُحذَف المرجع إلى الكائن المُمثِل للعقدة الثانية، وبالتالي يُكنَس بدوره أيَضًا. وستستمر تلك العملية إلى أن تُكنَس جميع العقد.
</p>

<p>
	بناءً على ما سبق، ما هو تصنيف التابع <code>clear</code>؟ يتضمَّن التابع عمليتين ثابتتي الزمن، ويبدو لهذا كما لو أنه يستغرِق زمنًا ثابتًا، ولكنك عندما تستدعيه ستُحفزّ كانس المهملات على إجراء عملية تتناسب مع عدد العناصر، ولذلك ربما علينا أن نَعُدّه خطّيَّ الزمن.
</p>

<p>
	يُعدّ هذا مثالًا على ما نُسميه أحيانًا بـمشكلة برمجية في الأداء، أي أن البرنامج يفعل الشيء الصحيح، ولكنه لا ينتمي إلى ترتيب النمو المُتوقَّع. يَصعُب العثور على هذا النوع من الأخطاء خاصةً في اللغات التي تُنفِّذ أعمالًا كثيرةً وراء الكواليس مثل عملية كنس المهملات مثلاً، وتُعدّ لغة جافا واحدةً من تلك اللغات.
</p>

<p>
	ترجمة -بتصرّف- للفصل <a href="https://greenteapress.com/thinkdast/html/thinkdast004.html" rel="external nofollow">Chapter 3: ArrayList</a> من كتاب <a href="https://greenteapress.com/thinkdast/html/index.html" rel="external nofollow">Think Data Structures: Algorithms and Information Retrieval in Java</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D9%85%D8%AA%D8%B1%D8%A7%D8%A8%D8%B7%D8%A9-r1349/" rel="">تحليل زمن تشغيل القوائم المنفذة باستخدام قائمة مترابطة</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/advanced/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1345/" rel="">مدخل إلى تحليل الخوارزميات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advance/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D8%A7%D8%B2%D8%AF%D9%88%D8%A7%D8%AC%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B1%D8%A7%D8%A8%D8%B7-r1350/" rel="">تحليل زمن تشغيل القوائم المنفذة باستخدام قائمة ازدواجية الترابط</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advance/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D9%85%D8%AA%D8%B1%D8%A7%D8%A8%D8%B7%D8%A9-r1349/" rel="">تحليل زمن تشغيل القوائم المنفذة باستخدام قائمة مترابطة</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1348</guid><pubDate>Sun, 07 Nov 2021 16:01:00 +0000</pubDate></item><item><title>&#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x627;&#x644;&#x62E;&#x648;&#x627;&#x631;&#x632;&#x645;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x634;&#x631;&#x647;&#x629;</title><link>https://academy.hsoub.com/programming/advanced/%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D9%87%D8%A9-r1372/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_11/61933ff12e28e_-01.jpg.a12bdf3c61b57382ab7ff5085062c4c8.jpg" /></p>
<p>
	هذه المقالة هي تتمة <a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D9%87%D8%A9-greedy-algorithms-r1366/" rel="">للمقالة السابقة</a>، وفيها تجد عددًا من التطبيقات الحقيقية لل<a href="https://en.wikipedia.org/wiki/Greedy_algorithm" rel="external nofollow">خوارزميات الشَرِهَة</a> لحل بعض المشاكل، مثل تقليل التأخير وجدولة الوظائف وإدارة ذاكرة التخزين المؤقت.
</p>

<h2>
	التخزين المؤقت غير المتصل Offline Caching
</h2>

<p>
	تنشأ مشكلة التخزين المؤقت caching بسبب محدودية مساحة التخزين، فمثلًا لنفرض أن ذاكرةَ تخزينٍ مؤقتة ولتكن <code>C</code>، تحتوي على عدد <code>k</code> من الصفحات، ونريد معالجة سلسلة من العناصر عددها <code>m</code> عنصر، هنا يجب تخزين هذه العناصر في الذاكرة المؤقتة قبل معالجتها.
</p>

<p>
	لا شك أنه لن توجد مشكلة إن كانت <code>‎m&lt;=k‎</code>، إذ سنضع جميع العناصر في ذاكرة التخزين المؤقت، ولكن في العادة تكون <code>‎m&gt;&gt;k‎</code>.
</p>

<p>
	نقول أنّ طلبيّةً ما مقبولة في ذاكرة التخزين المؤقت cache hit إذا كان العنصر موجودًا في ذاكرة التخزين المؤقت فعليًا، وإلا سنقول أنّها مُفوَّتة عن ذاكرة التخزين المؤقت cache miss. سيكون علينا في مثل هذه الحالة إحضار العنصر المطلوب إلى ذاكرة التخزين المؤقت وإخراج عنصر آخر، وذلك بفرض أنّ ذاكرة التخزين المؤقت ممتلئة، وهدفنا هو تصميم جدول إخلاء eviction schedule يقلّل قدر الإمكان من عدد عمليات الإخلاء الضرورية.
</p>

<p>
	هناك عدة استراتيجيات شَرِهَة لحلّ هذه المشكلة، من بينها:
</p>

<ul>
	<li>
		أول داخل، أول خارج First in, ﬁrst out أو FIFO: تُخلى أقدم صفحة.
	</li>
	<li>
		آخر داخل، أوّل خارج Last in, ﬁrst out أو LIFO: تُخلى أحدث صفحة.
	</li>
	<li>
		خروج الأبكر وصولًا Last recent out أو اختصارا LRU: إخلاء الصفحة التي تمّ الدخول إليها في أبكر وقت.
	</li>
	<li>
		الأقل طلبًا Least frequently requested أو LFU: إخلاء الصفحة التي طُلِبت أقل عدد من المرات.
	</li>
	<li>
		أطول مسافة أمامية Longest forward distance أو LFD: إخلاء الصفحة التي ستُطلَب في أبعد مسافة في المستقبل.
	</li>
</ul>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<strong>تنبيه</strong>: في الأمثلة التالية، سنُخلى الصفحة ذات الفهرس الأصغر في حال كان بالإمكان إخلاء أكثر من صفحة واحدة.
	</p>
</blockquote>

<h3>
	مثال FIFO
</h3>

<p>
	لنفترض أنّ حجم ذاكرة التخزين المؤقت هو <code>‎k=3‎</code>، وأنّ ذاكرة التخزين المؤقت الأولية تحتوي <code>‎a,b,c‎</code>، وأنّ هناك قائمةً من الطلبيات هي على النحو الآتي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_3933_19" style=""><span class="pun">‎</span><span class="pln">a</span><span class="pun">,</span><span class="pln">a</span><span class="pun">,</span><span class="pln">d</span><span class="pun">,</span><span class="pln">e</span><span class="pun">,</span><span class="pln">b</span><span class="pun">,</span><span class="pln">b</span><span class="pun">,</span><span class="pln">a</span><span class="pun">,</span><span class="pln">c</span><span class="pun">,</span><span class="pln">f</span><span class="pun">,</span><span class="pln">d</span><span class="pun">,</span><span class="pln">e</span><span class="pun">,</span><span class="pln">a</span><span class="pun">,</span><span class="pln">f</span><span class="pun">,</span><span class="pln">b</span><span class="pun">,</span><span class="pln">e</span><span class="pun">,</span><span class="pln">c</span><span class="pun">‎</span><span class="pln">
</span></pre>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
	<thead>
		<tr>
			<th>
				الطلب
			</th>
			<th>
				a
			</th>
			<th>
				a
			</th>
			<th>
				d
			</th>
			<th>
				e
			</th>
			<th>
				b
			</th>
			<th>
				b
			</th>
			<th>
				a
			</th>
			<th>
				c
			</th>
			<th>
				f
			</th>
			<th>
				d
			</th>
			<th>
				e
			</th>
			<th>
				a
			</th>
			<th>
				f
			</th>
			<th>
				b
			</th>
			<th>
				e
			</th>
			<th>
				c
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				المخزن المؤقت 1
			</td>
			<td>
				a
			</td>
			<td>
				a
			</td>
			<td>
				d
			</td>
			<td>
				d
			</td>
			<td>
				d
			</td>
			<td>
				d
			</td>
			<td>
				a
			</td>
			<td>
				a
			</td>
			<td>
				a
			</td>
			<td>
				d
			</td>
			<td>
				d
			</td>
			<td>
				d
			</td>
			<td>
				f
			</td>
			<td>
				f
			</td>
			<td>
				f
			</td>
			<td>
				c
			</td>
		</tr>
		<tr>
			<td>
				المخزن المؤقت 2
			</td>
			<td>
				b
			</td>
			<td>
				b
			</td>
			<td>
				b
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				c
			</td>
			<td>
				c
			</td>
			<td>
				c
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				b
			</td>
			<td>
				b
			</td>
			<td>
				b
			</td>
		</tr>
		<tr>
			<td>
				المخزن المؤقت 3
			</td>
			<td>
				c
			</td>
			<td>
				c
			</td>
			<td>
				c
			</td>
			<td>
				c
			</td>
			<td>
				b
			</td>
			<td>
				b
			</td>
			<td>
				b
			</td>
			<td>
				b
			</td>
			<td>
				f
			</td>
			<td>
				f
			</td>
			<td>
				f
			</td>
			<td>
				a
			</td>
			<td>
				a
			</td>
			<td>
				a
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
		</tr>
		<tr>
			<td>
				الحالات المفوَّتة
			</td>
			<td>
				 
			</td>
			<td>
				 
			</td>
			<td>
				x
			</td>
			<td>
				x
			</td>
			<td>
				x
			</td>
			<td>
				 
			</td>
			<td>
				x
			</td>
			<td>
				x
			</td>
			<td>
				x
			</td>
			<td>
				x
			</td>
			<td>
				x
			</td>
			<td>
				x
			</td>
			<td>
				x
			</td>
			<td>
				x
			</td>
			<td>
				x
			</td>
			<td>
				x
			</td>
		</tr>
	</tbody>
</table>

<p>
	فوّتنا ثلاثة عشرة عنصرًا من ذاكرة التخزين المؤقت من بين ستة عشر طلبية، وهو أمر لا يبدو جيدًا، لذلك من الأحسن أن نجرّب استراتيجيةً أخرى.
</p>

<h3>
	مثال LFD
</h3>

<p>
	لنفترض أنّ حجم ذاكرة التخزين المؤقت هو <code>‎k=3‎</code>، وأنّ ذاكرة التخزين المؤقت الأولية تحتوي <code>‎a,b,c‎</code>؛ أما الطلبيات فهي:
</p>

<table>
	<thead>
		<tr>
			<th>
				الطلب
			</th>
			<th>
				a
			</th>
			<th>
				a
			</th>
			<th>
				d
			</th>
			<th>
				e
			</th>
			<th>
				b
			</th>
			<th>
				b
			</th>
			<th>
				a
			</th>
			<th>
				c
			</th>
			<th>
				f
			</th>
			<th>
				d
			</th>
			<th>
				e
			</th>
			<th>
				a
			</th>
			<th>
				f
			</th>
			<th>
				b
			</th>
			<th>
				e
			</th>
			<th>
				c
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				المخزن المؤقت 1
			</td>
			<td>
				a
			</td>
			<td>
				a
			</td>
			<td>
				d
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				e
			</td>
			<td>
				c
			</td>
		</tr>
		<tr>
			<td>
				المخزن المؤقت 2
			</td>
			<td>
				b
			</td>
			<td>
				b
			</td>
			<td>
				b
			</td>
			<td>
				b
			</td>
			<td>
				b
			</td>
			<td>
				b
			</td>
			<td>
				a
			</td>
			<td>
				a
			</td>
			<td>
				a
			</td>
			<td>
				a
			</td>
			<td>
				a
			</td>
			<td>
				a
			</td>
			<td>
				f
			</td>
			<td>
				f
			</td>
			<td>
				f
			</td>
			<td>
				f
			</td>
		</tr>
		<tr>
			<td>
				المخزن المؤقت 3
			</td>
			<td>
				c
			</td>
			<td>
				c
			</td>
			<td>
				c
			</td>
			<td>
				c
			</td>
			<td>
				c
			</td>
			<td>
				c
			</td>
			<td>
				c
			</td>
			<td>
				c
			</td>
			<td>
				f
			</td>
			<td>
				d
			</td>
			<td>
				d
			</td>
			<td>
				d
			</td>
			<td>
				d
			</td>
			<td>
				b
			</td>
			<td>
				b
			</td>
			<td>
				b
			</td>
		</tr>
		<tr>
			<td>
				الحالات المفوَّتة
			</td>
			<td>
				 
			</td>
			<td>
				 
			</td>
			<td>
				x
			</td>
			<td>
				x
			</td>
			<td>
				 
			</td>
			<td>
				 
			</td>
			<td>
				x
			</td>
			<td>
				 
			</td>
			<td>
				x
			</td>
			<td>
				x
			</td>
			<td>
				 
			</td>
			<td>
				 
			</td>
			<td>
				x
			</td>
			<td>
				x
			</td>
			<td>
				 
			</td>
			<td>
				x
			</td>
		</tr>
	</tbody>
</table>

<p>
	فوّتنا ثمانيةً هذه المرة، وهذا أفضل بكثير.
</p>

<h3>
	تمرين
</h3>

<p>
	جرّب استراتيجيات LIFO وLFU وRFU على المثال، وانظر إلى ما يحدث.
</p>

<p>
	يتكون البرنامج التوضيحي التالي (مكتوب بلغة C++‎) من جزأين، حيث أن الأول هو هيكل البرنامج، ويحلّ المشكلة اعتمادًا على استراتيجية الشَرِههَ المختارة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3933_21" style=""><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;iostream&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;memory&gt;</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="kwd">namespace</span><span class="pln"> std</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> cacheSize     </span><span class="pun">=</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> requestLength </span><span class="pun">=</span><span class="pln"> </span><span class="lit">16</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="kwd">char</span><span class="pln"> request</span><span class="pun">[]</span><span class="pln">    </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'a'</span><span class="pun">,</span><span class="str">'a'</span><span class="pun">,</span><span class="str">'d'</span><span class="pun">,</span><span class="str">'e'</span><span class="pun">,</span><span class="str">'b'</span><span class="pun">,</span><span class="str">'b'</span><span class="pun">,</span><span class="str">'a'</span><span class="pun">,</span><span class="str">'c'</span><span class="pun">,</span><span class="str">'f'</span><span class="pun">,</span><span class="str">'d'</span><span class="pun">,</span><span class="str">'e'</span><span class="pun">,</span><span class="str">'a'</span><span class="pun">,</span><span class="str">'f'</span><span class="pun">,</span><span class="str">'b'</span><span class="pun">,</span><span class="str">'e'</span><span class="pun">,</span><span class="str">'c'</span><span class="pun">};</span><span class="pln">
</span><span class="kwd">char</span><span class="pln"> cache</span><span class="pun">[]</span><span class="pln">            </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'a'</span><span class="pun">,</span><span class="str">'b'</span><span class="pun">,</span><span class="str">'c'</span><span class="pun">};</span><span class="pln">
</span><span class="com">// for reset</span><span class="pln">
</span><span class="kwd">char</span><span class="pln"> originalCache</span><span class="pun">[]</span><span class="pln">    </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="str">'a'</span><span class="pun">,</span><span class="str">'b'</span><span class="pun">,</span><span class="str">'c'</span><span class="pun">};</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Strategy</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">public</span><span class="pun">:</span><span class="pln">
   </span><span class="typ">Strategy</span><span class="pun">(</span><span class="pln">std</span><span class="pun">::</span><span class="pln">string name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> strategyName</span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{}</span><span class="pln">
   </span><span class="kwd">virtual</span><span class="pln"> </span><span class="pun">~</span><span class="typ">Strategy</span><span class="pun">()</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">default</span><span class="pun">;</span><span class="pln">
   </span><span class="com">// احسب موضع التخزين المؤقت الذي ينبغي  أن يُستخدم</span><span class="pln">
   </span><span class="kwd">virtual</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> apply</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> requestIndex</span><span class="pun">)</span><span class="pln">     </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
   </span><span class="com">// حدّث المعلومات التي تحتاجها الاستراتيجية</span><span class="pln">
   </span><span class="kwd">virtual</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> update</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> cachePlace</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> requestIndex</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">bool</span><span class="pln"> cacheMiss</span><span class="pun">)</span><span class="pln">    </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
   </span><span class="kwd">const</span><span class="pln"> std</span><span class="pun">::</span><span class="pln">string strategyName</span><span class="pun">;</span><span class="pln">
</span><span class="pun">};</span><span class="pln">
</span><span class="kwd">bool</span><span class="pln"> updateCache</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> requestIndex</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Strategy</span><span class="pun">*</span><span class="pln"> strategy</span><span class="pun">)</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="com">// حدد مكان وضع الطلب</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> cachePlace </span><span class="pun">=</span><span class="pln"> strategy</span><span class="pun">-&gt;</span><span class="pln">apply</span><span class="pun">(</span><span class="pln">requestIndex</span><span class="pun">);</span><span class="pln">
   </span><span class="com">// تحقق مما إذا قُبِل التخزين المؤقت أم لا</span><span class="pln">
   </span><span class="kwd">bool</span><span class="pln"> isMiss </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">[</span><span class="pln">requestIndex</span><span class="pun">]</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> cache</span><span class="pun">[</span><span class="pln">cachePlace</span><span class="pun">];</span><span class="pln">
   </span><span class="com">// تحديث الاستراتيجية - مثلا: إعادة حساب المسافات</span><span class="pln">
   strategy</span><span class="pun">-&gt;</span><span class="pln">update</span><span class="pun">(</span><span class="pln">cachePlace</span><span class="pun">,</span><span class="pln"> requestIndex</span><span class="pun">,</span><span class="pln"> isMiss</span><span class="pun">);</span><span class="pln">
   </span><span class="com">//الكتابة في ذاكرة التخزين المؤقت</span><span class="pln">
   cache</span><span class="pun">[</span><span class="pln">cachePlace</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> request</span><span class="pun">[</span><span class="pln">requestIndex</span><span class="pun">];</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> isMiss</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="typ">Strategy</span><span class="pun">*</span><span class="pln"> selectedStrategy</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> FIFO</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> LIFO</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> LRU</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> LFU</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> LFD </span><span class="pun">};</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> strat</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> strat </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">5</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">strat</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="com">//إعادة تعيين المخزن المؤقت </span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> cache</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> originalCache</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
       cout </span><span class="pun">&lt;&lt;</span><span class="str">"\nStrategy: "</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> selectedStrategy</span><span class="pun">[</span><span class="pln">strat</span><span class="pun">]-&gt;</span><span class="pln">strategyName </span><span class="pun">&lt;&lt;</span><span class="pln"> endl</span><span class="pun">;</span><span class="pln">
       cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"\nCache initial: ("</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> cacheSize</span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> cout </span><span class="pun">&lt;&lt;</span><span class="pln"> cache</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">","</span><span class="pun">;</span><span class="pln">
       cout </span><span class="pun">&lt;&lt;</span><span class="pln"> cache</span><span class="pun">[</span><span class="pln">cacheSize</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">")\n\n"</span><span class="pun">;</span><span class="pln">
       cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"Request\t"</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"cache "</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> i </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"\t"</span><span class="pun">;</span><span class="pln">
       cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"cache miss"</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> endl</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> cntMisses </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">requestLength</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">bool</span><span class="pln"> isMiss </span><span class="pun">=</span><span class="pln"> updateCache</span><span class="pun">(</span><span class="pln">i</span><span class="pun">,</span><span class="pln"> selectedStrategy</span><span class="pun">[</span><span class="pln">strat</span><span class="pun">]);</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isMiss</span><span class="pun">)</span><span class="pln"> </span><span class="pun">++</span><span class="pln">cntMisses</span><span class="pun">;</span><span class="pln">
           cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"  "</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> request</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"\t"</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> l</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> l </span><span class="pun">&lt;</span><span class="pln"> cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">l</span><span class="pun">)</span><span class="pln"> cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"  "</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> cache</span><span class="pun">[</span><span class="pln">l</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"\t"</span><span class="pun">;</span><span class="pln">
           cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="pun">(</span><span class="pln">isMiss </span><span class="pun">?</span><span class="pln"> </span><span class="str">"x"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">""</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> endl</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       cout</span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"\nTotal cache misses: "</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> cntMisses </span><span class="pun">&lt;&lt;</span><span class="pln"> endl</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="lit">5</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">delete</span><span class="pln"> selectedStrategy</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الفكرة الأساسية بسيطة، حيث نستدعي الاستراتيجية مرتين لكل طلب:
</p>

<ul>
	<li>
		التطبيق apply: يجب أن تخبر الاستراتيجية المستدعي بالصفحة التي يجب استخدامها.
	</li>
	<li>
		التحديث update: بعد أن يستخدم المستدعي المساحة، يخبر الإستراتيجية ما إذا تمّ تفويته أم لا. ثمّ تستطيع الاستراتيجية حينها تحديث بياناتها الداخلية. فمثلًا، على الاستراتيجية LFU تحديث تردّد القبول hit frequency لصفحات ذاكرة التخزين المؤقت، بينما تعيد استراتيجية LFD حساب مسافات صفحات ذاكرة التخزين المؤقت.
	</li>
</ul>

<p>
	نقدّم الآن تطبيقات للاستراتيجيات الخمس:
</p>

<ul>
	<li>
		FIFO
	</li>
</ul>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_3933_29" style=""><span class="kwd">class</span><span class="pln"> FIFO </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Strategy</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">public</span><span class="pun">:</span><span class="pln">
   FIFO</span><span class="pun">()</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Strategy</span><span class="pun">(</span><span class="str">"FIFO"</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> age</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">int</span><span class="pln"> apply</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> requestIndex</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">override</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">int</span><span class="pln"> oldest </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">cache</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> request</span><span class="pun">[</span><span class="pln">requestIndex</span><span class="pun">])</span><span class="pln">
               </span><span class="kwd">return</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">age</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> age</span><span class="pun">[</span><span class="pln">oldest</span><span class="pun">])</span><span class="pln">
               oldest </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> oldest</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">void</span><span class="pln"> update</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> cachePos</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> requestIndex</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">bool</span><span class="pln"> cacheMiss</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">override</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="com">// لم يتغير أي شيء، لسنا بحاجة إلى تحديث الصفحات</span><span class="pln">
</span><span class="kwd">if</span><span class="pun">(!</span><span class="pln">cacheMiss</span><span class="pun">)</span><span class="pln">
           </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
       </span><span class="com">// كل الصفحات القديمة تُصبح أقدم، والجديدة تحصل على القيمة 0</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">i </span><span class="pun">!=</span><span class="pln"> cachePos</span><span class="pun">)</span><span class="pln">
               age</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]++;</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln">
               age</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="kwd">private</span><span class="pun">:</span><span class="pln">
   </span><span class="kwd">int</span><span class="pln"> age</span><span class="pun">[</span><span class="pln">cacheSize</span><span class="pun">];</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	لا تحتاج FIFO إلا إلى المعلومات المتعلقة بطول الصفحة في ذاكرة التخزين المؤقت (نسبة إلى الصفحات الأخرى)، لذا فهي تكتفي بانتظار حدوث فوات miss، ثم تجعل الصفحات التي لم تُخلى أقدم.
</p>

<p>
	بالنسبة للمثال أعلاه، فسيكون الحل كالتالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_2679_7" style=""><span class="typ">Strategy</span><span class="pun">:</span><span class="pln"> FIFO
</span><span class="typ">Cache</span><span class="pln"> initial</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln">b</span><span class="pun">,</span><span class="pln">c</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Request</span><span class="pln">          cache </span><span class="lit">0</span><span class="pln">        cache </span><span class="lit">1</span><span class="pln">        cache </span><span class="lit">2</span><span class="pln">    cache miss
  a                  a              b              c    
  a                  a              b              c    
  d                  d              b              c              x
  e                  d              e              c              x
  b                  d              e              b              x
  b                  d              e              b    
  a                  a              e              b              x
  c                  a              c              b              x
  f                  a              c              f              x
  d                  d              c              f              x
  e                  d              e              f              x
  a                  d              e              a              x
  f                  f              e              a              x
  b                  f              b              a              x
  e                  f              b              e              x
  c                  c              b              e              x
</span><span class="typ">Total</span><span class="pln"> cache misses</span><span class="pun">:</span><span class="pln"> </span><span class="lit">13</span><span class="pln"> </span><span class="pun">العدد</span><span class="pln"> </span><span class="pun">الإجمالي</span><span class="pln"> </span><span class="pun">للفوات</span></pre>

<p>
	وهذا يكافئ الحل أعلاه.
</p>

<ul>
	<li>
		LIFO
	</li>
</ul>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3933_35" style=""><span class="kwd">class</span><span class="pln"> LIFO </span><span class="pun">:</span><span class="pln"> public </span><span class="typ">Strategy</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
public</span><span class="pun">:</span><span class="pln">
   LIFO</span><span class="pun">()</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Strategy</span><span class="pun">(</span><span class="str">"LIFO"</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">int i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> age</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   int apply</span><span class="pun">(</span><span class="pln">int requestIndex</span><span class="pun">)</span><span class="pln"> override
   </span><span class="pun">{</span><span class="pln">
       int newest </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">for</span><span class="pun">(</span><span class="pln">int i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">cache</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> request</span><span class="pun">[</span><span class="pln">requestIndex</span><span class="pun">])</span><span class="pln">
               </span><span class="kwd">return</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">age</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> age</span><span class="pun">[</span><span class="pln">newest</span><span class="pun">])</span><span class="pln">
               newest </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> newest</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   void update</span><span class="pun">(</span><span class="pln">int cachePos</span><span class="pun">,</span><span class="pln"> int requestIndex</span><span class="pun">,</span><span class="pln"> bool cacheMiss</span><span class="pun">)</span><span class="pln"> override
   </span><span class="pun">{</span><span class="pln">
       </span><span class="pun">//</span><span class="pln"> </span><span class="pun">لم</span><span class="pln"> </span><span class="pun">يتغير</span><span class="pln"> </span><span class="pun">شيء،</span><span class="pln"> </span><span class="pun">لا</span><span class="pln"> </span><span class="pun">نحتاج</span><span class="pln"> </span><span class="pun">إلى</span><span class="pln"> </span><span class="pun">تحديث</span><span class="pln"> </span><span class="pun">الصفحات</span><span class="pln">
       </span><span class="kwd">if</span><span class="pun">(!</span><span class="pln">cacheMiss</span><span class="pun">)</span><span class="pln">
           </span><span class="kwd">return</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">//</span><span class="pln"> </span><span class="pun">كل</span><span class="pln"> </span><span class="pun">الصفحات</span><span class="pln"> </span><span class="pun">القديمة</span><span class="pln"> </span><span class="pun">تُصبح</span><span class="pln"> </span><span class="pun">أقدم،</span><span class="pln"> </span><span class="pun">والصفحة</span><span class="pln"> </span><span class="pun">الجديدة</span><span class="pln"> </span><span class="pun">تحصل</span><span class="pln"> </span><span class="pun">على</span><span class="pln"> </span><span class="pun">القيمة</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="pln">int i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">i </span><span class="pun">!=</span><span class="pln"> cachePos</span><span class="pun">)</span><span class="pln">
               age</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]++;</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln">
               age</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
private</span><span class="pun">:</span><span class="pln">
   int age</span><span class="pun">[</span><span class="pln">cacheSize</span><span class="pun">];</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	تقديم LIFO مشابه إلى حد ما لتقديم FIFO، بيْد أنّنا نخلي الصفحة الأحدث وليس الأقدم. ستكون نتائج البرنامج كالتالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_146_8" style=""><span class="typ">Strategy</span><span class="pun">:</span><span class="pln"> LIFO
</span><span class="typ">Cache</span><span class="pln"> initial</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln">b</span><span class="pun">,</span><span class="pln">c</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Request</span><span class="pln">            cache </span><span class="lit">0</span><span class="pln">       cache </span><span class="lit">1</span><span class="pln">    cache </span><span class="lit">2</span><span class="pln">    cache miss
 a                   a              b          c   
 a                   a              b          c   
 d                   d              b          c          x
 e                   e              b          c          x
 b                   e              b          c   
 b                   e              b          c   
 a                   a              b          c          x
 c                   a              b          c   
 f                   f              b          c          x
 d                   d              b          c          x
 e                   e              b          c          x
 a                   a              b          c          x
 f                   f              b          c          x
 b                   f              b          c   
 e                   e              b          c          x
 c                   e              b          c   

</span><span class="typ">Total</span><span class="pln"> cache misses</span><span class="pun">:</span><span class="pln"> </span><span class="lit">9</span><span class="pln"> </span><span class="pun">العدد</span><span class="pln"> </span><span class="pun">الإجمالي</span><span class="pln"> </span><span class="pun">لحالات</span><span class="pln"> </span><span class="pun">الفوات</span></pre>

<ul>
	<li>
		LRU، سنستخدم كلمة <code>oldest</code> في المثال أدناه للإشارة إلى طول فترة "عدم" الاستخدام.
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3933_39" style=""><span class="kwd">class</span><span class="pln"> LRU </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Strategy</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">public</span><span class="pun">:</span><span class="pln">
   LRU</span><span class="pun">()</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Strategy</span><span class="pun">(</span><span class="str">"LRU"</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> age</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">

        </span><span class="typ">int</span><span class="pln"> apply</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> requestIndex</span><span class="pun">)</span><span class="pln"> override
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> oldest </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">cache</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> request</span><span class="pun">[</span><span class="pln">requestIndex</span><span class="pun">])</span><span class="pln">
               </span><span class="kwd">return</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">age</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> age</span><span class="pun">[</span><span class="pln">oldest</span><span class="pun">])</span><span class="pln">
               oldest </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> oldest</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">void</span><span class="pln"> update</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> cachePos</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> requestIndex</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">bool</span><span class="pln"> cacheMiss</span><span class="pun">)</span><span class="pln"> override
   </span><span class="pun">{</span><span class="pln">
       </span><span class="com">// الصفحات القديمة تصبح أقدم، والصفحة الجديدة تأخذ القيمة 0</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">i </span><span class="pun">!=</span><span class="pln"> cachePos</span><span class="pun">)</span><span class="pln">
               age</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]++;</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln">
               age</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="kwd">private</span><span class="pun">:</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> age</span><span class="pun">[</span><span class="pln">cacheSize</span><span class="pun">];</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	في حالة LRU، فإن الاستراتيجية مستقلة عن صفحة ذاكرة التخزين المؤقت، إذ أنّ تركيزها ينصبّ على الصفحة الأخيرة فقط.
</p>

<p>
	نتائج البرنامج هي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_146_10" style=""><span class="typ">Strategy</span><span class="pun">:</span><span class="pln"> LRU
</span><span class="typ">Cache</span><span class="pln"> initial</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln">b</span><span class="pun">,</span><span class="pln">c</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Request</span><span class="pln">            cache </span><span class="lit">0</span><span class="pln">        cache </span><span class="lit">1</span><span class="pln">         cache </span><span class="lit">2</span><span class="pln">    cache miss
  a                   a              b              c    
  a                   a              b              c    
  d                   a              d              c              x
  e                   a              d              e              x
  b                   b              d              e              x
  b                   b              d              e    
  a                   b              a              e              x
  c                   b              a              c              x
  f                   f              a              c              x
  d                   f              d              c              x
  e                   f              d              e              x
  a                   a              d              e              x
  f                   a              f              e              x
  b                   a              f              b              x
  e                   e              f              b              x
  c                   e              c              b              x
</span><span class="typ">Total</span><span class="pln"> cache misses</span><span class="pun">:</span><span class="pln"> </span><span class="lit">13</span><span class="pln"> </span><span class="pun">العدد</span><span class="pln"> </span><span class="pun">الإجمالي</span><span class="pln"> </span><span class="pun">لحالات</span><span class="pln"> </span><span class="pun">الفوات</span></pre>

<ul>
	<li>
		LFU:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3933_43" style=""><span class="kwd">class</span><span class="pln"> LFU </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Strategy</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">public</span><span class="pun">:</span><span class="pln">
   LFU</span><span class="pun">()</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Strategy</span><span class="pun">(</span><span class="str">"LFU"</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> requestFrequency</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> apply</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> requestIndex</span><span class="pun">)</span><span class="pln"> override
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> least </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">cache</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> request</span><span class="pun">[</span><span class="pln">requestIndex</span><span class="pun">])</span><span class="pln">
               </span><span class="kwd">return</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">requestFrequency</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> requestFrequency</span><span class="pun">[</span><span class="pln">least</span><span class="pun">])</span><span class="pln">
               least </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> least</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">void</span><span class="pln"> update</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> cachePos</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> requestIndex</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">bool</span><span class="pln"> cacheMiss</span><span class="pun">)</span><span class="pln"> override
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">cacheMiss</span><span class="pun">)</span><span class="pln">
           requestFrequency</span><span class="pun">[</span><span class="pln">cachePos</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">else</span><span class="pln">
           </span><span class="pun">++</span><span class="pln">requestFrequency</span><span class="pun">[</span><span class="pln">cachePos</span><span class="pun">];</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="kwd">private</span><span class="pun">:</span><span class="pln">
   </span><span class="com">// ما هو تردد استخدام الصفحة</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> requestFrequency</span><span class="pun">[</span><span class="pln">cacheSize</span><span class="pun">];</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	تُخلي LFU الصفحة الأقل استخدامًا، لذا تعتمد استراتيجية التحديث على عدد مرّات الوصول إلى الصفحات. وبالطبع، يُصفَّر العدّاد بعد الإخلاء، وهذه نتائج البرنامج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_146_13" style=""><span class="typ">Strategy</span><span class="pun">:</span><span class="pln"> LFU
</span><span class="typ">Cache</span><span class="pln"> initial</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln">b</span><span class="pun">,</span><span class="pln">c</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Request</span><span class="pln">          cache </span><span class="lit">0</span><span class="pln">         cache </span><span class="lit">1</span><span class="pln">        cache </span><span class="lit">2</span><span class="pln">    cache miss
  a                  a              b              c    
  a                  a              b              c    
  d                  a              d              c              x
  e                  a              d              e              x
  b                  a              b              e              x
  b                  a              b              e    
  a                  a              b              e    
  c                  a              b              c              x
  f                  a              b              f              x
  d                  a              b              d              x
  e                  a              b              e              x
  a                  a              b              e    
  f                  a              b              f              x
  b                  a              b              f    
  e                  a              b              e              x
  c                  a              b              c              x
</span><span class="typ">Total</span><span class="pln"> cache misses</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10</span></pre>

<ul>
	<li>
		LFD:
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3933_47" style=""><span class="kwd">class</span><span class="pln"> LFD </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">Strategy</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">public</span><span class="pun">:</span><span class="pln">
   LFD</span><span class="pun">()</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Strategy</span><span class="pun">(</span><span class="str">"LFD"</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="com">// الحساب المُسبق للاستخدام اللاحق قبل تلبية الطلبات</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> nextUse</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> calcNextUse</span><span class="pun">(-</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> cache</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> apply</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> requestIndex</span><span class="pun">)</span><span class="pln"> override
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> latest </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">cacheSize</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">cache</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> request</span><span class="pun">[</span><span class="pln">requestIndex</span><span class="pun">])</span><span class="pln">
               </span><span class="kwd">return</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">nextUse</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> nextUse</span><span class="pun">[</span><span class="pln">latest</span><span class="pun">])</span><span class="pln">
               latest </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> latest</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">void</span><span class="pln"> update</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> cachePos</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> requestIndex</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">bool</span><span class="pln"> cacheMiss</span><span class="pun">)</span><span class="pln"> override
   </span><span class="pun">{</span><span class="pln">
           nextUse</span><span class="pun">[</span><span class="pln">cachePos</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> calcNextUse</span><span class="pun">(</span><span class="pln">requestIndex</span><span class="pun">,</span><span class="pln"> cache</span><span class="pun">[</span><span class="pln">cachePos</span><span class="pun">]);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="kwd">private</span><span class="pun">:</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> calcNextUse</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> requestPosition</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">char</span><span class="pln"> pageItem</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> requestPosition</span><span class="pun">+</span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> requestLength</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">request</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> pageItem</span><span class="pun">)</span><span class="pln">
               </span><span class="kwd">return</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> requestLength </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="com">// الاستخدام اللاحق للصفحة</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> nextUse</span><span class="pun">[</span><span class="pln">cacheSize</span><span class="pun">];</span><span class="pln">
</span><span class="pun">};</span></pre>

<p>
	تختلف استراتيجية LFD عن جميع ما قبلها، فهي الاستراتيجية الوحيدة التي تستخدم الطلبات المستقبلية لاتخاذ القرار بخصوص الصفحة التي ينبغي أن تُخلى. يَستخدم التطبيق دالة <code>‎calcNextUse‎</code> للحصول على الصفحة التي يكون استخدَامها التالي هو الأبعد في المستقبل.
</p>

<p>
	الحل الذي يعطيه البرنامج يساوي الحل اليدوي الذي وجدناه أعلاه:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_146_15" style=""><span class="typ">Strategy</span><span class="pun">:</span><span class="pln"> LFD
</span><span class="typ">Cache</span><span class="pln"> initial</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln">b</span><span class="pun">,</span><span class="pln">c</span><span class="pun">)</span><span class="pln">
</span><span class="typ">Request</span><span class="pln">            cache </span><span class="lit">0</span><span class="pln">       cache </span><span class="lit">1</span><span class="pln">       cache </span><span class="lit">2</span><span class="pln">       cache miss
  a                  a              b              c    
  a                  a              b              c    
  d                  a              b              d              x
  e                  a              b              e              x
  b                  a              b              e    
  b                  a              b              e    
  a                  a              b              e    
  c                  a              c              e              x
  f                  a              f              e              x
  d                  a              d              e              x
  e                  a              d              e    
  a                  a              d              e    
  f                  f              d              e              x
  b                  b              d              e              x
  e                  b              d              e    
  c                  c              d              e              x
</span><span class="typ">Total</span><span class="pln"> cache misses</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8</span></pre>

<p>
	استراتيجية LFD الشَرِهَة هي الاستراتيجية المثلى من بين الاستراتيجيات الخمس المقدمة، لكن هناك مشكلة كبيرة، فهي حل مثالي غير متصل optimal oﬄine solution، أي أنّها تتطلب قراءة جميع عناصر الطابور مرّةً واحدة؛ لكن عند التطبيق، سيكون التخزين المؤقت غالبًا مشكلة متصلة online، أي لا يمكنك أن تعرف من العناصر غير السابقة وحدها، وهذا يعني أنّ هذه الاستراتيجية غير مجدية لأننا لا نستطيع معرفة الموعد القادم الذي سنحتاج فيه إلى عنصر معيّن؛ أما الاستراتيجيات الأربع الأخرى فهي متصلة أيضًا. وبالنسبة للمشاكل المتصلة online، سنحتاج إلى منظور مختلف.
</p>

<h2>
	جهاز التذاكر
</h2>

<p>
	لنفترض أنّ لدينا جهاز تذاكر يصرّف المبالغ بقطع نقدية تحمل القيم 1 و2 و5 و10 و20. يمكن النظر إلى عملية الصرف مثل سلسلة من القطع النقدية التي تتساقط حتى يُستوفى المبلغ الصحيح، ونقول أنّ الصرف مثالي حين يكون عدد القطع النقدية أقل ما يمكن بالنسبة إلى قيمته.
</p>

<p>
	وإذا كانت <code>‎M‎</code> توجد بين <code>‎[1,50]‎</code> وتمثّل سعر التذكرة <code>‎T‎</code>، و العدد <code>‎P‎</code> الموجود بين <code>‎[1,50]‎</code> يمثل المبلغ المالي المدفوع مقابل التذكرة <code>‎T‎</code>، حيث <code>‎P &gt;= M‎</code>؛ فإننا نكتب <code>‎D=P-M‎</code>، ونعرّف الفائدة beneﬁt لخطوة معيّنة على أنّها الفرق بين <code>‎D‎</code> و<code>‎D-c‎</code>، حيث تمثّل<code>‎c‎</code> القطعة النقدية التي أضافها الجهاز في هذه الخطوة.
</p>

<p>
	انظر إلى الخوارزمية الشَرِهَة التوضيحية لإجراء عملية الصرف:
</p>

<ul>
	<li>
		الخطوة 1: إذا كانت <code>‎D &gt; 20‎</code>، أضف القطعة 20، وعيّن <code>‎D = D - 20‎</code>.
	</li>
	<li>
		الخطوة 2: إذا كانت <code>‎D &gt; 10‎</code>، أضف القطعة 10 وعيّن <code>‎D = D - 10‎</code>.
	</li>
	<li>
		الخطوة 3: إذا كانت <code>‎D &gt; 5‎</code>، أضف القطعة 5 وعيّن <code>‎D = D - 5‎</code>.
	</li>
	<li>
		الخطوة 4: إذا كانت <code>‎D &gt; 2‎</code>، أضف القطعة 2 وعيّن <code>‎D = D - 2‎</code>.
	</li>
	<li>
		الخطوة 5: إذا كانت <code>‎D &gt; 1‎</code>، أضف القطعة 1 وعيّن <code>‎D = D - 1‎</code>.
	</li>
</ul>

<p>
	بعد ذلك سيكون مجموع جميع العملات مساويًا القيمة <code>‎D‎</code>. هذه الخوارزمية شَرِهَة لأنّها تبحث بعد كل خطوة وبعد كل تكرار عن تعظيم الفائدة.
</p>

<p>
	والآن، لنكتب برنامج التذكرة بلغة C++‎‎‎:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3933_15" style=""><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;iostream&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;vector&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;string&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;algorithm&gt;</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="kwd">namespace</span><span class="pln"> std</span><span class="pun">;</span><span class="pln">
</span><span class="com">// اقرأ قيم بعض القطع النقدية، ورتّبها تنازليا</span><span class="pln">
</span><span class="com">// احذف النسخ مع ضمان أن تكون القطعة 1 موجودة بينها</span><span class="pln">
std</span><span class="pun">::</span><span class="typ">vector</span><span class="pun">&lt;</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="typ">int</span><span class="pun">&gt;</span><span class="pln"> readInCoinValues</span><span class="pun">();</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   std</span><span class="pun">::</span><span class="typ">vector</span><span class="pun">&lt;</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="typ">int</span><span class="pun">&gt;</span><span class="pln"> coinValues</span><span class="pun">;</span><span class="pln">   </span><span class="com">//  مصفوفة القطع النقدية تنازليا  </span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> ticketPrice</span><span class="pun">;</span><span class="pln">                        </span><span class="com">// في المثال M</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> paidMoney</span><span class="pun">;</span><span class="pln">                          </span><span class="com">// في المثال P</span><span class="pln">

   </span><span class="com">// ولِّد قيم القطع النقدية</span><span class="pln">
   coinValues </span><span class="pun">=</span><span class="pln"> readInCoinValues</span><span class="pun">();</span><span class="pln">

   cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"ticket price: "</span><span class="pun">;</span><span class="pln">
   cin </span><span class="pun">&gt;&gt;</span><span class="pln"> ticketPrice</span><span class="pun">;</span><span class="pln">

   cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"money paid: "</span><span class="pun">;</span><span class="pln">
   cin </span><span class="pun">&gt;&gt;</span><span class="pln"> paidMoney</span><span class="pun">;</span><span class="pln">

   </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">paidMoney </span><span class="pun">&lt;=</span><span class="pln"> ticketPrice</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"No exchange money"</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> endl</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">

   </span><span class="typ">int</span><span class="pln"> diffValue </span><span class="pun">=</span><span class="pln"> paidMoney </span><span class="pun">-</span><span class="pln"> ticketPrice</span><span class="pun">;</span><span class="pln">

   </span><span class="com">// هنا تبدأ الخوارزمية الشَرِهَة.</span><span class="pln">
   </span><span class="com">// نحفظ عدد القطع النقدية التي علينا إعطاؤها</span><span class="pln">
   std</span><span class="pun">::</span><span class="typ">vector</span><span class="pun">&lt;</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="typ">int</span><span class="pun">&gt;</span><span class="pln"> coinCount</span><span class="pun">;</span><span class="pln">

   </span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">auto</span><span class="pln"> coinValue  </span><span class="pun">=</span><span class="pln"> coinValues</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">();</span><span class="pln">
            coinValue </span><span class="pun">!=</span><span class="pln"> coinValues</span><span class="pun">.</span><span class="pln">end</span><span class="pun">();</span><span class="pln"> </span><span class="pun">++</span><span class="pln">coinValue</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> countCoins </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

       </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">diffValue </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="pun">*</span><span class="pln">coinValue</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           diffValue </span><span class="pun">-=</span><span class="pln"> </span><span class="pun">*</span><span class="pln">coinValue</span><span class="pun">;</span><span class="pln">
           countCoins</span><span class="pun">++;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">

       coinCount</span><span class="pun">.</span><span class="pln">push_back</span><span class="pun">(</span><span class="pln">countCoins</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">

   </span><span class="com">// اطبع النتائج</span><span class="pln">
   cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"the difference "</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> paidMoney </span><span class="pun">-</span><span class="pln"> ticketPrice
        </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">" is paid with: "</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> endl</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> coinValues</span><span class="pun">.</span><span class="pln">size</span><span class="pun">();</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">coinCount</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
           cout </span><span class="pun">&lt;&lt;</span><span class="pln"> coinCount</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">" coins with value "</span><span class="pln">
                </span><span class="pun">&lt;&lt;</span><span class="pln"> coinValues</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> endl</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">

   </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
std</span><span class="pun">::</span><span class="typ">vector</span><span class="pun">&lt;</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="typ">int</span><span class="pun">&gt;</span><span class="pln"> readInCoinValues</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="com">// قيم القطع النقدية</span><span class="pln">
   std</span><span class="pun">::</span><span class="typ">vector</span><span class="pun">&lt;</span><span class="kwd">unsigned</span><span class="pln"> </span><span class="typ">int</span><span class="pun">&gt;</span><span class="pln"> coinValues</span><span class="pun">;</span><span class="pln">

   </span><span class="com">// تحقق من أنّ 1 موجود في المتجهة</span><span class="pln">
   coinValues</span><span class="pun">.</span><span class="pln">push_back</span><span class="pun">(</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
   </span><span class="com">// اقرأ قيم القطع النقدية، لاحظ أن خطأ المعالجة يهمَل.</span><span class="pln">
   </span><span class="kwd">while</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> coinValue</span><span class="pun">;</span><span class="pln">

       cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"Coin value (&lt;1 to stop): "</span><span class="pun">;</span><span class="pln">
       cin </span><span class="pun">&gt;&gt;</span><span class="pln"> coinValue</span><span class="pun">;</span><span class="pln">

       </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">coinValue </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln">
           coinValues</span><span class="pun">.</span><span class="pln">push_back</span><span class="pun">(</span><span class="pln">coinValue</span><span class="pun">);</span><span class="pln">

       </span><span class="kwd">else</span><span class="pln">
           </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">

   </span><span class="com">// رتب القيم</span><span class="pln">
   sort</span><span class="pun">(</span><span class="pln">coinValues</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">(),</span><span class="pln"> coinValues</span><span class="pun">.</span><span class="pln">end</span><span class="pun">(),</span><span class="pln"> std</span><span class="pun">::</span><span class="pln">greater</span><span class="str">&lt;int&gt;</span><span class="pun">());</span><span class="pln">

   </span><span class="com">// امح النسخ التي لها القيمة نفسها</span><span class="pln">
   </span><span class="kwd">auto</span><span class="pln"> last </span><span class="pun">=</span><span class="pln"> std</span><span class="pun">::</span><span class="pln">unique</span><span class="pun">(</span><span class="pln">coinValues</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">(),</span><span class="pln"> coinValues</span><span class="pun">.</span><span class="pln">end</span><span class="pun">());</span><span class="pln">
   coinValues</span><span class="pun">.</span><span class="pln">erase</span><span class="pun">(</span><span class="pln">last</span><span class="pun">,</span><span class="pln"> coinValues</span><span class="pun">.</span><span class="pln">end</span><span class="pun">());</span><span class="pln">

   </span><span class="com">// اطبع المصفوفة</span><span class="pln">
   cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"Coin values: "</span><span class="pun">;</span><span class="pln">

   </span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">auto</span><span class="pln"> i </span><span class="pun">:</span><span class="pln"> coinValues</span><span class="pun">)</span><span class="pln">
       cout </span><span class="pun">&lt;&lt;</span><span class="pln"> i </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">" "</span><span class="pun">;</span><span class="pln">

   cout </span><span class="pun">&lt;&lt;</span><span class="pln"> endl</span><span class="pun">;</span><span class="pln">

   </span><span class="kwd">return</span><span class="pln"> coinValues</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	لاحظ أننا لم نضع أيّ فحص للمدخلات من أجل إبقاء المثال بسيطًا، وهنا سيكون خرج المثال كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3933_51" style=""><span class="typ">Coin</span><span class="pln"> value </span><span class="pun">(&lt;</span><span class="lit">1</span><span class="pln"> to stop</span><span class="pun">):</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="typ">Coin</span><span class="pln"> value </span><span class="pun">(&lt;</span><span class="lit">1</span><span class="pln"> to stop</span><span class="pun">):</span><span class="pln"> </span><span class="lit">4</span><span class="pln">
</span><span class="typ">Coin</span><span class="pln"> value </span><span class="pun">(&lt;</span><span class="lit">1</span><span class="pln"> to stop</span><span class="pun">):</span><span class="pln"> </span><span class="lit">7</span><span class="pln">
</span><span class="typ">Coin</span><span class="pln"> value </span><span class="pun">(&lt;</span><span class="lit">1</span><span class="pln"> to stop</span><span class="pun">):</span><span class="pln"> </span><span class="lit">9</span><span class="pln">
</span><span class="typ">Coin</span><span class="pln"> value </span><span class="pun">(&lt;</span><span class="lit">1</span><span class="pln"> to stop</span><span class="pun">):</span><span class="pln"> </span><span class="lit">14</span><span class="pln">
</span><span class="typ">Coin</span><span class="pln"> value </span><span class="pun">(&lt;</span><span class="lit">1</span><span class="pln"> to stop</span><span class="pun">):</span><span class="pln"> </span><span class="lit">4</span><span class="pln">
</span><span class="typ">Coin</span><span class="pln"> value </span><span class="pun">(&lt;</span><span class="lit">1</span><span class="pln"> to stop</span><span class="pun">):</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="typ">Coin</span><span class="pln"> values</span><span class="pun">:</span><span class="pln"> </span><span class="lit">14</span><span class="pln"> </span><span class="lit">9</span><span class="pln"> </span><span class="lit">7</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
ticket price</span><span class="pun">:</span><span class="pln"> </span><span class="lit">34</span><span class="pln">
money paid</span><span class="pun">:</span><span class="pln"> </span><span class="lit">67</span><span class="pln">
the difference </span><span class="lit">33</span><span class="pln"> is paid with</span><span class="pun">:</span><span class="pln">
</span><span class="lit">2</span><span class="pln"> coins with value </span><span class="lit">14</span><span class="pln">
</span><span class="lit">1</span><span class="pln"> coins with value </span><span class="lit">4</span><span class="pln">
</span><span class="lit">1</span><span class="pln"> coins with value </span><span class="lit">1</span></pre>

<p>
	إن كانت قيمة القطعة النقدية تساوي <code>‎1‎</code>، فستنتهي <a href="https://wiki.hsoub.com/Algorithms" rel="external">الخوارزمية</a>، لأن:
</p>

<ul>
	<li>
		D تنخفض مع كل خطوة.
	</li>
	<li>
		لا يمكن أن تكون D موجبةً وأصغر من أصغر عملة (<code>‎1‎</code>) في نفس الوقت.
	</li>
</ul>

<p>
	هذه الخوارزمية فيها ثغرتان:
</p>

<ol>
	<li>
		إذا كانت <code>‎C‎</code> هي أكبر قطعة نقدية، فسيكون وقت التشغيل كثير الحدود polynomial طالما أنّ <code>‎D/C‎</code> كثيرة الحدود أيضًا، ذلك أن تمثيل <code>‎D‎</code> يستخدم بتَّات <code>‎log D‎</code> وحسب؛ أمّا وقت التشغيل، فهو على الأقل خطيٌ في <code>‎D/C‎</code>
	</li>
	<li>
		تختار خوَارزميتنا الخيار المحلي الأمثل في كل خطوة، لكنّ هذا لا يعني أنّ الحل الذي تقدمه الخوارزمية هو الحل الأمثل العام.
	</li>
</ol>

<p>
	انظر إلى المثال التوضيحي التالي: لنفترض أنّ القطع النقدية هي <code>‎1,3,4‎</code>، وأنّ <code>‎D=6‎</code>. من الواضح أنّ الحل الأمثل هو قطعتان نقديتان من فئة <code>‎3‎</code>، ولكنّ الخوارزمية الشَرِهَة ستختار <code>‎4‎</code> في الخطوة الأولى، لذا سيكون عليها أن تختار <code>‎1‎</code> في الخطوتين الثانية والثالثة، وعليه فهي لا تعطينا الحل الأمثل. قد يكون استخدام البرمجة الديناميكية لإيجاد الحل الأمثل هو الأفضل في هذه الحالة.
</p>

<h2>
	جدولة الوظائف
</h2>

<p>
	لنفترض أنّ لدينا مجموعةً من الوظائف <code>‎J={a,b,c,d,e,f,g}‎</code>. إذا كانت <code>j</code> التي تنتمي إلى <code>‎J‎</code> هي وظيفة تبدأ عند <code>‎sj‎</code> وتنتهي عند <code>‎fj‎</code>، فسنقول عندئذ أنّ وظيفتين متوافقتان إذا لم تتدَاخلا overlap. انظر الصورة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82500" href="https://academy.hsoub.com/uploads/monthly_2021_11/img1.png.291fc4bbd750afc3f58f9dc205cd11d2.png" rel="" data-fileext="png"><img alt="img1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82500" data-unique="qldvj35dx" src="https://academy.hsoub.com/uploads/monthly_2021_11/img1.thumb.png.016f97f2bd88058a6255f3249fc74916.png"></a>
</p>

<p>
	والهدف هنا هو العثور على أكبر مجموعة من الوظائف المتوافقة مع بعضها بعضًا، وهناك عدة أوجه شَرِهَة لحل هذه المشكلة:
</p>

<ul>
	<li>
		أبكر وقت بداية: خذ الوظائف وفق ترتيب تصاعدي لقيم <code>‎sj‎</code>.
	</li>
	<li>
		أبكر وقت انتهاء: خذ الوظائف وفق ترتيب تصاعدي لـ <code>‎fj‎</code>.
	</li>
	<li>
		أقصر مدة: خذ الوظائف وفق ترتيب تصاعدي لـ <code>‎fj-sj‎</code>.
	</li>
	<li>
		أقل تعارض: لكل وظيفة <code>‎j‎</code>، احسب عدد الوظائف المتعارضة معها (<code>‎cj‎</code>).
	</li>
</ul>

<p>
	السؤال الآن هو: أيّ وجه أفضل؟ من الواضح أنّ منظور أبكر وقت بداية غير صالح كما يوضّح المثال المضاد التالي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82501" href="https://academy.hsoub.com/uploads/monthly_2021_11/img2.png.55dcc7f90fe9cceb9263dcaf848961df.png" rel="" data-fileext="png"><img alt="img2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82501" data-unique="jdo40ecgn" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_11/img2.thumb.png.f7137f45476804d1dadcc986dad5b776.png"></a>
</p>

<p>
	كذلك فإن منظور أقصر مدة ليس مثاليًا:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82502" href="https://academy.hsoub.com/uploads/monthly_2021_11/img3.png.a8f539099649fa213e6f23df6f3fa363.png" rel="" data-fileext="png"><img alt="img3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82502" data-unique="vbv4tc5nl" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_11/img3.thumb.png.d450e0fe8299a561519382c5c53fd5d2.png"></a>
</p>

<p>
	وقد يبدو أنّ منظور أقل تعارض هو الأمثل، غير أن المثال المضاد التالي ينفي ذلك:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="82503" href="https://academy.hsoub.com/uploads/monthly_2021_11/img4.png.9c61e37915e8f68954c0e98d16008e02.png" rel="" data-fileext="png"><img alt="img4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="82503" data-unique="weybph7d3" style="width: 600px; height: 174px;" src="https://academy.hsoub.com/uploads/monthly_2021_11/img4.thumb.png.b9869d3dd99639941d4b65758d4f1d6f.png"></a>
</p>

<p>
	إذًا الحل المتبقي هو أبكر وقت انتهاء. انظر شيفرته التوضيحية:
</p>

<ul>
	<li>
		رتّب الوظائف بحسب وقت الانتهاء <code>‎f1&lt;=f2&lt;=...&lt;=fn‎</code>.
	</li>
	<li>
		لتكن <code>‎A‎</code> مجموعةً فارغة.
	</li>
	<li>
		من <code>‎j=1‎</code> إلى <code>‎n‎</code>، إذا كان <code>‎j‎</code> متوافقًا مع جميع الوظائف في <code>‎A‎</code>، ضع <code>‎A=A+{j}‎</code>.
	</li>
	<li>
		ستكون A هي أكبر مجموعة تضمّ وظائفًا متوافقة.
	</li>
</ul>

<p>
	أو نفس الأمر مكتوبًا في برنامج بلغة C++‎:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3933_54" style=""><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;iostream&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;utility&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;tuple&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;vector&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;algorithm&gt;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> jobCnt </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">
</span><span class="com">// أوقات بداية الوظائف</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> startTimes</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">};</span><span class="pln">
</span><span class="com">// أوقات انتهاء الوظائف</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> endTimes</span><span class="pun">[]</span><span class="pln">   </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">};</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="kwd">namespace</span><span class="pln"> std</span><span class="pun">;</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="typ">vector</span><span class="pun">&lt;</span><span class="pln">pair</span><span class="pun">&lt;</span><span class="typ">int</span><span class="pun">,</span><span class="typ">int</span><span class="pun">&gt;&gt;</span><span class="pln"> jobs</span><span class="pun">;</span><span class="pln">

   </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">jobCnt</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
       jobs</span><span class="pun">.</span><span class="pln">push_back</span><span class="pun">(</span><span class="pln">make_pair</span><span class="pun">(</span><span class="pln">startTimes</span><span class="pun">[</span><span class="pln">i</span><span class="pun">],</span><span class="pln"> endTimes</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]));</span><span class="pln">

   </span><span class="com">// المرحلة الأولى: الترتيب</span><span class="pln">
   sort</span><span class="pun">(</span><span class="pln">jobs</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">(),</span><span class="pln"> jobs</span><span class="pun">.</span><span class="pln">end</span><span class="pun">(),[](</span><span class="pln">pair</span><span class="pun">&lt;</span><span class="typ">int</span><span class="pun">,</span><span class="typ">int</span><span class="pun">&gt;</span><span class="pln"> p1</span><span class="pun">,</span><span class="pln"> pair</span><span class="pun">&lt;</span><span class="typ">int</span><span class="pun">,</span><span class="typ">int</span><span class="pun">&gt;</span><span class="pln"> p2</span><span class="pun">)</span><span class="pln">
                                    </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> p1</span><span class="pun">.</span><span class="pln">second </span><span class="pun">&lt;</span><span class="pln"> p2</span><span class="pun">.</span><span class="pln">second</span><span class="pun">;</span><span class="pln"> </span><span class="pun">});</span><span class="pln">

   </span><span class="com">// A المرحلة الثانية: المجموعة الفارغة</span><span class="pln">
   </span><span class="typ">vector</span><span class="str">&lt;int&gt;</span><span class="pln"> A</span><span class="pun">;</span><span class="pln">

   </span><span class="com">// المرحلة الثالثة</span><span class="pln">
   </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">jobCnt</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">auto</span><span class="pln"> job </span><span class="pun">=</span><span class="pln"> jobs</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
       </span><span class="kwd">bool</span><span class="pln"> isCompatible </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">

       </span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">auto</span><span class="pln"> jobIndex </span><span class="pun">:</span><span class="pln"> A</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="com">// A تحقق مما إذا كانت الوظيفة الحالية غير متوافقة مع الوظيفة من</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">job</span><span class="pun">.</span><span class="pln">second </span><span class="pun">&gt;=</span><span class="pln"> jobs</span><span class="pun">[</span><span class="pln">jobIndex</span><span class="pun">].</span><span class="pln">first </span><span class="pun">&amp;&amp;</span><span class="pln">
              job</span><span class="pun">.</span><span class="pln">first  </span><span class="pun">&lt;=</span><span class="pln"> jobs</span><span class="pun">[</span><span class="pln">jobIndex</span><span class="pun">].</span><span class="pln">second</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               isCompatible </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
               </span><span class="kwd">break</span><span class="pun">;</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">

       </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">isCompatible</span><span class="pun">)</span><span class="pln">
           A</span><span class="pun">.</span><span class="pln">push_back</span><span class="pun">(</span><span class="pln">i</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">

   </span><span class="com">// A المرحلة الرابعة: طباعة</span><span class="pln">
   cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"Compatible: "</span><span class="pun">;</span><span class="pln">

   </span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">auto</span><span class="pln"> i </span><span class="pun">:</span><span class="pln"> A</span><span class="pun">)</span><span class="pln">
       cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"("</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> jobs</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">first </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">","</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> jobs</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">second </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">") "</span><span class="pun">;</span><span class="pln">
   cout </span><span class="pun">&lt;&lt;</span><span class="pln"> endl</span><span class="pun">;</span><span class="pln">

   </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	خرج هذا المثال سيكون:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3933_56" style=""><span class="typ">Compatible</span><span class="pun">:</span><span class="pln"> </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">3</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="lit">5</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="lit">8</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="lit">9</span><span class="pun">,</span><span class="lit">10</span><span class="pun">)</span></pre>

<p>
	تعقيد هذا التطبيق يساوي <code>‎Θ (n ^ 2)‎‎</code>، لكن هناك تطبيق آخر من التعقيد <code>‎Θ (n log n)‎‎</code> (انظر مثال جافا أدناه). أصبحت لدينا الآن خوارزمية شَرِهَة لحل مشكلة الجدولة الزمنية، ولكن أهي مُثلى؟
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<strong>خاصية</strong>: خوارزمية أبكر وقت انتهاء الشَرِهَة هي خوارزميةٌ مُثلى.
	</p>
</blockquote>

<p>
	 لنفترض أنّ هذه الخوارزمية الشَرِهَة ليست مثلى، وأن <code>‎i1,i2,...,ik‎</code> تشير إلى مجموعة من الوظائف التي اختارتها الخوارزمية الشَرِهَة، ولتكن <code>‎j1,j2,...,jm‎</code> تشير إلى مجموعة الوظائف في الحل الأمثل، وليكن <code>‎r‎</code> هو العدد الأكبر الذي يحقق <code>‎i1=j1,i2=j2,...,ir=jr‎</code>.
</p>

<p>
	الوظيفة <code>‎i(r+1)‎</code> موجودة وتنتهي قبل الوظيفة <code>‎j(r+1)‎</code> (أبكر وقت انتهاء)، لكن هذا يعني أنّ الوظيفة الآتية ستكون أيضًا حلًّا أمثلَ، ولكلّ <code>‎k‎</code> من المجال <code>‎[1,(r+1)]‎</code>، سيكون لدينا <code>‎jk=ik‎</code>، مما يناقض فرضية أنّ <code>‎r‎</code> هو العدد الأكبر. وهذا يُتمّ البرهان.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_7683_6" style=""><span class="pun">‎</span><span class="pln">j1</span><span class="pun">,</span><span class="pln">j2</span><span class="pun">,...,</span><span class="pln">jr</span><span class="pun">,</span><span class="pln">i</span><span class="pun">(</span><span class="pln">r</span><span class="pun">+</span><span class="lit">1</span><span class="pun">),</span><span class="pln">j</span><span class="pun">(</span><span class="pln">r</span><span class="pun">+</span><span class="lit">2</span><span class="pun">),...,</span><span class="pln">jm</span><span class="pun">‎</span><span class="pln">
</span></pre>

<p>
	يوضّح المثال التالي أنّ هناك العديد من الاستراتيجيات الشَرِهَة الممكنة في الغالب، ولكن ليست كلها تجد الحل الأمثل العام، بل قد لا تجده أي منها.
</p>

<p>
	فيما يلي برنامج Java تعقيده <code>‎Θ (n log n) ‎‎‎</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3933_58" style=""><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">util</span><span class="pun">.</span><span class="typ">Arrays</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">import</span><span class="pln"> java</span><span class="pun">.</span><span class="pln">util</span><span class="pun">.</span><span class="typ">Comparator</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">Job</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> start</span><span class="pun">,</span><span class="pln"> finish</span><span class="pun">,</span><span class="pln"> profit</span><span class="pun">;</span><span class="pln">
   </span><span class="typ">Job</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> start</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> finish</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> profit</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">start </span><span class="pun">=</span><span class="pln"> start</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">finish </span><span class="pun">=</span><span class="pln"> finish</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">profit </span><span class="pun">=</span><span class="pln"> profit</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">JobComparator</span><span class="pln"> implements </span><span class="typ">Comparator</span><span class="pun">&lt;</span><span class="typ">Job</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> compare</span><span class="pun">(</span><span class="typ">Job</span><span class="pln"> a</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Job</span><span class="pln"> b</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> a</span><span class="pun">.</span><span class="pln">finish </span><span class="pun">&lt;</span><span class="pln"> b</span><span class="pun">.</span><span class="pln">finish </span><span class="pun">?</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> a</span><span class="pun">.</span><span class="pln">finish </span><span class="pun">==</span><span class="pln"> b</span><span class="pun">.</span><span class="pln">finish </span><span class="pun">?</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">WeightedIntervalScheduling</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> binarySearch</span><span class="pun">(</span><span class="typ">Job</span><span class="pln"> jobs</span><span class="pun">[],</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> index</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> lo </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> hi </span><span class="pun">=</span><span class="pln"> index </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">while</span><span class="pln"> </span><span class="pun">(</span><span class="pln">lo </span><span class="pun">&lt;=</span><span class="pln"> hi</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="typ">int</span><span class="pln"> mid </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">lo </span><span class="pun">+</span><span class="pln"> hi</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">jobs</span><span class="pun">[</span><span class="pln">mid</span><span class="pun">].</span><span class="pln">finish </span><span class="pun">&lt;=</span><span class="pln"> jobs</span><span class="pun">[</span><span class="pln">index</span><span class="pun">].</span><span class="pln">start</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">jobs</span><span class="pun">[</span><span class="pln">mid </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">].</span><span class="pln">finish </span><span class="pun">&lt;=</span><span class="pln"> jobs</span><span class="pun">[</span><span class="pln">index</span><span class="pun">].</span><span class="pln">start</span><span class="pun">)</span><span class="pln">
                   lo </span><span class="pun">=</span><span class="pln"> mid </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
               </span><span class="kwd">else</span><span class="pln">
                   </span><span class="kwd">return</span><span class="pln"> mid</span><span class="pun">;</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln">
               hi </span><span class="pun">=</span><span class="pln"> mid </span><span class="pun">-</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> schedule</span><span class="pun">(</span><span class="typ">Job</span><span class="pln"> jobs</span><span class="pun">[])</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">Arrays</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="pln">jobs</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">JobComparator</span><span class="pun">());</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> n </span><span class="pun">=</span><span class="pln"> jobs</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> table</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[</span><span class="pln">n</span><span class="pun">];</span><span class="pln">
       table</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> jobs</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">profit</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">1</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">n</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           </span><span class="typ">int</span><span class="pln"> inclProf </span><span class="pun">=</span><span class="pln"> jobs</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">profit</span><span class="pun">;</span><span class="pln">
           </span><span class="typ">int</span><span class="pln"> l </span><span class="pun">=</span><span class="pln"> binarySearch</span><span class="pun">(</span><span class="pln">jobs</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">);</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">l </span><span class="pun">!=</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
               inclProf </span><span class="pun">+=</span><span class="pln"> table</span><span class="pun">[</span><span class="pln">l</span><span class="pun">];</span><span class="pln">
           table</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">inclProf</span><span class="pun">,</span><span class="pln"> table</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]);</span><span class="pln">

       </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> table</span><span class="pun">[</span><span class="pln">n</span><span class="pun">-</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">Job</span><span class="pln"> jobs</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Job</span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">),</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Job</span><span class="pun">(</span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">),</span><span class="pln">
                   </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Job</span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">19</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">),</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Job</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">)};</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Optimal profit is "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> schedule</span><span class="pun">(</span><span class="pln">jobs</span><span class="pun">));</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الخرج المتوقع هو:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3933_60" style=""><span class="typ">Optimal</span><span class="pln"> profit is </span><span class="lit">250</span></pre>

<h2>
	تقليل التأخير Minimizing Lateness
</h2>

<p>
	هناك العديد من المشاكل التي تقلل التأخير، ولنفترض هنا أنّ لدينا مصدرًا وحيدًا يمكنه معالجة مهمّة واحدة فقط في كل مرّة، والوظيفة <code>‎j‎</code> تتطلب <code>‎tj‎</code> وحدة وقت من زمن المعالجة، وتبدأ عند التوقيت <code>‎dj‎</code>، فإن بدأت <code>‎j‎</code> في الوقت <code>‎sj‎</code>، فستنتهي عند الوقت <code>fj ‎=‎ sj ‎+‎ tj</code>.
</p>

<p>
	نعرّف التأخير lateness بالصيغة التالية: <code>‎L=max{ 0 ,fj-dh}‎</code>، لكل وظيفة <code>j</code>، والهدف هو تقليل أقصى تأخير لـ L.
</p>

<table>
	<thead>
		<tr>
			<th>
				 
			</th>
			<th>
				1
			</th>
			<th>
				2
			</th>
			<th>
				3
			</th>
			<th>
				4
			</th>
			<th>
				5
			</th>
			<th>
				6
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				<code>tj</code>
			</td>
			<td>
				3
			</td>
			<td>
				2
			</td>
			<td>
				1
			</td>
			<td>
				4
			</td>
			<td>
				3
			</td>
			<td>
				2
			</td>
		</tr>
		<tr>
			<td>
				<code>dj</code>
			</td>
			<td>
				6
			</td>
			<td>
				8
			</td>
			<td>
				9
			</td>
			<td>
				9
			</td>
			<td>
				10
			</td>
			<td>
				11
			</td>
		</tr>
	</tbody>
</table>

<table>
	<thead>
		<tr>
			<th>
				الوظيفة
			</th>
			<th>
				3
			</th>
			<th>
				2
			</th>
			<th>
				2
			</th>
			<th>
				5
			</th>
			<th>
				5
			</th>
			<th>
				5
			</th>
			<th>
				4
			</th>
			<th>
				4
			</th>
			<th>
				4
			</th>
			<th>
				4
			</th>
			<th>
				1
			</th>
			<th>
				1
			</th>
			<th>
				1
			</th>
			<th>
				6
			</th>
			<th>
				6
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				الوقت
			</td>
			<td>
				1
			</td>
			<td>
				2
			</td>
			<td>
				3
			</td>
			<td>
				4
			</td>
			<td>
				5
			</td>
			<td>
				6
			</td>
			<td>
				7
			</td>
			<td>
				8
			</td>
			<td>
				9
			</td>
			<td>
				10
			</td>
			<td>
				11
			</td>
			<td>
				12
			</td>
			<td>
				13
			</td>
			<td>
				14
			</td>
			<td>
				15
			</td>
		</tr>
		<tr>
			<td>
				<code>Lj</code>
			</td>
			<td>
				8-
			</td>
			<td>
				 
			</td>
			<td>
				5-
			</td>
			<td>
				 
			</td>
			<td>
				 
			</td>
			<td>
				4-
			</td>
			<td>
				 
			</td>
			<td>
				 
			</td>
			<td>
				 
			</td>
			<td>
				1
			</td>
			<td>
				 
			</td>
			<td>
				 
			</td>
			<td>
				7
			</td>
			<td>
				 
			</td>
			<td>
				4
			</td>
		</tr>
	</tbody>
</table>

<p>
	من الواضح أنّ الحل <code>‎L=7‎</code> ليس الأمثل. لهذا من الأفضل أن نلقي نظرةً على بعض الاستراتيجيات الشَرِهَة:
</p>

<ul>
	<li>
		أقصر وقت معالجة أولاً: نُجدول المهام وفق ترتيب تصاعدي لوقت المعالجة j`.
	</li>
	<li>
		أبكر موعد نهائي أولًا: جدولة المهام وفق ترتيب تصاعدي للمواعيد النهائية <code>‎dj‎</code>.
	</li>
	<li>
		أقصر مُهلة Smallest slack: جدولة المهام وفق ترتيب تصاعدي للمهلة <code>‎dj-tj‎</code>.
	</li>
</ul>

<p>
	من الواضح أنّ منظور أقصر وقت معالجة أولًا ليس الأمثل، هذا المثال المضاد يبيّن ذلك:
</p>

<table>
	<thead>
		<tr>
			<th>
				 
			</th>
			<th>
				1
			</th>
			<th>
				2
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				<code>tj</code>
			</td>
			<td>
				1
			</td>
			<td>
				5
			</td>
		</tr>
		<tr>
			<td>
				<code>dj</code>
			</td>
			<td>
				10
			</td>
			<td>
				5
			</td>
		</tr>
	</tbody>
</table>

<p>
	كذلك فإن منظور أقصر مهلة لديه مشاكل مشابهة كما يبيّن المثال التالي:
</p>

<table>
	<thead>
		<tr>
			<th>
				 
			</th>
			<th>
				1
			</th>
			<th>
				2
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				<code>tj</code>
			</td>
			<td>
				1
			</td>
			<td>
				5
			</td>
		</tr>
		<tr>
			<td>
				<code>dj</code>
			</td>
			<td>
				3
			</td>
			<td>
				5
			</td>
		</tr>
	</tbody>
</table>

<p>
	والإستراتيجية الأخيرة تبدو صالحة، انظر هذه الشيفرة التوضيحية لها:
</p>

<ol>
	<li>
		رتّب <code>‎n‎</code> وظيفةً بحسب المواعيد النهائية، بحيث تكون <code>‎d1&lt;=d2&lt;=...&lt;=dn‎</code>.
	</li>
	<li>
		عيّن <code>‎‎</code>t=0.
	</li>
	<li>
		من <code>‎j=1‎</code> إلى <code>‎n‎</code>:
		<ul style="margin-right: 40px;">
			<li>
				عيّن المهمة <code>‎j‎</code> للفاصل الزمني <code>‎[t,t+tj]‎</code>.
			</li>
			<li>
				عيّن <code>‎sj=t‎</code> و<code>‎fj=t+tj‎</code>.
			</li>
			<li>
				عيّن <code>‎t=t+tj‎</code>.
			</li>
		</ul>
	</li>
	<li>
		أعِد المجالات <code>‎[s1,f1],[s2,f2],...,[sn,fn]‎</code>.
	</li>
</ol>

<p>
	هذا تطبيق بلغة C++‎:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3933_62" style=""><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;iostream&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;utility&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;tuple&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;vector&gt;</span><span class="pln">
</span><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;algorithm&gt;</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> jobCnt </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pun">;</span><span class="pln">
</span><span class="com">// أوقات بداية الوظائف</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> processTimes</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">};</span><span class="pln">
</span><span class="com">// أوقات انتهاء الوظائف</span><span class="pln">
</span><span class="kwd">const</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> dueTimes</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">13</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">17</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">11</span><span class="pun">,</span><span class="pln"> </span><span class="lit">22</span><span class="pun">,</span><span class="pln"> </span><span class="lit">25</span><span class="pun">};</span><span class="pln">
</span><span class="kwd">using</span><span class="pln"> </span><span class="kwd">namespace</span><span class="pln"> std</span><span class="pun">;</span><span class="pln">
</span><span class="typ">int</span><span class="pln"> main</span><span class="pun">()</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
    </span><span class="typ">vector</span><span class="pun">&lt;</span><span class="pln">pair</span><span class="pun">&lt;</span><span class="typ">int</span><span class="pun">,</span><span class="typ">int</span><span class="pun">&gt;&gt;</span><span class="pln"> jobs</span><span class="pun">;</span><span class="pln">

 </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">jobCnt</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
        jobs</span><span class="pun">.</span><span class="pln">push_back</span><span class="pun">(</span><span class="pln">make_pair</span><span class="pun">(</span><span class="pln">processTimes</span><span class="pun">[</span><span class="pln">i</span><span class="pun">],</span><span class="pln"> dueTimes</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]));</span><span class="pln">

 </span><span class="com">// المرحلة الأولى: الترتيب</span><span class="pln">
    sort</span><span class="pun">(</span><span class="pln">jobs</span><span class="pun">.</span><span class="pln">begin</span><span class="pun">(),</span><span class="pln"> jobs</span><span class="pun">.</span><span class="pln">end</span><span class="pun">(),[](</span><span class="pln">pair</span><span class="pun">&lt;</span><span class="typ">int</span><span class="pun">,</span><span class="typ">int</span><span class="pun">&gt;</span><span class="pln"> p1</span><span class="pun">,</span><span class="pln"> pair</span><span class="pun">&lt;</span><span class="typ">int</span><span class="pun">,</span><span class="typ">int</span><span class="pun">&gt;</span><span class="pln"> p2</span><span class="pun">)</span><span class="pln">
 </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> p1</span><span class="pun">.</span><span class="pln">second </span><span class="pun">&lt;</span><span class="pln"> p2</span><span class="pun">.</span><span class="pln">second</span><span class="pun">;</span><span class="pln"> </span><span class="pun">});</span><span class="pln">

 </span><span class="com">// t=0 المرحلة الثانية: تعيين</span><span class="pln">
 </span><span class="typ">int</span><span class="pln"> t </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

 </span><span class="com">// المرحلة الثالثة</span><span class="pln">
    </span><span class="typ">vector</span><span class="pun">&lt;</span><span class="pln">pair</span><span class="pun">&lt;</span><span class="typ">int</span><span class="pun">,</span><span class="typ">int</span><span class="pun">&gt;&gt;</span><span class="pln"> jobIntervals</span><span class="pun">;</span><span class="pln">

 </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">jobCnt</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
 </span><span class="pun">{</span><span class="pln">
        jobIntervals</span><span class="pun">.</span><span class="pln">push_back</span><span class="pun">(</span><span class="pln">make_pair</span><span class="pun">(</span><span class="pln">t</span><span class="pun">,</span><span class="pln">t</span><span class="pun">+</span><span class="pln">jobs</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">first</span><span class="pun">));</span><span class="pln">
        t </span><span class="pun">+=</span><span class="pln"> jobs</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">first</span><span class="pun">;</span><span class="pln">
 </span><span class="pun">}</span><span class="pln">

 </span><span class="com">// المرحلة الرابعة: طباعة المجالات</span><span class="pln">
 cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"Intervals:\n"</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> endl</span><span class="pun">;</span><span class="pln">

 </span><span class="typ">int</span><span class="pln"> lateness </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">

 </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">jobCnt</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln">
 </span><span class="pun">{</span><span class="pln">
 </span><span class="kwd">auto</span><span class="pln"> pair </span><span class="pun">=</span><span class="pln"> jobIntervals</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">

        lateness </span><span class="pun">=</span><span class="pln"> max</span><span class="pun">(</span><span class="pln">lateness</span><span class="pun">,</span><span class="pln"> pair</span><span class="pun">.</span><span class="pln">second</span><span class="pun">-</span><span class="pln">jobs</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">second</span><span class="pun">);</span><span class="pln">
 cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"("</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> pair</span><span class="pun">.</span><span class="pln">first </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">","</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> pair</span><span class="pun">.</span><span class="pln">second </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">") "</span><span class="pln">
 </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"Lateness: "</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> pair</span><span class="pun">.</span><span class="pln">second</span><span class="pun">-</span><span class="pln">jobs</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">second </span><span class="pun">&lt;&lt;</span><span class="pln"> std</span><span class="pun">::</span><span class="pln">endl</span><span class="pun">;</span><span class="pln">
 </span><span class="pun">}</span><span class="pln">

 cout </span><span class="pun">&lt;&lt;</span><span class="pln"> </span><span class="str">"\nmaximal lateness is "</span><span class="pln"> </span><span class="pun">&lt;&lt;</span><span class="pln"> lateness </span><span class="pun">&lt;&lt;</span><span class="pln"> endl</span><span class="pun">;</span><span class="pln">
 </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	والخرج الناتج لهذا البرنامج هو:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3933_64" style=""><span class="typ">Intervals</span><span class="pun">:</span><span class="pln">
</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">2</span><span class="pun">)</span><span class="pln">   </span><span class="typ">Lateness</span><span class="pun">:-</span><span class="lit">2</span><span class="pln">
</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="lit">5</span><span class="pun">)</span><span class="pln">   </span><span class="typ">Lateness</span><span class="pun">:-</span><span class="lit">2</span><span class="pln">
</span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="lit">8</span><span class="pun">)</span><span class="pln">   </span><span class="typ">Lateness</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="pun">(</span><span class="lit">8</span><span class="pun">,</span><span class="lit">9</span><span class="pun">)</span><span class="pln">   </span><span class="typ">Lateness</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="pun">(</span><span class="lit">9</span><span class="pun">,</span><span class="lit">12</span><span class="pun">)</span><span class="pln">  </span><span class="typ">Lateness</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="pun">(</span><span class="lit">12</span><span class="pun">,</span><span class="lit">17</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Lateness</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
</span><span class="pun">(</span><span class="lit">17</span><span class="pun">,</span><span class="lit">21</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Lateness</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8</span><span class="pln">
</span><span class="pun">(</span><span class="lit">21</span><span class="pun">,</span><span class="lit">23</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Lateness</span><span class="pun">:</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
</span><span class="pun">(</span><span class="lit">23</span><span class="pun">,</span><span class="lit">25</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Lateness</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="pun">(</span><span class="lit">25</span><span class="pun">,</span><span class="lit">26</span><span class="pun">)</span><span class="pln"> </span><span class="typ">Lateness</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
maximal lateness is </span><span class="lit">8</span></pre>

<p>
	الظاهر هنا أنّ وقت تشغيل هذه الخوارزمية هو <code>‎‎</code>Θ(n log n)‎‎، لأنّ الترتيب هو العملية الغالبة في هذه الخوارزمية. سنحاول الآن إثبات أنّ هذه الخوارزمية مُثلى، وهذا يستلزم ألا يكون في الجدول الزمني وقت خامل idle time أو غير مُستخدم. وهو أمر يتحقق في منظور أبكر موعد نهائي أولًا.
</p>

<p>
	لنفترض أنّ الوظائف مُرقّمة بحيث تكون <code>‎d1&lt;=d2&lt;=...&lt;=dn‎</code>. نقول أن تقليبات جدول ما inversion of a schedule هي أزواج من الوظائف <code>‎i‎</code> و<code>‎j‎</code>، بحيث تكون <code>‎i&lt;j‎</code>، وتكون j مُجدولةً قبل <code>‎i‎</code>. من الواضح أنّ منظور أبكر وقت نهائي أولًا ليس لها تقليبات، وإن كان الجدول يحتوي تقليبة، فهذا يعني أنّه يحتوي زوجًا من الوظائف المقلوبة والمُجدولة بالتتابع.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<strong>خاصية</strong>: يؤدي تبديل وظيفتين متجاورتين adjacent ومقلوبتين inverted إلى تقليل عدد التقليبات بمقدار واحد دون أن يزيد الحد الأقصى لوقت التأخير.
	</p>
</blockquote>

<p>
	إذا كانت <code>‎L‎</code> هي قيمة التأخير قبل التبديل، و<code>‎M‎</code> هو التأخير بعد التبديل، فستكون <code>‎Lk=Mk‎</code> لكل <code>‎k != i,j.‎</code>، نظرًا لأنّ تبديل وظيفتين متجاورتين لا ينقل الوظائف الأخرى من مواقعها.
</p>

<p>
	من الواضح أنّ <code>‎Mi&lt;=Li‎</code> لأنّ الوظيفة <code>‎i‎</code> جُدوِلَت في وقت أبكر، أما إذا تأخرت الوظيفة <code>‎j‎</code> فيمكن أن نستنتج من التعريف أنّ:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3933_66" style=""><span class="pln">       </span><span class="typ">Mj</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> fi</span><span class="pun">-</span><span class="pln">dj    </span><span class="pun">من</span><span class="pln"> </span><span class="pun">التعريف</span><span class="pln"> 
       </span><span class="pun">&lt;=</span><span class="pln"> fi</span><span class="pun">-</span><span class="pln">di    </span><span class="pun">(</span><span class="pln"> j </span><span class="pun">و</span><span class="pln"> i </span><span class="pun">لأنّه</span><span class="pln"> </span><span class="pun">يمكن</span><span class="pln"> </span><span class="pun">مبادلة)</span><span class="pln"> 
       </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="typ">Li</span></pre>

<p>
	هذا يعني أنّ التأخير بعد المبادلة سيكون أقل أو يساوي التأخير قبل المبادلة، وهذا يُتمّ البرهان.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<strong>خاصية</strong>: الجدول الزمني S الناتج عن منظور أبكر وقت نهائي أولًا هو الجدول الأمثل.
	</p>
</blockquote>

<p>
	 لنفترض أنّ <code>‎S*‎</code> هو الجدول الأمثل وأنّ له أقل عدد ممكن من التقليبات. يمكن أن نفترض أنّ <code>‎S*‎</code> ليس فيه وقت شاغر، إذ لو كانت لـ <code>‎S*‎</code> أي تقليبات، فسيكون لدينا <code>‎S=S*‎</code>، وهذا يتمّ البرهان؛ أمّا إن احتوى <code>‎S*‎</code> على تقلِيبة فستكون له تقلِيبة مجاورة adjacent inversion. الخاصية الأخيرة تنصّ على أنّنا نستطيع تبديل التقليبات المتجاورة وتقليل عدد التقليبات دون زيادة التأخير، وهذا يتناقض مع تعريف <code>‎S*‎</code>.
</p>

<p>
	هناك الكثير من التطبيقات لمشكلة تقليل التأخير ومشكلة الحد الأدنى المشابهة لها minimum makespan problem، وهي المشكلة التي تحاول تقليل وقت انتهاء الوظائف. والمعتاد أنه لا تكون لديك آلة واحدة فقط، بل العديد من الآلات التي يمكنها القيام بالمهام نفسها بمعدّلات مختلفة. يمكن أن تتحول هذه المشكلة بسرعة إلى مشكلة من الصنف <a href="https://ar.wikipedia.org/wiki/%D9%85%D8%B3%D8%A3%D9%84%D8%A9_%D9%83%D8%AB%D9%8A%D8%B1%D8%A9_%D8%AD%D8%AF%D9%88%D8%AF_%D8%BA%D9%8A%D8%B1_%D9%82%D8%B7%D8%B9%D9%8A%D8%A9_%D9%83%D8%A7%D9%85%D9%84%D8%A9" rel="external nofollow">NP-complete</a>.
</p>

<p>
	يظهر هنا سؤال مثير للاهتمام إن نظرنا إلى المشكلة المتصلة online، حيث تكون لدينا كل المهام والبيانات، لكن في صورة متصلة online، حيث تظهر المهام أثناء التنفيذ.
</p>

<p>
	ترجمة -بتصرّف- للفصل 18 من كتاب <a href="https://goalkicker.com/AlgorithmsBook/" rel="external nofollow">Algorithms Notes for Professionals</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AF%D9%84%D9%8A%D9%84-%D8%B4%D8%A7%D9%85%D9%84-%D8%B9%D9%86-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%AA%D8%B9%D9%82%D9%8A%D8%AF-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-r1247/" rel="">دليل شامل عن تحليل تعقيد الخوارزمية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA/" rel="">المرجع الشامل إلى تعلم الخوارزميات للمبتدئين</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1282/" rel="">مدخل إلى الخوارزميات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-%D8%AA%D8%AD%D8%AF%D9%8A%D8%AF-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1-%D8%A7%D9%84%D9%86%D8%AC%D9%85%D9%8A%D8%A9-a-path%EF%AC%81nding-r1363/" rel="">خوارزمية تحديد المسار النجمية A* Pathﬁnding</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-%D8%AF%D9%8A%D9%83%D8%B3%D8%AA%D8%B1%D8%A7-dijkstra%E2%80%99s-algorithm-r1336/" rel="">خوارزمية ديكسترا Dijkstra’s Algorithm</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1372</guid><pubDate>Wed, 03 Nov 2021 16:00:00 +0000</pubDate></item><item><title>&#x62A;&#x62D;&#x644;&#x64A;&#x644; &#x632;&#x645;&#x646; &#x62A;&#x634;&#x63A;&#x64A;&#x644; &#x627;&#x644;&#x642;&#x648;&#x627;&#x626;&#x645; &#x627;&#x644;&#x645;&#x646;&#x641;&#x630;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x642;&#x627;&#x626;&#x645;&#x629; &#x645;&#x62A;&#x631;&#x627;&#x628;&#x637;&#x629;</title><link>https://academy.hsoub.com/programming/advanced/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D9%85%D8%AA%D8%B1%D8%A7%D8%A8%D8%B7%D8%A9-r1349/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/61730dccbde0e_-------.png.f28fbaac6f5793747a0b3e3f4f3f4ec5.png" /></p>
<p>
	سنتناول في هذه المقالة حل تمرين <a href="https://academy.hsoub.com/programming/advance/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A9-r1348/" rel="">مقالة تحليل زمن تشغيل القوائم المُنفَّذة باستخدام مصفوفة</a>، ثم نتابع مناقشة <a href="https://academy.hsoub.com/programming/advanced/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1345/" rel="">تحليل الخوارزميات</a>.
</p>

<h2 id="تصنيف-توابع-الصنف-mylinkedlist">
	تصنيف توابع الصنف MyLinkedList
</h2>

<p>
	تَعرِض الشيفرة التالية تنفيذ التابع <code>indexOf</code>. اقرأها وحاول تحديد ترتيب نمو order of growth التابع قبل المتابعة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5919_33" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> indexOf</span><span class="pun">(</span><span class="typ">Object</span><span class="pln"> target</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Node</span><span class="pln"> node </span><span class="pun">=</span><span class="pln"> head</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">size</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">equals</span><span class="pun">(</span><span class="pln">target</span><span class="pun">,</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">data</span><span class="pun">))</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">return</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
            node </span><span class="pun">=</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">next</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	تُسنَد <code>head</code> إلى <code>node</code> أولًا، ويعني هذا أنّ كليهما يشير الآن إلى نفس العقدة. يَعُدّ المُتغيّرُ <code>i</code> هو المُتحكِّم بالحلقة من 0 إلى <code>size-1</code>، ويَستدعِي في كل تكرارٍ التابعَ <code>equals</code> ليفحص ما إذا كان قد وجد القيمة المطلوبة. فإذا وجدها، فسيعيد قيمة <code>i</code> على الفور؛ أما إذا لم يجدها، فسينتقل إلى العقدة التالية ضمن القائمة.
</p>

<p>
	عادةً ما نتأكَّد أولًا مما إذا كانت العقدة التالية لا تحتوي على قيمة فارغة <code>null</code>، ولكن ليس هذا ضروريًا في حالتنا؛ لأن الحلقة تنتهي بمجرد وصولنا إلى نهاية القائمة (بفرض أن قيمة <code>size</code> مُتّسقةٌ مع العدد الفعلي للعقد الموجودة ضمن القائمة).
</p>

<p>
	إذا نفَّذنا الحلقة بالكامل دون العثور على القيمة المطلوبة، فسيعيد التابع القيمة -1.
</p>

<p>
	والآن، ما هو ترتيب نمو هذا التابع؟
</p>

<ol start="">
	<li>
		إننا نستدعِي في كل تكرار التابع <code>equals</code> الذي يَستغرِق زمنًا ثابتًا (قد يعتمد على حجم <code>target</code> أو <code>data</code>، ولكنه لا يعتمد على حجم القائمة). تستغرق جميع التعليمات الأخرى ضمن الحلقة زمنًا ثابتًا أيضًا.
	</li>
	<li>
		تُنفَّذ الحلقة عددًا من المرات مقدراه n لأننا قد نضطّر إلى اجتياز القائمة بالكامل في الحالة الأسوأ.
	</li>
</ol>

<p>
	وبالتالي يتناسب زمن تنفيذ ذلك التابع مع طول القائمة.
</p>

<p>
	والآن، انظر إلى تنفيذ التابع <code>add</code> ذي المعاملين، وحاول تصنيفه قبل متابعة القراءة.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5919_31" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> add</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> index</span><span class="pun">,</span><span class="pln"> E element</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">index </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            head </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Node</span><span class="pun">(</span><span class="pln">element</span><span class="pun">,</span><span class="pln"> head</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Node</span><span class="pln"> node </span><span class="pun">=</span><span class="pln"> getNode</span><span class="pun">(</span><span class="pln">index</span><span class="pun">-</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
            node</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Node</span><span class="pun">(</span><span class="pln">element</span><span class="pun">,</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">next</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        size</span><span class="pun">++;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	إذا كان <code>index</code> يُساوِي الصِّفر، فإننا نضيف العقدة الجديدة إلى بداية القائمة، ولهذا علينا أن نُعالِج ذلك مثل حالة خاصة. وبخلاف ذلك سنضطرّ إلى اجتياز القائمة إلى أن نصِل إلى العنصر الموجود في الفهرس <code>index-1</code>، كما سنستخدِم لهذا الهدف التابعَ المساعدَ <code>getNode</code>، وفيما يلي شيفرته:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5919_29" style=""><span class="pln">    </span><span class="kwd">private</span><span class="pln"> </span><span class="typ">Node</span><span class="pln"> getNode</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> index</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">index </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> index </span><span class="pun">&gt;=</span><span class="pln"> size</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">IndexOutOfBoundsException</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="typ">Node</span><span class="pln"> node </span><span class="pun">=</span><span class="pln"> head</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">index</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            node </span><span class="pun">=</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">next</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> node</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	يفحص التابع <code>getNode</code> ما إذا كانت قيمة <code>index</code> خارج النطاق المسموح به، فإذا كانت كذلك، فإنه يُبلِّغ عن اعتراض exception؛ أما إذا لم تكن كذلك، فإنه يمرّ عبر عناصر القائمة ويعيد العقدة المطلوبة.
</p>

<p>
	الآن وقد حصلنا على العقدة المطلوبة، نعود إلى التابع <code>add</code> وننشئ عقدةً جديدةً، ونضعها بين العقدتين <code>node</code> و<code>node.next</code>. قد يساعدك رسم هذه العملية على التأكد من فهمها بوضوح.
</p>

<p>
	والآن، ما هو ترتيب نمو التابع <code>add</code>؟
</p>

<ol start="">
	<li>
		يشبه التابع <code>getNode</code> التابع <code>indexOf</code>، وهو خطّيٌّ لنفس السبب.
	</li>
	<li>
		تَستغرِق جميع التعليمات زمنًا ثابتًا سواءٌ قبل استدعاء التابع <code>getNode</code> أوبعد استدعائه ضمن التابع <code>add</code>.
	</li>
</ol>

<p>
	وعليه، يكون التابع <code>add</code> خطيًّا.
</p>

<p>
	وأخيرًا، لنُلقِ نظرةً على التابع <code>remove</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5919_27" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> E remove</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> index</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        E element </span><span class="pun">=</span><span class="pln"> get</span><span class="pun">(</span><span class="pln">index</span><span class="pun">);</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">index </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            head </span><span class="pun">=</span><span class="pln"> head</span><span class="pun">.</span><span class="pln">next</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">Node</span><span class="pln"> node </span><span class="pun">=</span><span class="pln"> getNode</span><span class="pun">(</span><span class="pln">index</span><span class="pun">-</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
            node</span><span class="pun">.</span><span class="pln">next </span><span class="pun">=</span><span class="pln"> node</span><span class="pun">.</span><span class="pln">next</span><span class="pun">.</span><span class="pln">next</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        size</span><span class="pun">--;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> element</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	يَستدعِي <code>remove</code> التابع <code>get</code> للعثور على العنصر الموجود في الفهرس <code>index</code> ثم عندما يجده يحذف العقدة التي تتضمنه.
</p>

<p>
	إذا كان <code>index</code> يُساوي الصفر، نُعالِج ذلك مثل حالة خاصة. وإذا لم يكن يساوي الصفر فسنذهب إلى العقدة الموجودة في الفهرس <code>index-1</code>، وهي العقدة التي تقع قبل العقدة المستهدفة بالحذف، ونُعدِّل حقل next فيها ليشير مباشرةً إلى العقدة <code>node.next.next</code>، وبذلك نكون قد حذفنا العقدة <code>node.next</code> من القائمة، ومن ثمَّ تُحرّر الذاكرة التي كانت تحتّلها عن طريق الكنس garbage collection. وأخيرًا، يُنقِص التابع قيمة <code>size</code> ويُعيد العنصر المُسترجَع في البداية.
</p>

<p>
	والآن بناءً على ما سبق، ما هو ترتيب نمو التابع <code>remove</code>؟ تَستغرِق جميع التعليمات في ذلك التابع زمنًا ثابتًا باستثناء استدعائه للتابعين <code>get</code> و<code>getNode</code> اللذين يستغرقان زمنًا خطّيًّا. وبناءً على ذلك يكون التابع <code>remove</code> خطّيًّا هو الآخر.
</p>

<p>
	بعض الأشخاص عندما يرون عمليتين خطّيّتين أن النتيجة الإجمالية ستكون تربيعيّةً، ولكن هذا ليس صحيحًا إلا إذا كانت إحداهما داخل الأخرى؛ أما إذا استُدعِيت إحداهما تلو الأخرى، فستُحسَب المُحصلة بجمع زمنيهما، ولأن كليهما ينتميان إلى المجموعة O(n)‎، فسينتمي المجموع إلى O(n)‎ أيضًا.
</p>

<h2 id="الموازنة-بين-الصنفين-myarraylist-وmylinkedlist">
	الموازنة بين الصنفين MyArrayList وMyLinkedList
</h2>

<p>
	يُلخِّص الجدول التالي الاختلافات بين الصنفين <code>MyArrayList</code> و<code>MyLinkedList</code>. يشير <code>1</code> إلى المجموعة O(1)‎ أو الزمن الثابت، بينما يشير <code>n</code> إلى المجموعة O(n)‎ أو الزمن الخطّي:
</p>

<table>
	<thead>
		<tr>
			<th>
				 
			</th>
			<th>
				MyArrayList
			</th>
			<th>
				MyLinkedList
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				add (في النهاية)
			</td>
			<td>
				1
			</td>
			<td>
				n
			</td>
		</tr>
		<tr>
			<td>
				add (في البداية)
			</td>
			<td>
				n
			</td>
			<td>
				1
			</td>
		</tr>
		<tr>
			<td>
				add (في العموم)
			</td>
			<td>
				n
			</td>
			<td>
				n
			</td>
		</tr>
		<tr>
			<td>
				get / set
			</td>
			<td>
				1
			</td>
			<td>
				n
			</td>
		</tr>
		<tr>
			<td>
				indexOf / lastIndexOf
			</td>
			<td>
				n
			</td>
			<td>
				n
			</td>
		</tr>
		<tr>
			<td>
				isEmpty / size
			</td>
			<td>
				1
			</td>
			<td>
				1
			</td>
		</tr>
		<tr>
			<td>
				remove (من النهاية)
			</td>
			<td>
				1
			</td>
			<td>
				n
			</td>
		</tr>
		<tr>
			<td>
				remove (من البداية)
			</td>
			<td>
				n
			</td>
			<td>
				1
			</td>
		</tr>
		<tr>
			<td>
				remove (في العموم)
			</td>
			<td>
				n
			</td>
			<td>
				n
			</td>
		</tr>
	</tbody>
</table>

<p>
	<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;

    text-align: center;} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}	</style>
</p>

<p>
	في حالتي إضافة عنصر أو حذفه من نهاية القائمة، فإنّ الصنف <code>MyArrayList</code> هو أفضلُ من نظيره <code>MyLinkedList</code>، وكذلك في عمليتي الاسترجاع والتعديل؛ أمّا في حالتي إضافة عنصر أو حذفه من مقدّمة القائمة، فإن الصنف <code>MyLinkedList</code> هو أفضل من نظيره <code>MyArrayList</code>.
</p>

<p>
	يحظى الصنفان بنفس ترتيب النمو بالنسبة للعمليات الأخرى.
</p>

<p>
	إذًا، أيهما أفضل؟ يعتمد ذلك على العمليات التي يُحتمل استخدامها أكثر، وهذا السبب هو الذي يجعل جافا تُوفِّر أكثر من تنفيذٍ implementation وحيد.
</p>

<h2 id="التشخيص-profiling">
	التشخيص Profiling
</h2>

<p>
	ستحتاج إلى الصنف <code>Profiler</code> في التمرين التالي. يحتوي هذا الصنف على شيفرة بإمكانها أن تُشغِّل تابعًا ما على مشاكلَ ذات أحجامٍ متفاوتةٍ، وتقيس زمن التشغيل لكلٍّ منها، وتَعرِض النتائج.
</p>

<p>
	ستَستخدِم الصنف <code>Profiler</code> لتصنيف أداء التابع <code>add</code> المُعرَّف في كلٍّ من الصنفين <code>ArrayList</code> و<code>LinkedList</code> اللذين تُوفِّرهما <a href="https://academy.hsoub.com/programming/java/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B3%D8%B1%D9%8A%D8%B9-%D9%84%D9%84%D8%BA%D8%A9-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-java-r599/" rel="">لغة جافا</a>.
</p>

<p>
	تُوضِّح الشيفرة التالية طريقة استخدام ذلك الصنف:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8126_7" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> profileArrayListAddEnd</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Timeable</span><span class="pln"> timeable </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Timeable</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">List</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">&gt;</span><span class="pln"> </span><span class="typ">list</span><span class="pun">;</span><span class="pln">

            </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> setup</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">list</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">ArrayList</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">&gt;();</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

            </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> timeMe</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">n</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="typ">list</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="str">"a string"</span><span class="pun">);</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">};</span><span class="pln">

        </span><span class="typ">String</span><span class="pln"> title </span><span class="pun">=</span><span class="pln"> </span><span class="str">"ArrayList add end"</span><span class="pun">;</span><span class="pln">
        </span><span class="typ">Profiler</span><span class="pln"> profiler </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Profiler</span><span class="pun">(</span><span class="pln">title</span><span class="pun">,</span><span class="pln"> timeable</span><span class="pun">);</span><span class="pln">

        </span><span class="typ">int</span><span class="pln"> startN </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4000</span><span class="pun">;</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> endMillis </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">;</span><span class="pln">
        </span><span class="typ">XYSeries</span><span class="pln"> series </span><span class="pun">=</span><span class="pln"> profiler</span><span class="pun">.</span><span class="pln">timingLoop</span><span class="pun">(</span><span class="pln">startN</span><span class="pun">,</span><span class="pln"> endMillis</span><span class="pun">);</span><span class="pln">
        profiler</span><span class="pun">.</span><span class="pln">plotResults</span><span class="pun">(</span><span class="pln">series</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	يقيس التابعُ السابقُ الزمنَ الذي يستغرقه تشغيلُ التابعِ <code>add</code> الذي يُضيف عنصرًا جديدًا في نهاية قائمةٍ من النوع <code>ArrayList</code>. سنشرح الشيفرة أولًا ثم نَعرِض النتائج.
</p>

<p>
	لكي يتمكَّن الصنف <code>Profiler</code> من أداء عمله، سنحتاج أولًا إلى إنشاء كائنٍ من النوع <code>Timeable</code>. يُوفِّر هذا الكائنُ التابعين <code>setup</code> و<code>timeMe</code>، حيث يُنفِّذ التابع <code>setup</code> كل ما ينبغي فعله قبل بدء تشغيل المؤقت، وفي هذا المثال سيُنشِئ قائمةً فارغة، أمّا التابع <code>timeMe</code> فيُنفِّذ العملية التي نحاول قياس أدائها. في هذا المثال، سنجعله يُضيف عددًا من العناصر مقداره n إلى القائمة.
</p>

<p>
	لقد عرَّفنا الشيفرة المسؤولة عن إنشاء المتغير <code>timeable</code> ضمن صنفٍ مجهول الاسم anonymous، حيث يُعرِّف ذلك الصنف تنفيذًا جديدًا للواجهة <code>Timeable</code>، ويُنشِئ نسخةً من الصنف الجديد في نفس الوقت. ولكنك على كل حالٍ لست في حاجةٍ إلى معرفة الكثير عنها لحل التمرين التالي، ويُمكِنك نسخ شيفرة المثال وتعديلها.
</p>

<p>
	والآن سننتقل إلى الخطوة التالية، وهي إنشاء كائن من الصنف <code>Profiler</code> مع تمرير معاملين له هما: العنوان title وكائن من النوع <code>Timeable</code>.
</p>

<p>
	يحتوي الصنف <code>Profiler</code> على التابع <code>timingLoop</code>. يستخدم ذلك التابعُ الكائنَ <code>Timeable</code> المُخزَّن مثل متغيِّرِ نُسْخَةٍ instance variable، حيث يَستدعِي تابعه <code>timeMe</code> عدة مراتٍ مع قيم مختلفةٍ لحجم المشكلة <code>n</code> في كل مرة. ويَستقبِل التابع <code>timingLoop</code> المعاملين التاليين:
</p>

<ul>
	<li>
		<code>startN</code>: هي قيمة <code>n</code> التي تبدأ منها الحلقة.
	</li>
	<li>
		<code>endMillis</code>: عبارة عن قيمة قصوى بوحدة الميلي ثانية. يزداد زمن التشغيل عندما يُزيد التابع <code>timingLoop</code> حجم المشكلة، وعندما يتجاوز ذلك الزمنُ القيمةَ القصوى المُحدّدة، فينبغي أن يتوقف التابع <code>timingLoop</code>.
	</li>
</ul>

<p>
	قد تضطّر إلى ضبط قيم تلك المعاملات عند إجراء تلك التجارب، فإذا كانت قيمة <code>startN</code> ضئيلةً للغاية، فلن يكون زمن التشغيل طويلًا بما يكفي لقياسه بدقّة، وإذا كانت قيمة <code>endMillis</code> صغيرةً للغاية، فقد لا تحصل على بياناتٍ كافيةٍ لاستنباط العلاقة بين حجم المشكلة وزمن التشغيل.
</p>

<p>
	ستجِد تلك الشيفرة -التي ستحتاج إليها في التمرين التالي- في الملف <code>ProfileListAdd.java</code>، والتي حصلنا عند تشغيلها على الخرج التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8126_9" style=""><span class="lit">4000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="lit">8000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="lit">16000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
</span><span class="lit">32000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pln">
</span><span class="lit">64000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="lit">128000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
</span><span class="lit">256000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">18</span><span class="pln">
</span><span class="lit">512000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">30</span><span class="pln">
</span><span class="lit">1024000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">88</span><span class="pln">
</span><span class="lit">2048000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">185</span><span class="pln">
</span><span class="lit">4096000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">242</span><span class="pln">
</span><span class="lit">8192000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">544</span><span class="pln">
</span><span class="lit">16384000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1325</span></pre>

<p>
	يُمثِل العمود الأول حجم المشكلة n، أما العمود الثاني فيُمثِل زمن التشغيل بوحدة الميلي ثانية. كما تلاحظ، فالقياسات القليلة الأولى ليست دقيقةً تمامًا وليس لها مدلول حقيقي، ولعلّه كان من الأفضل ضبط قيمة <code>startN</code> إلى 64000.
</p>

<p>
	يُعيد التابعُ <code>timingLoop</code> النتائجَ بهيئة كائن من النوع <code>XYSeries</code>، ويُمثِل متتاليةً تحتوي على القياسات. إذا مرَّرتها إلى التابع <code>plotResults</code>، فإنه يَرسِم شكلًا بيانيًا -مشابها للموجود في الصورة التالية- وسنشرحه طبعًا في القسم التالي.
</p>

<p style="text-align: center;">
	<code><code><img alt="001Profiling_Results.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="80449" data-unique="5ck156r91" style="" src="https://academy.hsoub.com/uploads/monthly_2021_10/001Profiling_Results.PNG.3cb963dbd47766fdade10fba52cfc74f.PNG"></code> </code>
</p>

<h2 id="تفسير-النتائج">
	تفسير النتائج
</h2>

<p>
	بناءً على فهمنا لكيفية عمل الصنف <code>ArrayList</code>، فإننا نتوقَّع أن يستغرق التابع <code>add</code> زمنًا ثابتًا عندما نضيف عناصرَ إلى نهاية القائمة، وبالتالي ينبغي أن يكون الزمنُ الكلّيُّ لإضافة عددٍ من العناصر مقداره n زمنًا خطيًا.
</p>

<p>
	لكي نختبر صحة تلك النظرية، سنَعرِض تأثير زيادة حجم المشكلة على زمن التشغيل الكلّي. من المفترض أن نحصل على خطٍّ مستقيمٍ على الأقل لأحجام المشكلة الكبيرة بالقدر الكافي لقياس زمن التشغيل بدقة. ويُمكِننا كتابةُ دالّة هذا الخط المستقيم رياضيًّا على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5919_21" style=""><code>
<code>
<span class="pln">runtime </span><span class="pun">=</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">*</span><span class="pln">n</span></code></code></pre>

<p>
	حيث يشير <code>a</code> إلى إزاحةِ الخط وهو قيمة ثابتة و <code>b</code> إلى ميل الخط.
</p>

<p>
	في المقابل، إذا كان التابع <code>add</code> خطّيًّا، فسيكون الزمن الكليُّ لتنفيذ عددٍ من الإضافات بمقدار n تربيعيًا. وعندها إذا نظرنا إلى تأثير زيادة حجم المشكلة على زمن التشغيل، فسنتوقَّع الحصول على قطعٍ مكافئٍ parabola، والذي يُمكِن كتابة معادلته رياضيًّا على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5919_17" style=""><code>
<code>
<span class="pln">runtime </span><span class="pun">=</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">*</span><span class="pln">n </span><span class="pun">+</span><span class="pln"> c</span><span class="pun">*</span><span class="pln">n</span><span class="pun">^</span><span class="lit">2</span></code></code></pre>

<p>
	إذا كانت القياسات التي حصلنا عليها دقيقةً فسنتمكَّن بسهولةٍ من التمييز بين الخط المستقيم والقطع المكافئ، أمّا إذا لم تكن دقيقةً تمامًا، فقد يكون تمييز ذلك صعبًا إلى حدٍّ ما، وعندئذٍ يُفضّلُ استخدام مقياس لوغاريتمي-لوغاريتمي log-log لعرض تأثير حجم المشكلة على زمن التشغيل.
</p>

<p>
	ولِنَعرِفَ السببَ، لنفترض أن زمن التشغيل يتناسب مع n<sup>k</sup>‎، ولكننا لا نعلم قيمة الأس k. يُمكِننا كتابة تلك العلاقة على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8126_11" style=""><span class="pln">runtime </span><span class="pun">=</span><span class="pln"> a </span><span class="pun">+</span><span class="pln"> b</span><span class="pun">*</span><span class="pln">n </span><span class="pun">+</span><span class="pln"> </span><span class="pun">…</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> c</span><span class="pun">*</span><span class="pln">n</span><span class="pun">^</span><span class="pln">k</span></pre>

<p>
	كما ترى في المعادلة السابقة، فإنّ الأساس ذا الأسِّ الأكبر هو الأهم من بين القيم الكبيرة لحجم المشكلة، وبالتالي يُمكِن تقريبيًّا إهمال باقي الحدود وكتابة العلاقة على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8126_13" style=""><span class="pln">runtime </span><span class="pun">≈</span><span class="pln"> c </span><span class="pun">*</span><span class="pln"> n</span><span class="pun">^</span><span class="pln">k </span></pre>

<p>
	حيث نعني بالرمز ≈ "يساوي تقريبًا"، فإذا حسبنا اللوغاريتم لطرفي المعادلة، فستصبح مثل الآتي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8126_15" style=""><span class="pln">log</span><span class="pun">(</span><span class="pln">runtime</span><span class="pun">)</span><span class="pln"> </span><span class="pun">≈</span><span class="pln"> log</span><span class="pun">(</span><span class="pln">c</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> k</span><span class="pun">*</span><span class="pln">log</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span></pre>

<p>
	تعني المعادلة السابقة أنه لو رسمنا زمن التشغيل مقابل حجم المشكلة n باستخدام مقياس لوغاريتمي-لوغاريتمي، فسنرى خطًا مستقيمًا بثابتٍ -يمثل الإزاحة- يساوي log(c)‎ وبميل يساوي k. لا يهمنا الثابت هنا وإنما يهمنا الميل k، فهو الذي يشير إلى ترتيب النمو. وزبدةُ الكلام أنه إذا كانت قيمة k تساوي 1، فالخوارزميةُ خطيّة؛ أما إذا كانت تساوي 2، فالخوارزمية تربيعيّة.
</p>

<p>
	إذا تأمّلنا في الرسم البيانيّ السابق، يُمكِننا أن نُقدِّر قيمة المَيْلِ تقريبيًا، في حين لو استدعينا التابع <code>plotResults</code>، فسيحسب قيمة الميل بتطبيق طريقة المربعات الدنيا least squares fit على القياسات، ثم يَطبَعه. و قد كانت قيمة الميل التي حصل عليها التابع:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_8126_17" style=""><span class="typ">Estimated</span><span class="pln"> slope </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1.06194352346708</span></pre>

<p>
	أي تقريبًا يساوي 1. إذًا فالزمنُ الكلّيّ لإجراء عدد مقداره n من الإضافات هو زمن خطي، وزمن كل إضافة منها ثابت كما توقعنا.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<em>نقطة مهمة</em> إذا رأيت خطًا مستقيمًا في رسمة مشابهة للرسمة السابقة، فهذا لا يَعنِي بالضرورة أن الخوارزميّة خطّيّة. إذا كان زمن التشغيل متناسبًا مع n<sup>k</sup>‎ لأي أس k، فمن المتوقع أن نرى خطًا مستقيمًا ميله يساوي k. فإذا كان الميل أقرب للواحد الصحيح، فمن المُرجَّح أن تكون الخوارزمية خطية؛ أما إذا كان أقرب لاثنين، فيُحتمَل أن تكون تربيعية.
	</p>
</blockquote>

<h2>
	تمرين 4
</h2>

<p>
	ستجد ملفات الشيفرة المطلوبة لهذا التمرين في <a href="https://github.com/AllenDowney/ThinkDataStructures" rel="external nofollow">مستودع الكتاب</a>.
</p>

<ol start="">
	<li>
		<code>Profiler.java</code>: يحتوي على تنفيذ الصنف <code>Profiler</code> الذي شرحناه فيما سبق. ستَستخدِم ذلك الصنف، ولن تحتاج لفهم طريقة عمله، ومع ذلك يُمكِنك الاطلاع على شيفرته إن أردت.
	</li>
	<li>
		<code>ProfileListAdd.java</code>: يحتوي على شيفرة تشغيل التمرين، بما في ذلك المثال العلوي الذي شخَّصنا خلاله التابع <code>ArrayList.add</code>. ستُعدِّل هذا الملف لتُجرِي التشخيص على القليل من التوابع الأخرى.
	</li>
</ol>

<p>
	ستجد ملف البناء <code>build.xml</code> في المجلد <code>code</code> أيضًا.
</p>

<p>
	نفِّذ الأمر <code>ant ProfileListAdd</code> لكي تُشغِّل الملف <code>ProfileListAdd.java</code>. ينبغي أن تحصل على نتائج مشابهة للصورة المُرفقة في الأعلى، ولكنك قد تضطّر إلى ضبط قيمة المعاملين <code>startN</code> و<code>endMillis</code>. ينبغي أن يكون الميل المُقدَّر قريبًا من 1، مما يَعني أن تنفيذ عدد n من عمليات الإضافة يستغرق زمنًا متناسبًا مع n مرفوعة للأس 1، أي ينتمي إلى المجموعة O(n)‎.
</p>

<p>
	ستجد تابعًا فارغًا في الملف <code>ProfileListAdd.java</code> اسمه كالآتي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_7981_7" style=""><span class="pln"> profileArrayListAddBeginning </span></pre>

<p>
	عندها املأه بشيفرةٍ تفحص التابع <code>ArrayList.add</code> جاعلًا إياه يُضيِف العنصر الجديد دائمًا إلى بداية القائمة. إذا نَسخَت شيفرة التابع <code>profileArrayListAddEnd</code>، فستحتاج فقط إلى إجراء القليل من التعديلات. في الأخير، أضف سطرًا ضمن التابع <code>main</code> لاستدعاء تلك الدالة.
</p>

<p>
	نفِّذ الأمر <code>ant ProfileListAdd</code> مرةً أخرى وفسِّر النتائج. بناءً على فهمنا لطريقة عمل الصنف <code>ArrayList</code>، فإننا نتوقَّع أن تَستغرِق عملية الإضافة الواحدة زمنًا خطيًا، وبالتالي سيكون الزمن الكلي الذي يَستغرِقه عدد مقداره n من الإضافات تربيعيًا. إن كان ذلك صحيحًا، فإن الميل المُقدَّر للخط بمقياس لوغاريتمي-لوغاريتمي ينبغي أن يكون قريبًا من 2.
</p>

<p>
	بعد ذلك، وازن ذلك الأداء مع أداء الصنف <code>LinkedList</code>. املأ متن التابع الآتي واستخدمه لتصنيف التابع <code>LinkedList.add</code> بينما يُضيِف عنصرًا جديدًا إلى بداية القائمة:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_7981_9" style=""><span class="pln">profileLinkedListAddBeginning</span></pre>

<p>
	أخيرًا، املأ متن التابع <code>profileLinkedListAddEnd</code>، واِستخدَمه لتصنيف التابع <code>LinkedList.add</code> بينما يُضيِف عنصرًا جديدًا إلى نهاية القائمة. ما الأداء الذي تتوقعه؟ وهل تتوافق النتائج مع تلك التوقعات؟
</p>

<p>
	سنَعرِض النتائج ونجيب على تلك الأسئلة في المقالة التالية.
</p>

<p>
	ترجمة -بتصرّف- للفصل <a href="https://greenteapress.com/thinkdast/html/thinkdast005.html" rel="external nofollow">Chapter 4: LinkedList</a> من كتاب <a href="https://greenteapress.com/thinkdast/html/index.html" rel="external nofollow">Think Data Structures: Algorithms and Information Retrieval in Java</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/advance/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D8%A7%D8%B2%D8%AF%D9%88%D8%A7%D8%AC%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B1%D8%A7%D8%A8%D8%B7-r1350/" rel="">تحليل زمن تشغيل القوائم المنفذة باستخدام قائمة ازدواجية الترابط</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A9-r1348/" rel="">تحليل زمن تشغيل القوائم المنفذة باستخدام مصفوفة</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1349</guid><pubDate>Mon, 01 Nov 2021 16:00:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62E;&#x648;&#x627;&#x631;&#x632;&#x645;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x634;&#x631;&#x647;&#x629; Greedy Algorithms</title><link>https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D8%B1%D9%87%D8%A9-greedy-algorithms-r1366/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/617d0246a3fca_GreedyAlgorithms-01.jpg.227ccedd7a68ad64847d391d72ad211b.jpg" /></p>

<p>
	الخوارزمية الشرهة هي كل خوارزمية تسعى إلى حل مشكلةٍ عبر البحث عن أفضل خيار في كل مرحلة جزئية من أجل إيجاد الحل الشامل والمثالي، ولهذا تُسمّى شرهة، إذ تحاول أن تبحث عن أفضل الخيارات في كل مرحلة ممكنة، ولا تأخذ بالضرورة كل المراحل بالحسبان، ولذلك لا تعطي الحل المثالي دائمًا لكامل المشكلة، وإنّما تعطي حلًا مؤلفًا من حلول جزئية مثالية، والتي تكون عادةً قريبةً إلى حدّ ما من الحل الشامل المثالي في مدة زمنية معقولة.
</p>

<h2>
	ترميز هوفمان Human Coding
</h2>

<p>
	<a href="https://ar.wikipedia.org/wiki/%D8%AA%D8%B1%D9%85%D9%8A%D8%B2_%D9%87%D9%88%D9%81%D9%85%D8%A7%D9%86" rel="external nofollow">ترميز هوفمان</a> هو نوع خاص من الترميز المُحسّن optimal prefix code الذي يُستخدم في الضغط المحافظ على البيانات lossless data compression، إذ تضغط هذه الخوارزمية البيانات بفعالية كبيرة، بحيث يمكن أن تختزل من 20٪ إلى 90٪ من مساحة الذاكرة تبعًا لخصائص البيانات المضغوطة.
</p>

<p>
	ونحن ننظر إلى البيانات التي سنعمل عليها على أنها سلاسل من الحروف، تبدأ خوارزمية هوفمان الشرهة Huﬀman's greedy algorithm بإنشاء جدول يحدّد عدد مرات ظهور كل حرف (أي تردّده)، وبناءً على ذلك تنشئ الترميز المثالي لتمثيل كل حرف على هيئة سلسلة من القيم الثنائية (0 و 1). وقد اقتُرِحت هذه الخوارزمية على يد <a href="https://ar.wikipedia.org/wiki/%D8%AF%D9%8A%D9%81%D9%8A%D8%AF_%D9%87%D9%88%D9%81%D9%85%D8%A7%D9%86" rel="external nofollow">ديفيد هوفمان</a> في عام 1951.
</p>

<p>
	لنفترض أنّ لدينا ملفًّا يحتوي بيانات مؤلفة من 100000 محرف، ونود ضغطها في أقل مساحة ممكنة. سنفترض أنّ هناك 6 أحرف مختلفة فقط في الملف. وأنّ تردّد الأحرف هو كالتالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6591_7" style="">
<span class="pun">+---------------------------------+-----+-----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">        </span><span class="typ">Character</span><span class="pln">                </span><span class="pun">|</span><span class="pln">   a </span><span class="pun">|</span><span class="pln">  b  </span><span class="pun">|</span><span class="pln">  c  </span><span class="pun">|</span><span class="pln">  d  </span><span class="pun">|</span><span class="pln">  e  </span><span class="pun">|</span><span class="pln">  f  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---------------------------------+-----+-----+-----+-----+-----+-----+</span><span class="pln">
</span><span class="pun">|</span><span class="typ">Frequency</span><span class="pln"> </span><span class="pun">(</span><span class="pln">in thousands</span><span class="pun">)</span><span class="pln">         </span><span class="pun">|</span><span class="pln">  </span><span class="lit">45</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">13</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">12</span><span class="pln"> </span><span class="pun">|</span><span class="pln">  </span><span class="lit">16</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">9</span><span class="pln">   </span><span class="pun">|</span><span class="pln">  </span><span class="lit">5</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---------------------------------+-----+-----+-----+-----+-----+-----+</span></pre>

<p>
	لدينا عدة خيارات لتمثيل هذه البيانات، وسنحاول فيما يلي تصميم ترميز ثنائي للمحارف Binary Character Code، بحيث نمثّل كلّ حرف بسلسلة ثنائية فريدة سنسميها codeword أو الكلمة الرمزية.
</p>

<p style="text-align: center;">
	<img alt="VP5UP.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="81270" data-unique="93q8e2ojl" src="https://academy.hsoub.com/uploads/monthly_2021_10/VP5UP.jpg.468a6ce8fcb74a073501b5ffd4a2fc77.jpg" style="width: 600px; height: auto;"></p>

<p>
	هذان الترميزان مشتقّان من الشجرة أعلاه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6591_9" style="">
<span class="pun">+----------------------------------+-----+-----+-----+-----+------+------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">        </span><span class="typ">Character</span><span class="pln">                 </span><span class="pun">|</span><span class="pln">  a  </span><span class="pun">|</span><span class="pln">   b </span><span class="pun">|</span><span class="pln">  c  </span><span class="pun">|</span><span class="pln">  d  </span><span class="pun">|</span><span class="pln">   e  </span><span class="pun">|</span><span class="pln">  f   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----------------------------------+-----+-----+-----+-----+------+------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln"> </span><span class="typ">Fixed</span><span class="pun">-</span><span class="pln">length </span><span class="typ">Codeword</span><span class="pln">            </span><span class="pun">|</span><span class="pln"> </span><span class="lit">000</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">001</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">010</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">011</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">100</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">101</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----------------------------------+-----+-----+-----+-----+------+------+</span><span class="pln">
</span><span class="pun">|</span><span class="typ">Variable</span><span class="pun">-</span><span class="pln">length </span><span class="typ">Codeword</span><span class="pln">          </span><span class="pun">|</span><span class="pln">  </span><span class="lit">0</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="lit">101</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">100</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">111</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1101</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="lit">1100</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----------------------------------+-----+-----+-----+-----+------+------+</span></pre>

<p>
	إذا أردنا استخدام ترميز ثابت الطول فسنحتاج إلى ثلاث بتّات bit لتمثيل الأحرف الستة. تتطلّب هذه الطريقة 300000 بتّة لتخزين الملف بأكمله. والسؤال الآن، هل هذا أفضل ترميز ممكن؟
</p>

<p>
	هناك نوع آخر من الترميز، وهو ترميز متغيّر الطول، أي أنّ الشيفرات التي تمثّل الحروف قد تكون من أطوال مختلفة، قد يكون أفضل بكثير من الترميز ثابت الطول، إذ أنّه يُرشِّد المساحة المُستخدمة لتخزين البيانات عبر إعطاء الأحرف الكثيرة التكرار/التردد شيفرات قصيرة، فيما يترك الشيفرات الطويلة للأحرف قليلة التردّد.
</p>

<p>
	ويتطلب هذا الترميز الآتي:<br>
	 
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2661_7" style="">
<span class="pln"> ‎‎(45 X 1 + 13 X 3 + 12 X 3 + 16 X 3 + 9 X 4 + 5 X 4) X 1000 = 224000
</span></pre>

<p>
	بتّةً لتمثيل الملف، أي أنّه يقتص على حوالي 25% من مساحة الذاكرة موازنة بالتمثيل ثابت الطول.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		<strong>تنبيه:</strong> لا نأخذ بالحسبان الترميزات التي تكون فيها كلمة رمزية codeword لحرف معيّن سابقةً preﬁx لكلمة رمزية أخرى، والتي يُطلق عليها ترميزات سابقة preﬁx codes. فمثلًا، في الترميز متغير الطول، سنرمّز السلسة النصية الثلاثية <code>abc</code> بالترميز 0.101.100 = 0101100، حيث تمثّل النقطة <code>.</code> عمليّة الضمّ concatenation.
	</p>
</blockquote>

<p>
	تبسّط ترميزات السوابق Preﬁx codes عمليّة فك الترميز decoding، فما دام من غير الممكن أن يكون أيّ ترميز كلميّ سابقة لترميز كلميّ آخر، فإنّ الترميز الكلميّ الذي يبدأ ترميز الملف لن يكون فيه أيّ لبس، لهذا يمكننا بسهولة تحديد الترميز الكلميّ الأولي، ثمّ ترجمته إلى الحرف الأصلي الذي يرمز له، ثمّ تكرار عملية فك الترميز على بقية الملف المُرمّز. على سبيل المثال، هناك طريقة واحدة فقط لفك ترميز 001011101، وهي 0.0.101.1101، لتي تُترجم إلى aabe.
</p>

<p>
	باختصار، ستكون جميع توليف التمثيلات الثنائية مختلفةً عن بعضها، فإذا رمزنا لحرف ما بالترميز الكلمي 110 مثلًا، فلا يمكن ترميز أيّ حرف آخر بترميز كلمي يبدأ بالترميز السابق، مثل 1101 أو 1100. وهذا لمنع اللبس أثناء فك الترميز، وتجنّب أيّ ارتباك حول ما إذا كان علينا اختيار 110 أو الاستمرار في تحليل التسلسل البتّي.
</p>

<h3>
	تقنيات الضغط
</h3>

<p>
	تعمل تقنية الضغط عبر إنشاء شجرة ثنائية من العقد، يمكن تخزينها في مصفوفة عادية حجمها (n) يساوي عدد الرموز، وكل عقدة يمكن أن تكون إما ورقة leaf أو عقدة داخلية internal node.
</p>

<p>
	وتكون جميع العقد في البداية عبارة عن أوراق، تحتوي كل ورقة الرمز المراد تمثيله إلى جانب تردّده، ورابطًا اختياريًا يشير إلى ابنيها child nodes. ونصطلح في العادة على تمثيل الابن الأيسر بالبتّة '0'، فيما تمثّل البتة '1' الابن الأيمن، وتُخزّن العقد في <a href="https://ar.wikipedia.org/wiki/%D8%B1%D8%AA%D9%84_(%D8%A8%D9%86%D9%8A%D8%A9_%D9%85%D8%B9%D8%B7%D9%8A%D8%A7%D8%AA)" rel="external nofollow">رتل أو طابور</a>، وعند استخراج قيمة منه، يعيد العقدة ذات التردد الأقل.
</p>

<p>
	وهذه هي خطوات العملية:
</p>

<ol>
<li>
		أنشئ ورقةً لكلّ رمز، ثمّ أضفه إلى رتل الأولويات.
	</li>
	<li>
		طالما يحتوي الطابور أكثر من عقدة واحدة:
	</li>
</ol>
<ul style="margin-right: 40px;">
<li>
		انزع العقدتين ذواتي أكبر أولوية من الطابور.
	</li>
	<li>
		أنشئ عقدةً داخليةً جديدة، مع جعل العُقدتين اللتان استخرجتَهما من الطابور أبناءً لها، بحيث يساوي التردّد مجموع تردّدي العقدتين.
	</li>
	<li>
		أضف العقدة الجديدة إلى الطابور.
	</li>
	<li>
		العقدة المتبقية هي العقدة الجذرية، وبهذا نكون قد أكملنا شجرة هوفمان.
	</li>
</ul>
<p>
	انظر إلى الأمثلة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="81269" href="https://academy.hsoub.com/uploads/monthly_2021_10/mOobp.jpg.8407f078c919f4e8d478b0039b2c84d6.jpg" rel=""><img alt="mOobp.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="81269" data-unique="d5gx47rfm" src="https://academy.hsoub.com/uploads/monthly_2021_10/mOobp.thumb.jpg.541ba1e17525cedc9d302619756cb2be.jpg" style="width: 600px; height: auto;"></a>
</p>

<p>
	ستبدو الشيفرة التوضيحية pseudo-code كالتالي، حيث أن C هي مجموعة المحارف والمعلومات ذات الصلة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9300_17" style="">
<span class="typ">Procedure</span><span class="pln"> </span><span class="typ">Huffman</span><span class="pun">(</span><span class="pln">C</span><span class="pun">):</span><span class="pln">  
n </span><span class="pun">=</span><span class="pln"> C</span><span class="pun">.</span><span class="pln">size
Q </span><span class="pun">=</span><span class="pln"> priority_queue</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to n
    n </span><span class="pun">=</span><span class="pln"> node</span><span class="pun">(</span><span class="pln">C</span><span class="pun">[</span><span class="pln">i</span><span class="pun">])</span><span class="pln">
    Q</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln">
end </span><span class="kwd">for</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> Q</span><span class="pun">.</span><span class="pln">size</span><span class="pun">()</span><span class="pln"> is not equal to </span><span class="lit">1</span><span class="pln">
    Z </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> node</span><span class="pun">()</span><span class="pln">
    Z</span><span class="pun">.</span><span class="pln">left </span><span class="pun">=</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> Q</span><span class="pun">.</span><span class="pln">pop
    Z</span><span class="pun">.</span><span class="pln">right </span><span class="pun">=</span><span class="pln"> y </span><span class="pun">=</span><span class="pln"> Q</span><span class="pun">.</span><span class="pln">pop
    Z</span><span class="pun">.</span><span class="pln">frequency </span><span class="pun">=</span><span class="pln"> x</span><span class="pun">.</span><span class="pln">frequency </span><span class="pun">+</span><span class="pln"> y</span><span class="pun">.</span><span class="pln">frequency
    Q</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="pln">Z</span><span class="pun">)</span><span class="pln">
end </span><span class="kwd">while</span><span class="pln">
</span><span class="typ">Return</span><span class="pln"> Q</span></pre>

<p>
	يتطلب استخدام الخوارزمية في الحالات العامة إجراء عملية ترتيب مسبق للمصفوفة المُدخلة. ويمثّل n عدد الرموز في الأبجدية، ويكون عادةً صغيرًا جدًّا (موازنةً بطول الرسالة المراد ترميزها)، لذا فإنّ تعقيد الوقت ليس مهمًا جدًا في اختيار هذه الخوارزمية.
</p>

<h4>
	تقنيات فك الضغط Decompression
</h4>

<p>
	فك الضغط هو عملية ترجمة تدفق من ترميزات السوابق preﬁx codes إلى بايتات فردية، وعادةً عن طريق تسلّق الشجرة عقدة بعقدة مع قراءة كل بتّة من المدخلات. يؤدّي الوصول إلى ورقة إلى إنهاء البحث عن قيمة البايت المضغوط، حيث تمثل قيمة الورقة الحرفَ المطلوب.
</p>

<p>
	وعادةً ما تُنشأ شجرة هوفمان باستخدام بيانات معدّلة إحصائيًا في كل دورة ضغط، وعليه فإنّ إعادة البناء بسيطة إلى حدّ ما؛ أما خلاف ذلك، فيجب إرسال المعلومات اللازمة لإعادة بناء الشجرة بشكل منفصل. انظر الشيفرة التوضيحية التالية، تمثل <code>root</code> جذر شجرة هوفمان، بينما تمثل <code>S</code> تدفق البتات المراد ضغطه:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_9300_19" style="">
<span class="typ">Procedure</span><span class="pln"> </span><span class="typ">HuffmanDecompression</span><span class="pun">(</span><span class="pln">root</span><span class="pun">,</span><span class="pln"> S</span><span class="pun">):</span><span class="pln">   
n </span><span class="pun">:=</span><span class="pln"> S</span><span class="pun">.</span><span class="pln">length                           
</span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">:=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to n
   current </span><span class="pun">=</span><span class="pln"> root
   </span><span class="kwd">while</span><span class="pln"> current</span><span class="pun">.</span><span class="pln">left </span><span class="pun">!=</span><span class="pln"> NULL </span><span class="kwd">and</span><span class="pln"> current</span><span class="pun">.</span><span class="pln">right </span><span class="pun">!=</span><span class="pln"> NULL
       </span><span class="kwd">if</span><span class="pln"> S</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="kwd">is</span><span class="pln"> equal to </span><span class="str">'0'</span><span class="pln">
           current </span><span class="pun">:=</span><span class="pln"> current</span><span class="pun">.</span><span class="pln">left
       </span><span class="kwd">else</span><span class="pln">
           current </span><span class="pun">:=</span><span class="pln"> current</span><span class="pun">.</span><span class="pln">right
       endif
       i </span><span class="pun">:=</span><span class="pln"> i</span><span class="pun">+</span><span class="lit">1</span><span class="pln">
   endwhile
   </span><span class="kwd">print</span><span class="pln"> current</span><span class="pun">.</span><span class="pln">symbol
endfor</span></pre>

<p>
	يحسب ترميز هوفمان تردّد كل محرف ويخزّنه على هيئة سلسلة ثنائية، وتتمثل فكرة الخوارزمية هنا في تعيين ترميزات متغيرة الأطوال للمحارف المُدخلة، بحيث يستند طول الترميزات على تردّدات الأحرف المقابلة، وذلك عبر إنشاء شجرة ثنائية والعمل عليها تصاعديًا حتى يكون الحرفان الأقل ترددًا بعيدين قدر الإمكان عن الجذر. وبهذه الطريقة سيحصل الحرف الأكثر تردّدًا على أقصر ترميز، بينما يحصل الحرف الأقل تردّدًا على أطول ترميز.
</p>

<h3>
	مشكلة اختيار الأنشطة Activity Selection Problem
</h3>

<p>
	لنفترض أنّ لديك مجموعةً من المهام التي عليك إنجازها (أنشطة)، بحيث لكل نشاط وقت بداية ووقت نهاية. ولا يُسمح لك بأداء أكثر من نشاط واحد في كلّ مرّة. السؤال الآن هو كيف تعثر على طريقة لأداء أقصى عدد ممكن من الأنشطة.
</p>

<p>
	على سبيل المثال، لنفترض أنّ لديك مجموعةً من الأقسام الدراسية للاختيار من بينها.
</p>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;
    text-align: center;
} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<table>
<thead><tr>
<th>
				النشاط رقم
			</th>
			<th>
				وقت البداية
			</th>
			<th>
				وقت النهاية
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				1
			</td>
			<td>
				10.20 صباحا
			</td>
			<td>
				11.00 صباحا
			</td>
		</tr>
<tr>
<td>
				2
			</td>
			<td>
				10.30 صباحا
			</td>
			<td>
				11.30 صباحا
			</td>
		</tr>
<tr>
<td>
				3
			</td>
			<td>
				11.00 صباحا
			</td>
			<td>
				12.00 صباحا
			</td>
		</tr>
<tr>
<td>
				4
			</td>
			<td>
				10.00 صباحا
			</td>
			<td>
				11.30 صباحا
			</td>
		</tr>
<tr>
<td>
				5
			</td>
			<td>
				9.00 صباحا
			</td>
			<td>
				11.00 صباحا
			</td>
		</tr>
</tbody>
</table>
<p>
	تذكّر أنه لا يمكنك أخذ فصلين دراسيين متداخلين، وهذا يعني أنه لا يمكنك أخذ الفصل 1 و2، لأنهما يتشاركان في الفترة من 10:30 صباحًا إلى 11.00 صباحًا. بالمقابل، يجوز لك أخذ الفصلين 1 و3، لأنهما لا يتشاركان أيّ وقت.
</p>

<p>
	عليك الآن أن تختار الفصول بطريقة تتيح لك أخذ أكبر عدد ممكن من الفصول دون أي تداخل، لكن كيف تفعل هذا؟
</p>

<h3>
	تحليل الجدول الزمني للفصول
</h3>

<p>
	هذه بعض الطرق الممكنة لحل المشكلة:
</p>

<ul>
<li>
		ترتيب الأنشطة بحسب وقت البداية: هذا يعني أنّنا سنأخذ النشاطات التي تبدأ أولًا، ثم نأخذ النشاطات من القائمة المُرتّبة من النشاط الأوّل إلى الأخير، ونتحقق ممّا إذا كان كل نشاط يتداخل مع النشاط الذي اخترناه سابقًا أم لا. إذا لم يكن هناك تداخل بين النشاطين، فسننفّذ النشاط، وإلا لن ننفّذه. تُعَد هذه الطريقة صالحةً لبعض الحالات، كما في المثال التالي:
	</li>
</ul>
<table>
<thead><tr>
<th>
				النشاط رقم
			</th>
			<th>
				وقت البداية
			</th>
			<th>
				وقت النهاية
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				1
			</td>
			<td>
				11.00 صباحا
			</td>
			<td>
				1.30 مساء
			</td>
		</tr>
<tr>
<td>
				2
			</td>
			<td>
				11.30 صباحا
			</td>
			<td>
				12.00 ظهرًا
			</td>
		</tr>
<tr>
<td>
				3
			</td>
			<td>
				1.30 مساء
			</td>
			<td>
				2.00 مساء
			</td>
		</tr>
<tr>
<td>
				4
			</td>
			<td>
				10.00 صباحا
			</td>
			<td>
				11.00 صباحا
			</td>
		</tr>
</tbody>
</table>
<p>
	سنحصل على هذا الترتيب 4 -&gt; 1 -&gt; 2 -&gt; 3، وسننفّذ الأنشطة 4 -&gt; 1 -&gt; 3، ونتخطّى النشاط 2. وهذا يعني أننا سننفّذ 3 نشاطات، وهو الحد الأقصى الممكن. بهذا تكون طريقتنا قد نجحت إذًا في هذه الحالة، لكن هذا لا يعني أنّها ستنجح دائمًا، إذ هناك حالات يمكن أن تفشل فيها. كما يبيّن المثال التالي:
</p>

<table>
<thead><tr>
<th>
				النشاط رقم
			</th>
			<th>
				وقت البداية
			</th>
			<th>
				وقت النهاية
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				1
			</td>
			<td>
				11.00 صباحا
			</td>
			<td>
				1.30 مساء
			</td>
		</tr>
<tr>
<td>
				2
			</td>
			<td>
				11.30 صباحا
			</td>
			<td>
				12.00 ظهرًا
			</td>
		</tr>
<tr>
<td>
				3
			</td>
			<td>
				1.30 مساء
			</td>
			<td>
				2.00 مساء
			</td>
		</tr>
<tr>
<td>
				4
			</td>
			<td>
				10.00 صباحا
			</td>
			<td>
				3.00 صباحا
			</td>
		</tr>
</tbody>
</table>
<p>
	سنحصل على الترتيب التالي: 4 -&gt; 1 -&gt; 2 -&gt; 3، ولن يُنفّذ إلا النشاط 4، أي نشاط واحد وحسب، لكنّنا نعلم أنّ الإجابة الأمثل هي 1 -&gt; 3 أو 2- -&gt; 3، وذلك لأنه في كلا الحالتين سنحضر فصلين دراسيين، وهذا يبيّن أنّ طريقتنا لم تنجح في الحالة المذكورة أعلاه، وذلك لنجرّب طريقةً أخرى.
</p>

<ul>
<li>
		ترتيب الأنشطة بحسب مددها الزمنية: هذا يعني تنفيذ أقصر الأنشطة أولًا. ستحل هذه الطريقة المشكلة السابقة، لكنها ليست كاملةً أيضًا، فلا تزال هناك بعض الحالات التي لا يمكن أن تحلها. ولنطبق الطريقة على الحالة التالية:
	</li>
</ul>
<table>
<thead><tr>
<th>
				النشاط رقم
			</th>
			<th>
				وقت البداية
			</th>
			<th>
				وقت النهاية
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				1
			</td>
			<td>
				6.00 صباحا
			</td>
			<td>
				11.40 صباحا
			</td>
		</tr>
<tr>
<td>
				2
			</td>
			<td>
				11.30 صباحا
			</td>
			<td>
				12.00 ظهرًا
			</td>
		</tr>
<tr>
<td>
				3
			</td>
			<td>
				11.40 صباحا
			</td>
			<td>
				2.00 مساء
			</td>
		</tr>
</tbody>
</table>
<p>
	إذا رتّبنا الأنشطة بحسب مددها الزمنية فسنحصل على الترتيب 2 -&gt; 3 -&gt; 1، لكن إن نفّذنا النشاط رقم 2 أولاً، فلن نستطيع تنفيذ أيّ نشاط آخر. الجواب المثالي هو تنفيذ النشاط 1 ثم 3، لذا لا يمكن أن يكون هذا حلًا لهذه المشكلة.
</p>

<p>
	لنجرّب طريقةً أخرى:
</p>

<ul>
<li>
		ترتيب الأنشطة بحسب وقت الإنتهاء: هذا يعني أنّ الأنشطة التي تنتهي أولا توضع أولًا. انظر الخوارزمية:
		<ol>
<li>
				ترتيب الأنشطة بحسب أوقات نهايتها.
			</li>
			<li>
				إذا لم يتقاسم النشاط المراد تنفيذه وقتًا مشتركًا مع الأنشطة المُنفّذة سابقًا، فسننفّذه.
			</li>
		</ol>
</li>
</ul>
<p>
	لنحلّل المثال الأول:
</p>

<table>
<thead><tr>
<th>
				النشاط رقم
			</th>
			<th>
				وقت البداية
			</th>
			<th>
				وقت النهاية
			</th>
		</tr></thead>
<tbody>
<tr>
<td>
				1
			</td>
			<td>
				10.20 صباحا
			</td>
			<td>
				11.00 صباحا
			</td>
		</tr>
<tr>
<td>
				2
			</td>
			<td>
				10.30 صباحا
			</td>
			<td>
				11.30 صباحا
			</td>
		</tr>
<tr>
<td>
				3
			</td>
			<td>
				11.00 صباحا
			</td>
			<td>
				12.00 صباحا
			</td>
		</tr>
<tr>
<td>
				4
			</td>
			<td>
				10.00 صباحا
			</td>
			<td>
				11.30 صباحا
			</td>
		</tr>
<tr>
<td>
				5
			</td>
			<td>
				9.00 صباحا
			</td>
			<td>
				11.00 صباحا
			</td>
		</tr>
</tbody>
</table>
<p>
	نرتب الأنشطة بحسب أوقات نهاياتها لنحصل على الترتيب 1 -&gt; 5 -&gt; 2 -&gt; 4 -&gt; 3، والجواب الصحيح هو 1 -&gt; 3، أي أنّنا سننفّذ النشاطين 1 و3. وهو الجواب الصحيح:
</p>

<ol>
<li>
		ترتيب الأنشطة.
	</li>
	<li>
		نفّذ أول نشاط في قائمة الأنشطة المرتبة.
	</li>
	<li>
		عيّن قيمة النشاط الأول إلى النشاط الحالي Current_activity := ﬁrst activity.
	</li>
	<li>
		عين end_time := t، حيث t يمثل وقت إنهاء النشاط الحالي
	</li>
	<li>
		اذهب إلى النشاط الموالي إن كان موجودًا، خلاف ذلك أنهِ الخوارزمية.
	</li>
	<li>
		إن كان وقت البداية الخاص بالنشاط الحالي أكبر من end_time، نفّذ النشاط وعد إلى المرحلة 4.
	</li>
	<li>
		خلاف ذلك اذهب إلى المرحلة 5.
	</li>
</ol>
<h3>
	مشكلة الصرف Change-making problem
</h3>

<p>
	لنفترض أنّ لديك مبلغًا معينًا في نظام نقدي ما، هل يمكن إيجاد الحد الأدنى من القطع والأوراق النقدية المقابلة لذلك المبلغ.
</p>

<p>
	حسب الأنظمة المالية الأساسية، إذا افترضنا في بعض النظم المالية -مثل التي نستخدمها الآن- أنّ العملات النقدية الممكنة هي 1 و2 و5 و10، فالحل البديهي هو أن نبدأ بأعلى قطعة أو ورقة نقدية، ثمّ نكرّر هذا الإجراء إلى أن نستكمل المبلغ. فمثلا، إن كان المبلغ هو 28 درهمًا، فيمكننا تصريفه إلى 10 + 10 + 5 + 2 + 1 = 28، وهكذا سيكون الحدّ الأدنى هو 5، وهو الحل الصحيح.
</p>

<p>
	نستطيع فعل هذا بشكل تكراري في لغة OCaml كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9300_22" style="">
<span class="pun">(*</span><span class="pln"> </span><span class="pun">نفترض</span><span class="pln"> </span><span class="pun">أنّ</span><span class="pln"> </span><span class="pun">النظام</span><span class="pln"> </span><span class="pun">النقدي</span><span class="pln"> </span><span class="pun">مُرتب</span><span class="pln"> </span><span class="pun">ترتيبًا</span><span class="pln"> </span><span class="pun">تنازليًا</span><span class="pln"> </span><span class="pun">*)</span><span class="pln">
let change_make money_system amount </span><span class="pun">=</span><span class="pln">
  let rec loop given amount </span><span class="pun">=</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> amount </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> then given
    </span><span class="kwd">else</span><span class="pln">
       </span><span class="pun">(*</span><span class="pln"> </span><span class="pun">القيمة</span><span class="pln"> </span><span class="pun">الأولى</span><span class="pln"> </span><span class="pun">أصغر</span><span class="pln"> </span><span class="pun">أو</span><span class="pln"> </span><span class="pun">تساوي</span><span class="pln"> </span><span class="pun">باقي</span><span class="pln"> </span><span class="pun">المبلغ</span><span class="pln"> </span><span class="pun">*)</span><span class="pln">
        let coin </span><span class="pun">=</span><span class="pln"> </span><span class="typ">List</span><span class="pun">.</span><span class="pln">find </span><span class="pun">((&gt;=)</span><span class="pln"> amount</span><span class="pun">)</span><span class="pln"> money_system in
        loop </span><span class="pun">(</span><span class="pln">coin</span><span class="pun">::</span><span class="pln">given</span><span class="pun">)</span><span class="pln"> </span><span class="pun">(</span><span class="pln">amount </span><span class="pun">-</span><span class="pln"> coin</span><span class="pun">)</span><span class="pln">
   in loop </span><span class="pun">[]</span><span class="pln"> amount</span></pre>

<p>
	هذه الخوارزمية ليست صالحةً دائمًا، فلو كان المبلغ يساوي 99 وكانت القطع والأوراق النقدية الممكنة هي 10 و7 و5، فإنّ الحل السابق لن يعمل، إذ لو أخذنا أكبر القطع النقدية 10، وجمعناه إلى أن نصل إلى 90، فستبقى لنا 9، وهو مبلغ لا يمكن تكوينه من القطعتين 5 و7.
</p>

<p>
	ثم إنّه لا توجد ضمانة لوجود حلّ أصلًا، وهذه المشكلة في الواقع <a href="https://ar.wikipedia.org/wiki/%D9%85%D8%B3%D8%A7%D8%A6%D9%84_NP_%D8%B5%D8%B9%D8%A8%D8%A9" rel="external nofollow">صعبة للغاية</a>، لكن توجد بعض الحلول الصالحة التي تجمع بين الشره greediness والتذكر memoization، وتقوم على استكشاف جميع الإمكانات، واختيار تلك التي تتألف من أقل عدد من القطع النقدية.
</p>

<p>
	لنفترض أنّ لدينا مبلغًا ‎‏‏X&gt; 0، وقد اخترنا قطعة نقدية P من النظام المالي، سيكون المبلغ المتبقي إذن هو X-P. نحلّ الآن مشكلة تصريف المبلغ ‏‏X-P إلى أقل عدد ممكن من القطع النقدية، ونجرّب هذا مع جميع القطع النقدية في النظام. لاحظ أنّه في كل مرة نختار قطعة نقدية P فإنّنا نجعل المشكلة أصغر (أي X-P). ويكون الحل النهائي -إذا كان موجودًا- هو أصغر مسار من المسارات التي اتبعناها وأدّت إلى المبلغ 0.
</p>

<p>
	انظر فيما يلي دالة OCaml تكرارية لحل هذه المشكلة، تعيد هذه الدالة None في حال لم يكن هناك حل:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9300_24" style="">
<span class="pun">(*</span><span class="pln"> option utilities </span><span class="pun">*)</span><span class="pln">
let optmin x y </span><span class="pun">=</span><span class="pln">
 match x</span><span class="pun">,</span><span class="pln">y </span><span class="kwd">with</span><span class="pln">
 </span><span class="pun">|</span><span class="pln"> </span><span class="typ">None</span><span class="pun">,</span><span class="pln">a </span><span class="pun">|</span><span class="pln"> a</span><span class="pun">,</span><span class="typ">None</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> a
 </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Some</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Some</span><span class="pln"> y</span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">Some</span><span class="pln"> </span><span class="pun">(</span><span class="pln">min x y</span><span class="pun">)</span><span class="pln">
let optsucc </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln">
 </span><span class="pun">|</span><span class="pln"> </span><span class="typ">Some</span><span class="pln"> x </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">Some</span><span class="pln"> </span><span class="pun">(</span><span class="pln">x</span><span class="pun">+</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
 </span><span class="pun">|</span><span class="pln"> </span><span class="typ">None</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="typ">None</span><span class="pln">
</span><span class="pun">(*</span><span class="pln"> </span><span class="pun">مشكلة</span><span class="pln"> </span><span class="pun">الصرف*)</span><span class="pln">
let change_make money_system amount </span><span class="pun">=</span><span class="pln">
 let rec loop n </span><span class="pun">=</span><span class="pln">
   let onepiece acc piece </span><span class="pun">=</span><span class="pln">
     match n </span><span class="pun">-</span><span class="pln"> piece </span><span class="kwd">with</span><span class="pln">
     </span><span class="pun">|</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="pun">(*</span><span class="pln">problem solved </span><span class="kwd">with</span><span class="pln"> one coin</span><span class="pun">*)</span><span class="pln">
            </span><span class="typ">Some</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
     </span><span class="pun">|</span><span class="pln"> x </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> x </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> then
              </span><span class="pun">(*</span><span class="pln"> </span><span class="pun">نتجاهل</span><span class="pln"> </span><span class="pun">هذا</span><span class="pln"> </span><span class="pun">الحل</span><span class="pln"> </span><span class="pun">إن</span><span class="pln"> </span><span class="pun">لم</span><span class="pln"> </span><span class="pun">نصل</span><span class="pln"> </span><span class="pun">إلى</span><span class="pln"> </span><span class="lit">0</span><span class="pun">*)</span><span class="pln">
              </span><span class="typ">None</span><span class="pln">
            </span><span class="kwd">else</span><span class="pln">
              </span><span class="pun">(*من</span><span class="pln"> </span><span class="pun">القطع</span><span class="pln"> </span><span class="pun">النقدية</span><span class="pln"> </span><span class="pun">الباقية</span><span class="pln"> </span><span class="typ">None</span><span class="pln">  </span><span class="pun">نبحث</span><span class="pln"> </span><span class="pun">عن</span><span class="pln"> </span><span class="pun">أقصر</span><span class="pln"> </span><span class="pun">مسار</span><span class="pln"> </span><span class="pun">يخالف*)</span><span class="pln">
              optmin </span><span class="pun">(</span><span class="pln">optsucc </span><span class="pun">(</span><span class="pln">loop x</span><span class="pun">))</span><span class="pln"> acc
   in
   </span><span class="pun">(*على</span><span class="pln"> </span><span class="pun">جميع</span><span class="pln"> </span><span class="pun">القطع</span><span class="pln"> </span><span class="pun">النقدية</span><span class="pln"> onepiece </span><span class="pun">نستدعي*)</span><span class="pln">
   </span><span class="typ">List</span><span class="pun">.</span><span class="pln">fold_left onepiece </span><span class="typ">None</span><span class="pln"> money_system
 in loop amount</span></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		<strong>ملاحظة</strong>: يمكن أن تحسب هذه الخوارزمية مجموعة الصرف الخاصة بالقيمة نفسها عدة مرات، وهنا يمكن أن يكون التذكير memoization مفيدًا جدّا في تجنّب التكرار وتسريع النتائج.
	</p>
</blockquote>

<h2>
	خوارزمية كروسكال Kruskal's Algorithm
</h2>

<p>
	<a href="https://ar.wikipedia.org/wiki/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9_%D9%83%D8%B1%D9%88%D8%B3%D9%83%D8%A7%D9%84" rel="external nofollow">خوارزمية كروسكال</a> هي خوارزمية تهدف إلى إيجاد المسار الأقصر (الأقل كلفة)، وهي من <a href="https://ar.wikipedia.org/wiki/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9_%D8%AC%D8%B4%D8%B9%D8%A9" rel="external nofollow">الخوارزميات الشرهة</a> Greedy Algorithm التي تُستخدَم بكثرة في نظرية المخططات.
</p>

<h3>
	استخدام المجموعات التوزيعية
</h3>

<p>
	هناك شيئان يمكننا القيام بهما لتحسين مجموعة الخوارزميات الفرعية <a href="https://ar.wikipedia.org/wiki/%D9%87%D9%8A%D9%83%D9%84%D8%A9_%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA_%D8%A7%D9%84%D9%85%D8%AC%D9%85%D9%88%D8%B9%D8%A7%D8%AA_%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B5%D9%84%D8%A9" rel="external nofollow">للمجموعات التوزيعية</a> المُحسّنة sub-optimal disjoint-set subalgorithms، وهما:
</p>

<ul>
<li>
		مقاييس بحثية لضغط المسار Path compression heuristic: لن تحتاج الدالة <code>‎findSet‎</code> (انظر الشيفرة أدناه) إلى التكرار على شجرة ارتفاعها أطول من <code>‎2‎</code>، وإلا فيمكنها ربط العقد السفلية مباشرة بالجذر، مما يحسّن عمليات العبور traversals المستقبلية:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9300_26" style="">
<span class="pln">subalgo findSet</span><span class="pun">(</span><span class="pln">v</span><span class="pun">:</span><span class="pln"> a node</span><span class="pun">):</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> v</span><span class="pun">.</span><span class="pln">parent </span><span class="pun">!=</span><span class="pln"> v
       v</span><span class="pun">.</span><span class="pln">parent </span><span class="pun">=</span><span class="pln"> findSet</span><span class="pun">(</span><span class="pln">v</span><span class="pun">.</span><span class="pln">parent</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> v</span><span class="pun">.</span><span class="pln">parent</span></pre>

<ul>
<li>
		المقاييس البحثية القائمة على الارتفاع Height-based merging heuristic: خزّن ارتفاع الشجيرة subtree الخاصة بكل عقدة، واجعل الشجرة الأطول أبًا parent للشجرة الأصغر عند الدمج، وذلك دون زيادة ارتفاع أيّ شجرة:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9300_28" style="">
<span class="pln">subalgo unionSet</span><span class="pun">(</span><span class="pln">u</span><span class="pun">,</span><span class="pln"> v</span><span class="pun">:</span><span class="pln"> nodes</span><span class="pun">):</span><span class="pln">
   vRoot </span><span class="pun">=</span><span class="pln"> findSet</span><span class="pun">(</span><span class="pln">v</span><span class="pun">)</span><span class="pln">
   uRoot </span><span class="pun">=</span><span class="pln"> findSet</span><span class="pun">(</span><span class="pln">u</span><span class="pun">)</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> vRoot </span><span class="pun">==</span><span class="pln"> uRoot</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> vRoot</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&lt;</span><span class="pln"> uRoot</span><span class="pun">.</span><span class="pln">height</span><span class="pun">:</span><span class="pln">
       vRoot</span><span class="pun">.</span><span class="pln">parent </span><span class="pun">=</span><span class="pln"> uRoot
   </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pln"> vRoot</span><span class="pun">.</span><span class="pln">height </span><span class="pun">&gt;</span><span class="pln"> uRoot</span><span class="pun">.</span><span class="pln">height</span><span class="pun">:</span><span class="pln">
       uRoot</span><span class="pun">.</span><span class="pln">parent </span><span class="pun">=</span><span class="pln"> vRoot
   </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
       uRoot</span><span class="pun">.</span><span class="pln">parent </span><span class="pun">=</span><span class="pln"> vRoot
       uRoot</span><span class="pun">.</span><span class="pln">height </span><span class="pun">=</span><span class="pln">  uRoot</span><span class="pun">.</span><span class="pln">height </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span></pre>

<p>
	يستغرق هذا مدة <code>‎O(alpha(n))‎</code> لكلّ عملية، حيث تمثّل <code>‎alpha‎</code> مقلوب inverse <a href="https://ar.wikipedia.org/wiki/%D8%AF%D8%A7%D9%84%D8%A9_%D8%A3%D9%83%D8%B1%D9%85%D8%A7%D9%86" rel="external nofollow">دالة أكرمان Ackermann</a> المعروفة بسرعة نموها، وهذا يعني أنّ <code>‎alpha‎</code> ستكون بطيئة جدًا، ويمكن عدّ تعقيدها عمليًا ثابتًا (<code>‎O(1)‎</code>)، ما يعني أنّ تعقيد خوارزمية Kruskal سيساوي <code>‎O(m log m + m) = O(m log m)‎</code> أخذًا بالحسبان الترتيبَ الأولي.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		<strong>ملاحظة</strong>: قد يقلّل ضغط المسار Path compression ارتفاع الشجرة، وعليه فإنّ موازنة ارتفاعات الأشجار في خضمّ عملية الاتحاد union operation ليس مهمةً سهلة.
	</p>
</blockquote>

<p>
	ولتجنّب تعقيد تخزين وحساب ارتفاعات الأشجار، يمكن اختيار الشجرة الأب parent عشوائيًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9300_30" style="">
<span class="pln">    subalgo unionSet</span><span class="pun">(</span><span class="pln">u</span><span class="pun">,</span><span class="pln"> v</span><span class="pun">:</span><span class="pln"> nodes</span><span class="pun">):</span><span class="pln">
             vRoot </span><span class="pun">=</span><span class="pln"> findSet</span><span class="pun">(</span><span class="pln">v</span><span class="pun">)</span><span class="pln">
             uRoot </span><span class="pun">=</span><span class="pln"> findSet</span><span class="pun">(</span><span class="pln">u</span><span class="pun">)</span><span class="pln">
 </span><span class="kwd">if</span><span class="pln"> vRoot </span><span class="pun">==</span><span class="pln"> uRoot</span><span class="pun">:</span><span class="pln">
             </span><span class="kwd">return</span><span class="pln">
 </span><span class="kwd">if</span><span class="pln"> random</span><span class="pun">()</span><span class="pln"> </span><span class="pun">%</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">:</span><span class="pln">
            vRoot</span><span class="pun">.</span><span class="pln">parent </span><span class="pun">=</span><span class="pln"> uRoot
 </span><span class="kwd">else</span><span class="pun">:</span><span class="pln">
            uRoot</span><span class="pun">.</span><span class="pln">parent </span><span class="pun">=</span><span class="pln"> vRoot</span></pre>

<p>
	عمليًا، ينتج عن هذه الخوارزمية العشوائية مرفوقة بعملية ضغط المسار في الدالة <code>‎findSet‎</code>، تحسّن كبير في الأداء رغم أنّها أكثر بساطة.
</p>

<h4>
	تطبيق مفصل implementation
</h4>

<p>
	من أجل رصد الدورات cycle detection بفعالية، سنعُدّ كل عقدة جزءًا من شجرة، ونتحقّق عند إضافة ضلع ممّا إذا كانت عقدَتاه جزءًا من شجرتين منفصلتين. في البداية، تشكّل كلّ عقدة شجرةً مؤلفةً من عقدة واحدة وحسب:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9300_34" style="">
<span class="pln">algorithm kruskalMST</span><span class="pun">(</span><span class="pln">G</span><span class="pun">:</span><span class="pln"> a graph</span><span class="pun">)</span><span class="pln">
   sort </span><span class="typ">Gs</span><span class="pln"> edges by their value </span><span class="com">// بحسب القيم G ترتيب</span><span class="pln">
   MST </span><span class="pun">=</span><span class="pln"> a forest of trees</span><span class="pun">,</span><span class="pln"> initially each tree is a node in the graph
             </span><span class="com">// غابة من الأشجار، حيث تمثل كل شجرة عقدة من الشعبة</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> each edge e in G</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> the root of the tree that e</span><span class="pun">.</span><span class="pln">first belongs to is not the same
       as the root of the tree that e</span><span class="pun">.</span><span class="pln">second belongs to</span><span class="pun">:</span><span class="pln">
           connect one of the roots to the other</span><span class="pun">,</span><span class="pln"> thus merging two trees</span></pre>

<p>
	إذا كان جذر الشجرة التي ينتمي إليها e.first يساوي جذر الشجرة التي ينتمي إليها e.second، فاربط أحد الجذرين بالآخر، وهكذا تُدمَج الشجرتان.
</p>

<pre class="ipsCode">
    return MST, which now a single-tree forest // أصبحت الآن غابة من شجرة واحدة MST 
</pre>

<p>
	يقوم منظور الغابات forest -مجموعة من الأشجار غير المتصلة بالضرورة- المذكور أعلاه على استخدام المجموعات التوزيعية disjoint-set data structure، وينطوي على ثلاث عمليات رئيسية:
</p>

<pre class="ipsCode" id="ips_uid_9300_36">
subalgo makeSet(v: a node):
   v.parent = v    &lt;- make a new tree rooted at v

subalgo findSet(v: a node):
   if v.parent == v:
       return v
   return findSet(v.parent)
subalgo unionSet(v, u: nodes):
   vRoot = findSet(v)
   uRoot = findSet(u)
   uRoot.parent = vRoot
algorithm kruskalMST(G: a graph):
   sort Gs edges by their value
   for each node n in G:
       makeSet(n)
   for each edge e in G:
       if findSet(e.first) != findSet(e.second):
           unionSet(e.first, e.second)
</pre>

<p>
	يستغرق هذا التطبيق حوالي <code>‎O(n log n)‎</code> لإدارة المجموعات التوزيعية، وهكذا يصبح التعقيد الزمني الإجمالي لخوارزمية كروسكال <code>‎O(m*n‎ log n ‎)‎</code>.
</p>

<p>
	في الأخير، نستعرض تطبيقًا آخر عالي المستوى للخوارزمية، حيث نرتّب الأضلاع بحسب القيم، ثمّ نضيف كلّ واحد منها إلى <a href="https://en.wikipedia.org/wiki/Minimum_spanning_tree" rel="external nofollow">شجرة الامتداد الأدنى MST</a> بالترتيب ما لم ينجم عن ذلك دورة.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9300_40" style="">
<span class="pln">algorithm kruskalMST</span><span class="pun">(</span><span class="pln">G</span><span class="pun">:</span><span class="pln"> a graph</span><span class="pun">)</span><span class="pln">
   sort </span><span class="typ">Gs</span><span class="pln"> edges by their value
   MST </span><span class="pun">=</span><span class="pln"> an empty graph
   </span><span class="kwd">for</span><span class="pln"> each edge e in G</span><span class="pun">:</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> adding e to MST does not create a cycle</span><span class="pun">:</span><span class="pln">
           add e to MST
</span><span class="kwd">return</span><span class="pln"> MST</span></pre>

<p>
	ترجمة -بتصرّف- للفصلين 16 و17 من كتاب <a href="https://goalkicker.com/AlgorithmsBook/" rel="external nofollow">Algorithms Notes for Professionals</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/advance/%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AF%D9%8A%D9%86%D8%A7%D9%85%D9%8A%D9%83%D9%8A%D8%A9-r1365/" rel="">البرمجة الديناميكية</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advance/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1282/" rel="">مدخل إلى الخوارزميات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advance/%D8%AF%D9%84%D9%8A%D9%84-%D8%B4%D8%A7%D9%85%D9%84-%D8%B9%D9%86-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%AA%D8%B9%D9%82%D9%8A%D8%AF-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-r1247/" rel="">دليل شامل عن تحليل تعقيد الخوارزمية</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1366</guid><pubDate>Wed, 27 Oct 2021 15:00:00 +0000</pubDate></item><item><title>&#x62A;&#x62D;&#x644;&#x64A;&#x644; &#x632;&#x645;&#x646; &#x62A;&#x634;&#x63A;&#x64A;&#x644; &#x627;&#x644;&#x642;&#x648;&#x627;&#x626;&#x645; &#x627;&#x644;&#x645;&#x646;&#x641;&#x630;&#x629; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x642;&#x627;&#x626;&#x645;&#x629; &#x627;&#x632;&#x62F;&#x648;&#x627;&#x62C;&#x64A;&#x629; &#x627;&#x644;&#x62A;&#x631;&#x627;&#x628;&#x637;</title><link>https://academy.hsoub.com/programming/advanced/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D8%A7%D8%B2%D8%AF%D9%88%D8%A7%D8%AC%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D8%B1%D8%A7%D8%A8%D8%B7-r1350/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/61731140be08e_--------.png.243e1dde39b945a04ead68322eaa5253.png" /></p>
<p>
	سنراجع في هذه المقالة نتائج تمرين <a href="https://academy.hsoub.com/programming/advance/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D9%85%D8%AA%D8%B1%D8%A7%D8%A8%D8%B7%D8%A9-r1349/" rel="">مقالة تحليل زمن تشغيل القوائم المُنفَّذة باستخدام قائمة مترابطة</a>، ثم سنُقدِّم تنفيذًا آخرَ للواجهة <code>List</code>، وهو القائمة ازدواجية الترابط doubly-linked list.
</p>

<h2 id="نتائج-تشخيص-الأداء">
	نتائج تشخيص الأداء
</h2>

<p>
	اِستخدَمنا الصنف <code>Profiler.java</code> -في التمرين المشار إليه- لكي نُطبِّق عمليات الصنفين <code>ArrayList</code> و<code>LinkedList</code> على أحجام مختلفة من المشكلة، ثم عرضنا زمن التشغيل مقابل حجم المشكلة بمقياس لوغاريتمي-لوغاريتمي log-log، وقدّرنا ميل المنحني الناتج. يُوضِّح ذلك الميل العلاقة بين زمن التشغيل وحجم المشكلة.
</p>

<p>
	فعلى سبيل المثال، عندما استخدمنا التابع <code>add</code> لإضافة عناصر إلى نهاية قائمة من النوع <code>ArrayList</code>، وجدنا أن الزمن الكلّي لتنفيذ عدد n من الإضافات يتناسب مع n، أي أن الميل المُقدَّر كان قريبًا من 1، وبناءً على ذلك استنتجنا أن تنفيذ عدد n من الإضافات ينتمي إلى المجموعة O(n)‎، وأن تنفيذَ إضافةٍ واحدةٍ يتطلَّب زمنًا ثابتًا في المتوسط، أي أنه ينتمي إلى المجموعة O(1)‎، وهو نفس ما توصلنا إليه باستخدام تحليل <a href="https://academy.hsoub.com/programming/advanced/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1282/" rel="">الخوارزميات</a>.
</p>

<p>
	كان المطلوب من ذلك التمرين هو إكمال متن التابع <code>profileArrayListAddBeginning</code> الذي يُشخِّص عملية إضافة عناصر جديدة إلى بداية قائمة من النوع <code>ArrayList</code>. وبناءً على <a href="http://xn--%20%20%20-gzemaauezghe2bp1zcdachs9do3ak" rel="external nofollow">تحليلنا للخوارزمية</a>
</p>

<p>
	Y، فقد توقّعنا أن يتطلَّب تنفيذ إضافة واحدة زمنًا خطيًا بسبب تحريك العناصر الأخرى إلى اليمين، وعليه توقَّعنا أن يتطلَّب تنفيذ عدد n من الإضافات زمنًا تربيعيًا.
</p>

<p>
	انظر إلى حل التمرين الذي ستجده في مجلد الحل داخل <a href="https://github.com/AllenDowney/ThinkDataStructures" rel="external nofollow">مستودع الكتاب</a>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9300_7" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> profileArrayListAddBeginning</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Timeable</span><span class="pln"> timeable </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Timeable</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">List</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">&gt;</span><span class="pln"> </span><span class="typ">list</span><span class="pun">;</span><span class="pln">

            </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> setup</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">list</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">ArrayList</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">&gt;();</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

            </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> timeMe</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">n</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="typ">list</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="str">"a string"</span><span class="pun">);</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">};</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> startN </span><span class="pun">=</span><span class="pln"> </span><span class="lit">4000</span><span class="pun">;</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> endMillis </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10000</span><span class="pun">;</span><span class="pln">
        runProfiler</span><span class="pun">(</span><span class="str">"ArrayList add beginning"</span><span class="pun">,</span><span class="pln"> timeable</span><span class="pun">,</span><span class="pln"> startN</span><span class="pun">,</span><span class="pln"> endMillis</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	يتطابق هذا التابع تقريبًا مع التابع <code>profileArrayListAddEnd</code>، فالفارق الوحيد موجود في التابع <code>timeMe</code>، حيث يَستخدِم نسخةً ثنائيةَ المعامل من التابع <code>add</code> لكي يضع العناصر الجديدة في الفهرس 0، كما أنه يزيد من قيمة <code>endMillis</code> لكي يحصل على نقطة بياناتٍ إضافيّة.
</p>

<p>
	انظر إلى النتائج (حجم المشكلة على اليسار وزمن التشغيل بوحدة الميلي ثانية على اليمين):
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9300_9" style=""><span class="lit">4000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">14</span><span class="pln">
</span><span class="lit">8000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">35</span><span class="pln">
</span><span class="lit">16000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">150</span><span class="pln">
</span><span class="lit">32000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">604</span><span class="pln">
</span><span class="lit">64000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2518</span><span class="pln">
</span><span class="lit">128000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">11555</span></pre>

<p>
	تَعرِض الصورة التالية رسمًا بيانيًا لزمن التشغيل مقابل حجم المشكلة.
</p>

<p style="text-align: center;">
	<img alt="001ArrayList_Profiling.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="80451" data-unique="l6y21ssh4" style="" src="https://academy.hsoub.com/uploads/monthly_2021_10/001ArrayList_Profiling.PNG.50f7b85911e7b3ef7bd0842a4df206f6.PNG">
</p>

<p>
	لا يَعنِي ظهور خط مستقيم في هذا الرسم البياني أن الخوارزمية خطّيّة، وإنما يعني أنه إذا كان زمن التشغيل متناسبًا مع n<sup>k</sup>‎ لأي أس k، فإنه من المتوقَّع أن نرى خطًّا مستقيمًا ميله يساوي k. نتوقَّع في هذا المثال أن يكون الزمنُ الكلّيّ لعدد n من الإضافات متناسبًا مع n<sup>2</sup>‎، وأن نحصل على خطٍّ مستقيمٍ بميلٍ يساوي 2، وفي الحقيقة يساوي الميل المُقدَّر 1.992 تقريبًا، وهو في الحقيقة دقيق جدًا لدرجةٍ تجعلنا لا نرغب في تزوير بيانات بهذه الجودة.
</p>

<h2 id="تشخيص-توابع-الصنف-linkedlist">
	تشخيص توابع الصنف LinkedList
</h2>

<p>
	طلبَ التمرين المشار إليه منك أيضًا تشخيص أداء عملية إضافة عناصرَ جديدةٍ إلى بداية قائمةٍ من النوع <code>LinkedList</code>. وبناءً على تحليلنا للخوارزمية، توقّعنا أن يتطلَّب تنفيذ إضافةٍ واحدةٍ زمنًا ثابتًا؛ لأننا لا نضطّر إلى تحريك العناصر الموجودة في هذا النوع من القوائم، وإنما نضيف فقط عقدةً جديدةً إلى بداية القائمة، وعليه توقَّعنا أن يتطلَّب تنفيذ عدد n من الإضافات زمنًا خطّيًّا.
</p>

<p>
	انظر شيفرة الحل:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9300_11" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> profileLinkedListAddBeginning</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Timeable</span><span class="pln"> timeable </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Timeable</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">List</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">&gt;</span><span class="pln"> </span><span class="typ">list</span><span class="pun">;</span><span class="pln">

            </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> setup</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">list</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">LinkedList</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">&gt;();</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

            </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> timeMe</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">n</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="typ">list</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="str">"a string"</span><span class="pun">);</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">};</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> startN </span><span class="pun">=</span><span class="pln"> </span><span class="lit">128000</span><span class="pun">;</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> endMillis </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2000</span><span class="pun">;</span><span class="pln">
        runProfiler</span><span class="pun">(</span><span class="str">"LinkedList add beginning"</span><span class="pun">,</span><span class="pln"> timeable</span><span class="pun">,</span><span class="pln"> startN</span><span class="pun">,</span><span class="pln"> endMillis</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	اضطرّرنا إلى إجراء القليل من التعديلات، فعدّلنا الصنف <code>ArrayList</code> إلى الصنف <code>LinkedList</code>، كما ضبطنا قيمة المعاملين <code>startN</code> و<code>endMillis</code> لكي نحصل على قياسات مناسبة، فقد لاحظنا أن القياسات ليست بدقة القياسات السابقة. انظر إلى النتائج:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9300_13" style=""><span class="lit">128000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">16</span><span class="pln">
</span><span class="lit">256000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">19</span><span class="pln">
</span><span class="lit">512000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">28</span><span class="pln">
</span><span class="lit">1024000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">77</span><span class="pln">
</span><span class="lit">2048000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">330</span><span class="pln">
</span><span class="lit">4096000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">892</span><span class="pln">
</span><span class="lit">8192000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1047</span><span class="pln">
</span><span class="lit">16384000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4755</span></pre>

<p style="text-align: center;">
	<img alt="002LinkedList_Start_Profiling.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="80452" data-unique="sa9grxvqg" style="" src="https://academy.hsoub.com/uploads/monthly_2021_10/002LinkedList_Start_Profiling.PNG.060ffc2fed705dcc86a92f00ddc81c6f.PNG">
</p>

<p>
	لم نحصل على خط مستقيم تمامًا، وميل الخيط لا يساوي 1 بالضبط، وقد قدَّرت المربعات الدنيا least squares fit الميل بحوالي 1.23، ومع ذلك تشير تلك النتائج إلى أن الزمن الكلي لعدد n من الإضافات ينتمي إلى المجموعة O(n)‎ على الأقل، وبالتالي يتطلَّب تنفيذُ إضافةٍ واحدةٍ زمنًا ثابتًا.
</p>

<h2 id="الإضافة-إلى-نهاية-قائمة-من-الصنف-linkedlist">
	الإضافة إلى نهاية قائمة من الصنف LinkedList
</h2>

<p>
	تُعدّ إضافة العناصر إلى بداية القائمة واحدةً من العمليات التي نتوقَّع أن يكون الصنف <code>LinkedList</code> أثناء تنفيذها أسرع من الصنف <code>ArrayList</code>؛ وفي المقابل، بالنسبة لإضافة العناصر إلى نهاية القائمة، فإننا نتوقَّع أن يكون الصنف <code>LinkedList</code> أبطأ، حيث يضطّر تابع الإضافة إلى المرور عبر قائمة العناصر بالكامل لكي يتمكَّن من إضافة عنصر جديد إلى النهاية، مما يَعنِي أن العملية خطية، وعليه نتوقَّع أن يكون الزمن الكلي لعدد n من الإضافات تربيعيًا.
</p>

<p>
	في الواقع هذا ليس صحيحًا، ويمكنك الاطلاع إلى الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9300_15" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> profileLinkedListAddEnd</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Timeable</span><span class="pln"> timeable </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Timeable</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">List</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">&gt;</span><span class="pln"> </span><span class="typ">list</span><span class="pun">;</span><span class="pln">

            </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> setup</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">list</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">LinkedList</span><span class="pun">&lt;</span><span class="typ">String</span><span class="pun">&gt;();</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">

            </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> timeMe</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">&lt;</span><span class="pln">n</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                    </span><span class="typ">list</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="str">"a string"</span><span class="pun">);</span><span class="pln">
                </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">};</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> startN </span><span class="pun">=</span><span class="pln"> </span><span class="lit">64000</span><span class="pun">;</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> endMillis </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">;</span><span class="pln">
        runProfiler</span><span class="pun">(</span><span class="str">"LinkedList add end"</span><span class="pun">,</span><span class="pln"> timeable</span><span class="pun">,</span><span class="pln"> startN</span><span class="pun">,</span><span class="pln"> endMillis</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	ها هي النتائج التي حصلنا عليها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9300_17" style=""><span class="lit">64000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pln">
</span><span class="lit">128000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pln">
</span><span class="lit">256000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">21</span><span class="pln">
</span><span class="lit">512000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">24</span><span class="pln">
</span><span class="lit">1024000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">78</span><span class="pln">
</span><span class="lit">2048000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">235</span><span class="pln">
</span><span class="lit">4096000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">851</span><span class="pln">
</span><span class="lit">8192000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">950</span><span class="pln">
</span><span class="lit">16384000</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6160</span></pre>

<p style="text-align: center;">
	<img alt="003LinkedList_End_Profiling.PNG" class="ipsImage ipsImage_thumbnailed" data-fileid="80453" data-unique="q5xsfkdqv" style="" src="https://academy.hsoub.com/uploads/monthly_2021_10/003LinkedList_End_Profiling.PNG.d7ac59a48524ab0813b661a85a7a708d.PNG">
</p>

<p>
	كما ترى هنا فالقياسات غير دقيقة أيضًا، كما أن الخط ليس مستقيمًا تمامًا، والميل المُقدّر يُساوِي 1.19، وهو قريبٌ لما حصلنا عليه عند إضافة العناصر إلى بداية القائمة، وليس قريبًا من 2 الذي توقّعنا أن نحصل عليه بناءً على تحليلنا للخوارزمية. في الواقع، هو أقرب إلى 1، مما قد يشير إلى أن إضافة العناصر إلى نهاية القائمةِ يستغرق زمنًا ثابتًا.
</p>

<h2 id="القوائم-ازدواجية-الترابط-doubly-linked-list">
	القوائم ازدواجية الترابط Doubly-linked list
</h2>

<p>
	الفكرة هي أن الصنف <code>MyLinkedList</code> الذي نفَّذناه يَستخدِم قائمة مترابطة أحادية، أي أن كل عنصرٍ يحتوي على رابطٍ واحدٍ إلى العنصر التالي، في حين يحتوي الكائن <code>MyArrayList</code> نفسه على رابط إلى العقدة الأولى.
</p>

<p>
	في المقابل، إذا اطلعت على <a href="https://docs.oracle.com/javase/8/docs/api/java/util/LinkedList.html" rel="external nofollow">توثيق الصنف LinkedList باللغة الإنجليزية</a> الذي تُوفِّره جافا، فإننا نجد ما يلي:
</p>

<p>
	تنفيذ قائمة ازدواجية الترابط للواجهتين <code>List</code> و<code>Deque</code>. تَعمَل جميع العمليات بالشكل المُتوقَّع من قائمةٍ ازدواجية الترابط، أي تؤدي عمليات استرجاع فهرس معين إلى اجتياز عناصر القائمة من البداية أو من النهاية بناءً على أيهما أقرب لذلك الفهرس.
</p>

<p>
	فيما يلي نذكر الفكرة العامّة عن القوائم ازدواجية الترابط، إذ فيها:
</p>

<ul>
	<li>
		تحتوي كل عقدةٍ على رابطٍ إلى العقدة التالية ورابطٍ إلى العقدة السابقة.
	</li>
	<li>
		تحتوي كائنات الصنف <code>LinkedList</code> على روابط إلى العنصر الأول والعنصر الأخير في القائمة.
	</li>
</ul>

<p>
	بناءً على ما سبق، يُمكِننا أن نبدأ من أي طرف، وأن نجتاز القائمة بأي اتجاه، وعليه تتطلَّب إضافة العناصر وحذفها من بداية القائمة أو نهايتها زمنًا ثابتًا.
</p>

<p>
	يُلخِّص الجدول التالي الأداء المُتوقَّع من الصنف <code>ArrayList</code> والصنف المُخصَّص <code>MyLinkedList</code> الذي تحتوي عقده على رابط واحد والصنف <code>LinkedList</code> الذي تحتوي عقده على رابطين:
</p>

<table>
	<thead>
		<tr>
			<th>
				 
			</th>
			<th>
				MyArrayList
			</th>
			<th>
				MyLinkedList
			</th>
			<th>
				LinkedList
			</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>
				add (بالنهاية)
			</td>
			<td>
				1
			</td>
			<td>
				n
			</td>
			<td>
				1
			</td>
		</tr>
		<tr>
			<td>
				add (بالبداية)
			</td>
			<td>
				n
			</td>
			<td>
				1
			</td>
			<td>
				1
			</td>
		</tr>
		<tr>
			<td>
				add (في العموم)
			</td>
			<td>
				n
			</td>
			<td>
				n
			</td>
			<td>
				n
			</td>
		</tr>
		<tr>
			<td>
				get / set
			</td>
			<td>
				1
			</td>
			<td>
				n
			</td>
			<td>
				n
			</td>
		</tr>
		<tr>
			<td>
				indexOf / lastIndexOf
			</td>
			<td>
				n
			</td>
			<td>
				n
			</td>
			<td>
				n
			</td>
		</tr>
		<tr>
			<td>
				isEmpty / size
			</td>
			<td>
				1
			</td>
			<td>
				1
			</td>
			<td>
				1
			</td>
		</tr>
		<tr>
			<td>
				remove (من النهاية)
			</td>
			<td>
				1
			</td>
			<td>
				n
			</td>
			<td>
				1
			</td>
		</tr>
		<tr>
			<td>
				remove (من البداية)
			</td>
			<td>
				n
			</td>
			<td>
				1
			</td>
			<td>
				1
			</td>
		</tr>
		<tr>
			<td>
				remove (في العموم)
			</td>
			<td>
				n
			</td>
			<td>
				n
			</td>
			<td>
				n
			</td>
		</tr>
	</tbody>
</table>
<style type="text/css">
table {
    width: 100%;
}

thead {
    vertical-align: middle;

    text-align: center;} 

td, th {
    border: 1px solid #dddddd;
    text-align: right;
    padding: 8px;
    text-align: inherit;

}
tr:nth-child(even) {
    background-color: #dddddd;
}</style>
<h2 id="اختيار-هيكل-البيانات-الأنسب">
	اختيار هيكل البيانات الأنسب
</h2>

<p>
	يُعدّ التنفيذ مزدوج الروابط أفضل من التنفيذ <code>ArrayList</code> فيما يتعلَّق بعمليتي الإضافة والحذف من بداية القائمة، ويتمتعان بنفس الكفاءة فيما يتعلَّق بعمليتي الإضافة والحذف من نهاية القائمة، وبالتالي تقتصر أفضلية الصنف <code>ArrayList</code> عليه بعمليتي <code>get</code> و<code>set</code>، لأنهما تتطلبان زمنًا خطيًا في القوائم المترابطة حتى لو كانت مزدوجة.
</p>

<p>
	إذا كان زمن تشغيل التطبيق الخاص بك يعتمد على الزمن الذي تتطلَّبه عمليتا <code>get</code> و<code>set</code>، فقد يكون التنفيذ <code>ArrayList</code> هو الخيار الأفضل؛ أما إذا كان يَعتمِد على عملية إضافة العناصر وحذفها إلى بداية القائمة ونهايتها، فلربما التنفيذ <code>LinkedList</code> هو الخيار الأفضل.
</p>

<p>
	ولكن تذكّر أن هذه التوصياتِ مبنيّةٌ على ترتيب النمو order of growth للأحجام الكبيرة من المشكلات. هنالك عوامل أخرى ينبغي أن تأخذها في الحسبان أيضًا:
</p>

<ul>
	<li>
		لو لم تكن تلك العمليات تستغرِق جزءًا كبيرًا من زمن تشغيل التطبيق الخاص بك -أي لو كان التطبيق يقضِي غالبية زمن تشغيله في تنفيذ أشياء أخرى-، فإن اختيارك لتنفيذ الواجهة <code>List</code> غير مهم لتلك الدرجة.
	</li>
	<li>
		إذا لم تكن القوائم التي تُعالجها كبيرةً بدرجة كافية، فلربما لن تحصل على الأداء الذي تتوقَّعه، فبالنسبة للمشكلات الصغيرة، قد تكون الخوارزمية التربيعية أسرع من الخوارزمية الخطية، وقد تكون الخوارزمية الخطية أسرع من الخوارزمية ذات الزمن الثابت، كما أن الاختلاف بينها في العموم لا يُهمّ كثيرًا.
	</li>
	<li>
		لا تنسى عامل المساحة. ركزَّنا حتى الآن على زمن التشغيل، ولكن عامل المساحة مهم أيضًا، إذ تتطلَّب التنفيذات المختلفة مساحاتٍ مختلفةً من الذاكرة، وتُخزَّن العناصر في قائمةٍ من الصنف <code>ArrayList</code> إلى جانب بعضها البعض ضمن قطعة واحدة من الذاكرة، وبالتالي لا تُبدَّد مساحة الذاكرة، كما أن الحاسوب عادةً ما يكون أسرع عندما يتعامل مع أجزاء متصلة من الذاكرة. في المقابل، يتطلَّب كل عنصر في القوائم المترابطة عقدةً مكوَّنةً من رابطٍ أو رابطين.
	</li>
</ul>

<p>
	تحتل تلك الروابط حيزًا من الذاكرة - أحيانًا ما يكون أكبرَ من الحيزِ الذي تحتله البيانات نفسها-، كما تكون تلك العقدُ مبعثرةً ضمن أجزاءٍ مختلفةٍ من الذاكرة، مما يَجعَل الحاسوب أقلّ كفاءةً في تعامله معها.
</p>

<p>
	خلاصة القول هي أن تحليل الخوارزميات يُوفِّر بعض الإرشادات التي قد تساعدك على اختيار هياكل البيانات الأنسب، ولكن بشروط:
</p>

<ol start="">
	<li>
		زمن تشغيل التطبيق مهم.
	</li>
	<li>
		زمن تشغيل التطبيق يعتمد على اختيارك لهيكل البيانات.
	</li>
	<li>
		حجم المشكلة كبيرٌ بالقدر الكافي بحيث يتمكن ترتيب النمو من توقع هيكل البيانات الأنسب.
	</li>
</ol>

<p>
	في الحقيقة، يُمكِنك أن تتمتع بحياةٍ مهنيّةٍ طويلةٍ أثناء عملك كمهندس برمجيات دون أن تتعرَّض لهذا الموقف على الإطلاق.
</p>

<p>
	ترجمة -بتصرّف- للفصل <a href="https://greenteapress.com/thinkdast/html/thinkdast006.html" rel="external nofollow">Chapter 5: Doubly-linked list</a> من كتاب <a href="https://greenteapress.com/thinkdast/html/index.html" rel="external nofollow">Think Data Structures: Algorithms and Information Retrieval in Java</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D9%86%D9%81%D9%8A%D8%B0-%D8%A3%D8%B3%D9%84%D9%88%D8%A8-%D8%A7%D9%84%D8%A8%D8%AD%D8%AB-%D8%A8%D8%A7%D9%84%D8%B9%D9%85%D9%82-%D8%A3%D9%88%D9%84%D8%A7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%B7%D8%B1%D9%8A%D9%82%D8%AA%D9%8A-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%88%D8%AF-%D9%88%D8%A7%D9%84%D8%AA%D9%83%D8%B1%D8%A7%D8%B1-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1377/" rel="">تنفيذ أسلوب البحث بالعمق أولا باستخدام طريقتي التعاود والتكرار في جافا</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%82%D8%A7%D8%A6%D9%85%D8%A9-%D9%85%D8%AA%D8%B1%D8%A7%D8%A8%D8%B7%D8%A9-r1349/" rel="">تحليل زمن تشغيل القوائم المنفذة باستخدام قائمة مترابطة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advance/%D8%AA%D8%B9%D9%82%D9%8A%D8%AF-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-algorithms-complexity-r1284/" rel="">تعقيد الخوارزميات </a><a href="https://academy.hsoub.com/programming/advance/%D8%AA%D8%B9%D9%82%D9%8A%D8%AF-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-algorithms-complexity-r1284/" rel="">Algorithms Complexity</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%A3%D8%B4%D8%AC%D8%A7%D8%B1-trees-%D9%81%D9%8A-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1292/" rel="">الأشجار Trees في الخوارزميات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D8%B1%D9%85%D9%8A%D8%B2-big-o-%D9%81%D9%8A-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1290/" rel="">ترميز Big-O في الخوارزميات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%B1%D8%B3%D9%88%D9%85-%D8%A7%D9%84%D8%AA%D8%AE%D8%B7%D9%8A%D8%B7%D9%8A%D8%A9-graphs-%D9%81%D9%8A-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1293/" rel="">الرسوم التخطيطية Graphs في الخوارزميات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1350</guid><pubDate>Mon, 25 Oct 2021 15:00:00 +0000</pubDate></item><item><title>&#x645;&#x641;&#x647;&#x648;&#x645; &#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629; &#x627;&#x644;&#x62F;&#x64A;&#x646;&#x627;&#x645;&#x64A;&#x643;&#x64A;&#x629;</title><link>https://academy.hsoub.com/programming/advanced/%D9%85%D9%81%D9%87%D9%88%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%A7%D9%84%D8%AF%D9%8A%D9%86%D8%A7%D9%85%D9%8A%D9%83%D9%8A%D8%A9-r1365/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/617cedf2b7198_DynamicProgramming-01.jpg.d08c52d42518f3d775efea145f5e22e8.jpg" /></p>
<p>
	البرمجة الديناميكية هي مفهوم يُستخدم على نطاق واسع، وغالبًا ما تستخدم لأجل التحسين optimization، ومبدأ عملها هو تبسيط المشكلة المعقدة عبر تقسيمها إلى مشاكل تكرارية recursive فرعية وأبسط من المشكلة الأصلية.
</p>

<p>
	هناك صفتان رئيسيتان لا بد من وجودهما في المشكلة حتى يمكن تطبيق البرمجة الديناميكية عليها، وهما: البنية المثلى Optimal substructure، والتداخل بين المشاكل الفرعية Overlapping sub-problems. تستخدم البرمجة الديناميكية مفهومًا يسمى التذكير memoization من أجل العثور على الحل المثالي.
</p>

<h2>
	مسافة التحرير
</h2>

<p>
	إذا أُعطِيت سلسلتين نصيتين str1 وstr2، فما هو العدد الأدنى للعمليات التي يمكن إجراؤها على str1 لتحويلها إلى str2؟ في تلك الحالة يكون إجراء هاتين الوظيفتين معًا؛ أما خلاف ذلك فسنتحقّق مما إذا كان؟ انظر تنفيذ الحل أدناه في لغة جافا لهذه المشكلة:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5272_19" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">EditDistance</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
   </span><span class="com">// TODO Auto-generated method stub</span><span class="pln">
   </span><span class="typ">String</span><span class="pln"> str1 </span><span class="pun">=</span><span class="pln"> </span><span class="str">"march"</span><span class="pun">;</span><span class="pln">
   </span><span class="typ">String</span><span class="pln"> str2 </span><span class="pun">=</span><span class="pln"> </span><span class="str">"cart"</span><span class="pun">;</span><span class="pln">

   </span><span class="typ">EditDistance</span><span class="pln"> ed </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">EditDistance</span><span class="pun">();</span><span class="pln">
   </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">ed</span><span class="pun">.</span><span class="pln">getMinConversions</span><span class="pun">(</span><span class="pln">str1</span><span class="pun">,</span><span class="pln"> str2</span><span class="pun">));</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="kwd">public</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> getMinConversions</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> str1</span><span class="pun">,</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> str2</span><span class="pun">){</span><span class="pln">
   </span><span class="typ">int</span><span class="pln"> dp</span><span class="pun">[][]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()+</span><span class="lit">1</span><span class="pun">][</span><span class="pln">str2</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()+</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
   </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;=</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">length</span><span class="pun">();</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> j</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">j</span><span class="pun">&lt;=</span><span class="pln">str2</span><span class="pun">.</span><span class="pln">length</span><span class="pun">();</span><span class="pln">j</span><span class="pun">++){</span><span class="pln">
           </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">i</span><span class="pun">==</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
               dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> j</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">j</span><span class="pun">==</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
               dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> str2</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">))</span><span class="pln">
               dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">][</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
           </span><span class="kwd">else</span><span class="pun">{</span><span class="pln">
               dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">][</span><span class="pln">j</span><span class="pun">],</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">min</span><span class="pun">(</span><span class="pln">dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">],</span><span class="pln"> dp</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">][</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]));</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> dp</span><span class="pun">[</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()][</span><span class="pln">str2</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()];</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج الناتج:
</p>

<pre class="ipsCode">3  
</pre>

<h3>
	خوارزمية جدولة المهام الموزونة Weighted Job Scheduling Algorithm
</h3>

<p>
	يُطلق أحيانًا على <a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA/" rel="">خوارزمية</a> جدولة المهام الموزونة اسم خوارزمية اختيار الأنشطة الموزونة Weighted Activity Selection Algorithm، حيث تحاول هذه الخوارزمية حل المشكلة التالية: إذا كانت لديك قائمة من الوظائف وكان لكل وظيفة وقت بدء ووقت انتهاء والربح الذي تحقّقه عند الانتهاء منها، فما هو أقصى ربح يمكن أن تحقّقه؟ علمًا بأنّه لا يمكنك تنفيذ وظيفتين في الوقت نفسه؟
</p>

<p>
	تشبه هذه المشكلة مشكلة "اختيار النشاط باستخدام <a href="https://ar.wikipedia.org/wiki/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9_%D8%AC%D8%B4%D8%B9%D8%A9" rel="external nofollow">الخوارزمية الجشعة</a> Greedy Algorithm"، لكن هناك جانبًا آخر ينبغي أن يُؤخذ بالحسبان، إذ يجب نركّز على تحقيق أقصى قدر من الأرباح بدلًا من زيادة عدد الوظائف المطلوبة إلى أقصى حد، ولا يهم هنا عدد الوظائف المنجزة.
</p>

<p>
	لنأخذ مثالا عمليًا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3254_8" style=""><span class="pun">+---------------------------------+---------+---------+---------+---------+---------+--------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">          </span><span class="typ">Name</span><span class="pln">                   </span><span class="pun">|</span><span class="pln">    A    </span><span class="pun">|</span><span class="pln">    B    </span><span class="pun">|</span><span class="pln">    C    </span><span class="pun">|</span><span class="pln">    D    </span><span class="pun">|</span><span class="pln">    E    </span><span class="pun">|</span><span class="pln">    F   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---------------------------------+---------+---------+---------+---------+---------+--------+</span><span class="pln">
</span><span class="pun">|(</span><span class="typ">Start</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Finish</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">)</span><span class="pln">        </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="lit">5</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="lit">7</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">7</span><span class="pun">,</span><span class="lit">9</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">3</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="lit">8</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="lit">6</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---------------------------------+---------+---------+---------+---------+---------+--------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Profit</span><span class="pln">                  </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">2</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---------------------------------+---------+---------+---------+---------+---------+--------+</span></pre>

<p>
	يحتوي الجدول أعلاه على أسماء الوظائف ووقت بدايتها ونهايتها وأجرها. وتستطيع ملاحظة أنك إذا قمت بالعملين <code>A</code> و<code>E</code>، فستحصل على أقصى ربح ممكن (وهو 17)، لكن السؤال الآن هو: كيف يمكن العثور على ذلك باستخدام خوارزمية؟
</p>

<p>
	أول شيء سنفعله هو ترتيب الوظائف حسب أوقات انتهائها ترتيبًا غير متناقص non-decreasing order، وذلك لأنّه عند اختيار وظيفة تستغرق وقتًا قليلًا لتنفيذها، سيتبّقى وقت أطول ينقضي في اختيار الوظائف الأخرى. انظر أدناه حيث الوظائف مرتبةً:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3254_10" style=""><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">          </span><span class="typ">Name</span><span class="pln">                  </span><span class="pun">|</span><span class="pln">    D    </span><span class="pun">|</span><span class="pln">    A    </span><span class="pun">|</span><span class="pln">    F    </span><span class="pun">|</span><span class="pln">    B    </span><span class="pun">|</span><span class="pln">    E    </span><span class="pun">|</span><span class="pln">   C   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|(</span><span class="typ">Start</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Finish</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">)</span><span class="pln">       </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">3</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="lit">5</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="lit">6</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="lit">7</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="lit">8</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="pun">(</span><span class="lit">7</span><span class="pun">,</span><span class="lit">9</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Profit</span><span class="pln">                 </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span></pre>

<p>
	ستصبح لدينا المصفوفة المؤقّتة الإضافية <code>Acc_Prof</code> التي يساوي حجمها <code>n</code> (إجمالي عدد الوظائف)، وتحتوي أقصى قدر من الأرباح المتراكمة جرّاء أداء الوظائف.
</p>

<p>
	لتوضيح الفكرة، سنهيّئ initializing قيم المصفوفة بأرباح كل وظيفة، وهذا يعني أنّ العنصر Acc_Prof ‎‎ سيخزّن في البداية أرباح إنجاز الوظيفة رقم <code>i</code>.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3254_12" style=""><span class="pun">+-------------------------+---------+---------+---------+---------+---------+---------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Acc_Prof</span><span class="pln">        </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="lit">2</span><span class="pln">    </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+-------------------------+---------+---------+---------+---------+---------+---------+</span></pre>

<p>
	سنشير الآن إلى الموضع 2 بالرمز <code>i</code>، وإلى الموضع 1 بالرمز <code>j</code>. تُبنى استراتيجيتنا هنا على تكرار <code>j</code> من 1 إلى <code>i-1</code>، ونزيد <code>i</code> بمقدار 1 عقب كلّ تكرار إلى أن تساوي <code>i</code> قيمة <code>n +1</code>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3254_16" style=""><span class="pln">                                        j         i
</span><span class="pun">+----------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">          </span><span class="typ">Name</span><span class="pln">                    </span><span class="pun">|</span><span class="pln">    D    </span><span class="pun">|</span><span class="pln">    A    </span><span class="pun">|</span><span class="pln">    F    </span><span class="pun">|</span><span class="pln">    B    </span><span class="pun">|</span><span class="pln">    E    </span><span class="pun">|</span><span class="pln">   C   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|(</span><span class="typ">Start</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Finish</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">)</span><span class="pln">         </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">3</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="lit">5</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="lit">6</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="lit">7</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="lit">8</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="pun">(</span><span class="lit">7</span><span class="pun">,</span><span class="lit">9</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Profit</span><span class="pln">                   </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Acc_Prof</span><span class="pln">                 </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">   </span><span class="lit">11</span><span class="pln">    </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+----------------------------------+---------+---------+---------+---------+---------+-------+</span></pre>

<p>
	سنتحقق الآن ممّا إذا كان هناك تداخل بين الوظيفتين و<code>[j]</code>، أي إذا كان وقت إنتهاء الوظيفة <code>[j]</code> أكبر من وقت بدء الوظيفة ، إذ لا يمكن في تلك الحالة إجراء هاتين الوظيفتين معًا؛ أما خلاف ذلك فسنتحقّق مما إذا كان <code>Acc_Prof[j] + Proﬁt &gt; Acc_Prof</code>، وإذا كان كذلك، فسنجري التحديث الآتي: 
</p>

<p>
	<code>Acc_Prof = Acc_Prof[j] + Proﬁt‎‎</code>
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5272_30" style=""><span class="kwd">if</span><span class="pln"> </span><span class="typ">Job</span><span class="pun">[</span><span class="pln">j</span><span class="pun">].</span><span class="pln">finish_time </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="typ">Job</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">start_time
    </span><span class="kwd">if</span><span class="pln"> </span><span class="typ">Acc_Prof</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="typ">Profit</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="typ">Acc_Prof</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
        </span><span class="typ">Acc_Prof</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Acc_Prof</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="typ">Profit</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
    endif
endif</span></pre>

<p>
	تمثّل <code>Acc_Prof[j] + Proﬁt‎‎</code> هنا الربح المتراكم الناتج عن القيام بهاتين الوظيفتين، وتتداخل الوظيفة <code>[j]</code> مع ، لذا لا يمكن القيام بهما معًا. وبما أن <code>j</code> يساوي <code>i-1</code>، فسنزيد قيمة <code>i</code> إلى <code>i +1</code>، أي <code>3</code>، ثمّ نجعل <code>j = 1</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3254_18" style=""><span class="pln">                                       j                   i
</span><span class="pun">+---------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">          </span><span class="typ">Name</span><span class="pln">                   </span><span class="pun">|</span><span class="pln">    D    </span><span class="pun">|</span><span class="pln">    A    </span><span class="pun">|</span><span class="pln">    F    </span><span class="pun">|</span><span class="pln">    B    </span><span class="pun">|</span><span class="pln">    E    </span><span class="pun">|</span><span class="pln">   C   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|(</span><span class="typ">Start</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Finish</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">)</span><span class="pln">        </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">3</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="lit">5</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="lit">6</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="lit">7</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="lit">8</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="pun">(</span><span class="lit">7</span><span class="pun">,</span><span class="lit">9</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Profit</span><span class="pln">                  </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Acc_Prof</span><span class="pln">                </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="lit">2</span><span class="pln">  </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+---------------------------------+---------+---------+---------+---------+---------+-------+</span></pre>

<p>
	لا تتداخل الوظيفتان [j] و الآن، أمّا الربح الإجمالي الذي يمكن تحصيله بتنفيذهما، فهو Acc_Prof[j] + Proﬁt = 5 + 5 = 10، وهو أكبر من Acc_Prof ‎‎، لذا نجري التحديث Acc_Prof = 10، كما نزيد أيضًا قيمة <code>j</code> بـ <code>1</code> لنحصل على ما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3254_20" style=""><span class="pln">                                                j         i
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">           </span><span class="typ">Name</span><span class="pln">                 </span><span class="pun">|</span><span class="pln">    D    </span><span class="pun">|</span><span class="pln">    A    </span><span class="pun">|</span><span class="pln">    F    </span><span class="pun">|</span><span class="pln">    B    </span><span class="pun">|</span><span class="pln">    E    </span><span class="pun">|</span><span class="pln">   C   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|(</span><span class="typ">Start</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Finish</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">)</span><span class="pln">       </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">3</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="lit">5</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="lit">6</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="lit">7</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="lit">8</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="pun">(</span><span class="lit">7</span><span class="pun">,</span><span class="lit">9</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Profit</span><span class="pln">                 </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Acc_Prof</span><span class="pln">               </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">10</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span></pre>

<p>
	تتداخل هنا <code>[j]</code> مع ، بينما تساوي <code>j</code> قيمة <code>i-1</code>، لذا نزيد <code>i</code> بمقدار <code>1</code>، ونجعل <code>j = 1</code> لنحصل على التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3254_24" style=""><span class="pln">                                      j                             i
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">          </span><span class="typ">Name</span><span class="pln">                  </span><span class="pun">|</span><span class="pln">    D    </span><span class="pun">|</span><span class="pln">    A    </span><span class="pun">|</span><span class="pln">    F    </span><span class="pun">|</span><span class="pln">    B    </span><span class="pun">|</span><span class="pln">    E    </span><span class="pun">|</span><span class="pln">   C   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|(</span><span class="typ">Start</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Finish</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">)</span><span class="pln">       </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">3</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="lit">5</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="lit">6</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="lit">7</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="lit">8</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="pun">(</span><span class="lit">7</span><span class="pun">,</span><span class="lit">9</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Profit</span><span class="pln">                 </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Acc_Prof</span><span class="pln">               </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">10</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span></pre>

<p>
	الآن، لا تتداخل الوظيفتان <code>‎‎[j]‎‎</code> و<code>‎‎‎‎</code>، بينما يساوي الربح المتراكم القيمة 5 + 4 = 9، وهو أكبر من Acc_Prof، لذا نجري التحديث Acc_Prof = 9، ونزيد <code>j</code> بمقدار <code>1</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3254_26" style=""><span class="pln">                                                j                   i
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">          </span><span class="typ">Name</span><span class="pln">                  </span><span class="pun">|</span><span class="pln">    D    </span><span class="pun">|</span><span class="pln">    A    </span><span class="pun">|</span><span class="pln">    F    </span><span class="pun">|</span><span class="pln">    B    </span><span class="pun">|</span><span class="pln">    E    </span><span class="pun">|</span><span class="pln">   C   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|(</span><span class="typ">Start</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Finish</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">)</span><span class="pln">       </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">3</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="lit">5</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="lit">6</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="lit">7</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="lit">8</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="pun">(</span><span class="lit">7</span><span class="pun">,</span><span class="lit">9</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Profit</span><span class="pln">                 </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Acc_Prof</span><span class="pln">               </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">10</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="lit">9</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span></pre>

<p>
	كذلك، لا تتداخل ‎‎[j]‎‎ و‎‎‎‎ الآن، أمّا الربح المتراكم فيساوي: 6 + 4 = 10، وهو أكبر من Acc_Prof ‎‎. سنجري التحديث Acc_Prof = 10 مرّةً أخرى ، ونزيد <code>j</code> بـ <code>1</code> لنحصل على:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3254_28" style=""><span class="pln">                                                          j         i
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">          </span><span class="typ">Name</span><span class="pln">                  </span><span class="pun">|</span><span class="pln">    D    </span><span class="pun">|</span><span class="pln">    A    </span><span class="pun">|</span><span class="pln">    F    </span><span class="pun">|</span><span class="pln">    B    </span><span class="pun">|</span><span class="pln">    E    </span><span class="pun">|</span><span class="pln">   C   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|(</span><span class="typ">Start</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Finish</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">)</span><span class="pln">       </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">3</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="lit">5</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="lit">6</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="lit">7</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="lit">8</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="pun">(</span><span class="lit">7</span><span class="pun">,</span><span class="lit">9</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Profit</span><span class="pln">                 </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Acc_Prof</span><span class="pln">               </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">10</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="lit">10</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span></pre>

<p>
	إذا واصلنا هذه العملية وكررنا الجدول بأكمله، فسيبدو جدولنا كما يلي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3254_30" style=""><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">          </span><span class="typ">Name</span><span class="pln">                  </span><span class="pun">|</span><span class="pln">    D    </span><span class="pun">|</span><span class="pln">    A    </span><span class="pun">|</span><span class="pln">    F    </span><span class="pun">|</span><span class="pln">    B    </span><span class="pun">|</span><span class="pln">    E    </span><span class="pun">|</span><span class="pln">   C   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|(</span><span class="typ">Start</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Finish</span><span class="pln"> </span><span class="typ">Time</span><span class="pun">)</span><span class="pln">       </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">1</span><span class="pun">,</span><span class="lit">3</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="lit">5</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">4</span><span class="pun">,</span><span class="lit">6</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">6</span><span class="pun">,</span><span class="lit">7</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln">  </span><span class="pun">(</span><span class="lit">5</span><span class="pun">,</span><span class="lit">8</span><span class="pun">)</span><span class="pln">  </span><span class="pun">|</span><span class="pln"> </span><span class="pun">(</span><span class="lit">7</span><span class="pun">,</span><span class="lit">9</span><span class="pun">)</span><span class="pln"> </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Profit</span><span class="pln">                 </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">4</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">11</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">2</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span><span class="pln">
</span><span class="pun">|</span><span class="pln">         </span><span class="typ">Acc_Prof</span><span class="pln">               </span><span class="pun">|</span><span class="pln">    </span><span class="lit">5</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">6</span><span class="pln">    </span><span class="pun">|</span><span class="pln">    </span><span class="lit">10</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="lit">14</span><span class="pln">   </span><span class="pun">|</span><span class="pln">    </span><span class="lit">17</span><span class="pln">   </span><span class="pun">|</span><span class="pln">   </span><span class="lit">8</span><span class="pln">   </span><span class="pun">|</span><span class="pln">
</span><span class="pun">+--------------------------------+---------+---------+---------+---------+---------+-------+</span></pre>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		تجاوزنا بعض الخطوات للإيجاز.
	</p>
</blockquote>

<p>
	إذا كررنا عبر المصفوفة <code>Acc_Prof</code>، فسنجد أنّ الربح الأقصى الممكن هو 17.
</p>

<p>
	انظر إلى الشيفرة التوضيحية التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5272_44" style=""><span class="typ">Procedure</span><span class="pln"> </span><span class="typ">WeightedJobScheduling</span><span class="pun">(</span><span class="typ">Job</span><span class="pun">)</span><span class="pln">
sort </span><span class="typ">Job</span><span class="pln"> according to finish time in non</span><span class="pun">-</span><span class="pln">decreasing order
</span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> to n
   </span><span class="kwd">for</span><span class="pln"> j </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to i</span><span class="pun">-</span><span class="lit">1</span><span class="pln">
       </span><span class="kwd">if</span><span class="pln"> </span><span class="typ">Job</span><span class="pun">[</span><span class="pln">j</span><span class="pun">].</span><span class="pln">finish_time </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="typ">Job</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">start_time
           </span><span class="kwd">if</span><span class="pln"> </span><span class="typ">Acc_Prof</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="typ">Profit</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="typ">Acc_Prof</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
               </span><span class="typ">Acc_Prof</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Acc_Prof</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="typ">Profit</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
endif
       endif
   endfor
endfor
maxProfit </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">-&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> to n
   </span><span class="kwd">if</span><span class="pln"> maxProfit </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">Acc_Prof</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
       maxProfit </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Acc_Prof</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
</span><span class="kwd">return</span><span class="pln"> maxProfit</span></pre>

<p>
	تعقيد تعبئة المصفوفة Acc_Prof هو O(n2)‎‎، بينما يستغرق اجتياز المصفوفة O(n)‎‎، لذا فإنّ التعقيد الكلي لهذه الخوارزمية هو O (n2)‎‎.
</p>

<p>
	والآن، إذا أردنا العثور على الوظائف التي تحقّق أقصى قدر من الربح، فسنحتاج إلى عبور المصفوفة أو اجتيازها بترتيب عكسي، وإذا تطابق Acc_Prof مع الربح الأقصى maxPro، فسندفع push اسم الوظيفة إلى <a href="https://ar.wikipedia.org/wiki/%D9%85%D9%83%D8%AF%D8%B3_(%D8%A8%D9%86%D9%8A%D8%A9_%D8%A8%D9%8A%D8%A7%D9%86%D8%A7%D8%AA)" rel="external nofollow">مكدّس</a> stack، ونطرح أرباح تلك الوظيفة من قيمة maxPro. سنستمرّ في فعل هذا حتى يصير maxProT t&gt; 0، أو نصل إلى نقطة البداية في المصفوفة Acc_Prof. وستبدو الشيفرة التوضيحية كالتالي:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_5272_46" style=""><span class="typ">Procedure</span><span class="pln"> </span><span class="typ">FindingPerformedJobs</span><span class="pun">(</span><span class="typ">Job</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Acc_Prof</span><span class="pun">,</span><span class="pln"> maxProfit</span><span class="pun">):</span><span class="pln">
S </span><span class="pun">=</span><span class="pln"> stack</span><span class="pun">()</span><span class="pln">
</span><span class="kwd">for</span><span class="pln"> i </span><span class="pun">-&gt;</span><span class="pln"> n down to </span><span class="lit">0</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> maxProfit </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> maxProfit is equal to </span><span class="typ">Acc_Prof</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln">
        S</span><span class="pun">.</span><span class="pln">push</span><span class="pun">(</span><span class="typ">Job</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">name
        maxProfit </span><span class="pun">=</span><span class="pln"> maxProfit </span><span class="pun">-</span><span class="pln"> </span><span class="typ">Job</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">profit
    endif
endfor</span></pre>

<p>
	تعقيد هذا الإجراء هو O (n)‎‎.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<strong>تنبيه</strong>: إذا كان هناك أكثر من جدول أعمال واحد يمكن أن يحقق لنا أقصى قدر من الأرباح، فلن تعطينا هذه الخوارزمية إلا واحدًا منها فقط.
	</p>
</blockquote>

<h3>
	أطول تسلسل مشترك Longest Common Subsequence
</h3>

<p>
	لتكن str1 وstr2 سلسلتان نصيّتان، حيث سنحاول العثور على أطول تتابع sub-sequence مشترك بينهما من الحروف.
</p>

<p>
	انظر إلى الأمثلة التوضيحية التالية:
</p>

<ul>
	<li>
		أكبر تتابع مشترك للسلسلتين النصيتين “ABCDGH” و“AEDFHR” هو “ADH”، وطوله 3.
	</li>
	<li>
		أطول تتابع مشترك بين “AGGTAB” و“GXTXAYB” هو “GTAB”، وطوله 4.
	</li>
</ul>

<p>
	فيما يلي تطبيق للحلّ في لغة جافا:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5272_48" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> LCS </span><span class="pun">{</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
       </span><span class="com">// TODO Auto-generated method stub</span><span class="pln">
       </span><span class="typ">String</span><span class="pln"> str1 </span><span class="pun">=</span><span class="pln"> </span><span class="str">"AGGTAB"</span><span class="pun">;</span><span class="pln">
       </span><span class="typ">String</span><span class="pln"> str2 </span><span class="pun">=</span><span class="pln"> </span><span class="str">"GXTXAYB"</span><span class="pun">;</span><span class="pln">
       LCS obj </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> LCS</span><span class="pun">();</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">lcs</span><span class="pun">(</span><span class="pln">str1</span><span class="pun">,</span><span class="pln"> str2</span><span class="pun">,</span><span class="pln"> str1</span><span class="pun">.</span><span class="pln">length</span><span class="pun">(),</span><span class="pln"> str2</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()));</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">obj</span><span class="pun">.</span><span class="pln">lcs2</span><span class="pun">(</span><span class="pln">str1</span><span class="pun">,</span><span class="pln"> str2</span><span class="pun">));</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">

   </span><span class="com">//Recursive function</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> lcs</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> str1</span><span class="pun">,</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> str2</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> m</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> n</span><span class="pun">){</span><span class="pln">
</span><span class="kwd">if</span><span class="pun">(</span><span class="pln">m</span><span class="pun">==</span><span class="lit">0</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> n</span><span class="pun">==</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
           </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">m</span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> str2</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">n</span><span class="pun">-</span><span class="lit">1</span><span class="pun">))</span><span class="pln">
           </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> lcs</span><span class="pun">(</span><span class="pln">str1</span><span class="pun">,</span><span class="pln"> str2</span><span class="pun">,</span><span class="pln"> m</span><span class="pun">-</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">-</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
       </span><span class="kwd">else</span><span class="pln">
           </span><span class="kwd">return</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">lcs</span><span class="pun">(</span><span class="pln">str1</span><span class="pun">,</span><span class="pln"> str2</span><span class="pun">,</span><span class="pln"> m</span><span class="pun">-</span><span class="lit">1</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">),</span><span class="pln"> lcs</span><span class="pun">(</span><span class="pln">str1</span><span class="pun">,</span><span class="pln"> str2</span><span class="pun">,</span><span class="pln"> m</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">-</span><span class="lit">1</span><span class="pun">));</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">

   </span><span class="com">//دالة تكرارية</span><span class="pln">
   </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> lcs2</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> str1</span><span class="pun">,</span><span class="pln"> </span><span class="typ">String</span><span class="pln"> str2</span><span class="pun">){</span><span class="pln">
       </span><span class="typ">int</span><span class="pln"> lcs</span><span class="pun">[][]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">int</span><span class="pun">[</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()+</span><span class="lit">1</span><span class="pun">][</span><span class="pln">str2</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()+</span><span class="lit">1</span><span class="pun">];</span><span class="pln">

       </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;=</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">length</span><span class="pun">();</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">
           </span><span class="kwd">for</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> j</span><span class="pun">=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">j</span><span class="pun">&lt;=</span><span class="pln">str2</span><span class="pun">.</span><span class="pln">length</span><span class="pun">();</span><span class="pln">j</span><span class="pun">++){</span><span class="pln">
               </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">i</span><span class="pun">==</span><span class="lit">0</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> j</span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pun">){</span><span class="pln">
                   lcs</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
               </span><span class="pun">}</span><span class="pln">
               </span><span class="kwd">else</span><span class="pln"> </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> str2</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">)){</span><span class="pln">
                   lcs</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> lcs</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">][</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
               </span><span class="pun">}</span><span class="kwd">else</span><span class="pun">{</span><span class="pln">
                   lcs</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">lcs</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">][</span><span class="pln">j</span><span class="pun">],</span><span class="pln"> lcs</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]);</span><span class="pln">
               </span><span class="pun">}</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">

       </span><span class="kwd">return</span><span class="pln"> lcs</span><span class="pun">[</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()][</span><span class="pln">str2</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()];</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	سيكون الخرج الناتج كالآتي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5272_50" style=""><span class="lit">4</span></pre>

<h3>
	أعداد فيبوناتشي
</h3>

<p>
	هذا منظور تصاعدي لطباعة <a href="https://ar.wikipedia.org/wiki/%D9%84%D9%8A%D9%88%D9%86%D8%A7%D8%B1%D8%AF%D9%88_%D9%81%D9%8A%D8%A8%D9%88%D9%86%D8%A7%D8%AA%D8%B4%D9%8A" rel="external nofollow">عدد فيبوناتشي</a> التاسع باستخدام البرمجة الديناميكية:
</p>

<p>
	انظر إلى الشجرة التكرارية التالية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3254_32" style=""><span class="pln">                            fib</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln"> 
                  </span><span class="pun">/</span><span class="pln">                          \   
              fib</span><span class="pun">(</span><span class="lit">4</span><span class="pun">)</span><span class="pln">                       fib</span><span class="pun">(</span><span class="lit">3</span><span class="pun">)</span><span class="pln"> 
            </span><span class="pun">/</span><span class="pln">          \                  </span><span class="pun">/</span><span class="pln">    \
        fib</span><span class="pun">(</span><span class="lit">3</span><span class="pun">)</span><span class="pln">       fib</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln">             fib</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> fib</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">
       </span><span class="pun">/</span><span class="pln">     \      </span><span class="pun">/</span><span class="pln">    \              </span><span class="pun">/</span><span class="pln">     \ 
 fib</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln">   fib</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">   fib</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> fib</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">    fib</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">   fib</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
 </span><span class="pun">/</span><span class="pln">            \
fib</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">       fib</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span></pre>

<p>
	في هذا المثال، تكون كل من <code>ﬁb(0)‎‎</code> و<code>ﬁb(1)‎‎</code> و<code>ﬁb(3)‎‎</code> هي المشاكل المتداخلة الفرعية overlapping sub-problems، إذ أنّ <code>b(0)‎‎</code> تكرّرت 3 مرات، في حين تكرّرت <code>ﬁb(1)‎‎</code> خمس مرات، وتكرّرت <code>ﬁb(3)‎‎</code> مرّتين. انظر الشيفرة التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5272_54" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> fib</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> n</span><span class="pun">){</span><span class="pln">
 </span><span class="kwd">int</span><span class="pln"> f</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">[</span><span class="pln">n</span><span class="pun">+</span><span class="lit">1</span><span class="pun">];</span><span class="pln">

        f</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]=</span><span class="lit">0</span><span class="pun">;</span><span class="pln">f</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]=</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
 </span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">2</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;=</span><span class="pln">n</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">
            f</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]=</span><span class="pln">f</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]+</span><span class="pln">f</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">2</span><span class="pun">];</span><span class="pln">
 </span><span class="pun">}</span><span class="pln">
 </span><span class="kwd">return</span><span class="pln"> f</span><span class="pun">[</span><span class="pln">n</span><span class="pun">];</span><span class="pln">
 </span><span class="pun">}</span></pre>

<p>
	تعقيد الشيفرة أعلاه يساوي‎‎O(n) ‎‎.
</p>

<h3>
	أطول سلسلة نصية فرعية مشتركة Longest Common Substring
</h3>

<p>
	إذا كان لدينا السلسلتان النصيتان str1 وstr2، فيجب أن نبحث عن أطول سلسلة نصية فرعية مشتركة longest common substring بينهما. انظر الأمثلة التوضيحية التالية:
</p>

<ul>
	<li>
		الدخل: x = abcdxyz وy = xyzabcd والخرج: 4 -، لأنّ أطول سلسلة نصية فرعية مشتركة هي <code>abcd</code>، ويبلغ طولها 4.
	</li>
	<li>
		الدخل: x = zxabcdezy وy = yzabcdezx والخرج: 6 -، لأنّ أطول سلسلة نصية فرعية مشتركة هي <code>abcdez</code>، وطولها هو 6.
	</li>
</ul>

<p>
	هذا تطبيق في لغة جافا لخوارزمية تحلّ هذه المشكلة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5272_56" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">int</span><span class="pln"> getLongestCommonSubstring</span><span class="pun">(</span><span class="typ">String</span><span class="pln"> str1</span><span class="pun">,</span><span class="typ">String</span><span class="pln"> str2</span><span class="pun">){</span><span class="pln">
       </span><span class="kwd">int</span><span class="pln"> arr</span><span class="pun">[][]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="kwd">int</span><span class="pun">[</span><span class="pln">str2</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()+</span><span class="lit">1</span><span class="pun">][</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">length</span><span class="pun">()+</span><span class="lit">1</span><span class="pun">];</span><span class="pln">
       </span><span class="kwd">int</span><span class="pln"> max </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Integer</span><span class="pun">.</span><span class="pln">MIN_VALUE</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> i</span><span class="pun">=</span><span class="lit">1</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;=</span><span class="pln">str2</span><span class="pun">.</span><span class="pln">length</span><span class="pun">();</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">
           </span><span class="kwd">for</span><span class="pun">(</span><span class="kwd">int</span><span class="pln"> j</span><span class="pun">=</span><span class="lit">1</span><span class="pun">;</span><span class="pln">j</span><span class="pun">&lt;=</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">length</span><span class="pun">();</span><span class="pln">j</span><span class="pun">++){</span><span class="pln">
               </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">str1</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> str2</span><span class="pun">.</span><span class="pln">charAt</span><span class="pun">(</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">)){</span><span class="pln">
                   arr</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">][</span><span class="pln">j</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]+</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
                   </span><span class="kwd">if</span><span class="pun">(</span><span class="pln">arr</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]&gt;</span><span class="pln">max</span><span class="pun">)</span><span class="pln">
                       max </span><span class="pun">=</span><span class="pln"> arr</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">];</span><span class="pln">
               </span><span class="pun">}</span><span class="pln">
               </span><span class="kwd">else</span><span class="pln">
                   arr</span><span class="pun">[</span><span class="pln">i</span><span class="pun">][</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> max</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span></pre>

<p>
	التعقيد الزمني للخوارزمية أعلاه يساوي O(m*n)‎‎.
</p>

<h2>
	تطبيقات البرمجة الديناميكية
</h2>

<p>
	تقوم البرمجة الديناميكية على فكرة تقسيم مشكلة معقدة إلى مشاكل أصغر وأبسط متكرّرة كما ذكرنا أول حديثنا، وسنركّز في هذه الفقرة على التطبيقات، وليس على إنشاء خوارزميات البرمجة الديناميكية.
</p>

<p>
	تعرضنا لأعداد فيبوناتشي كذلك قبل قليل، وتعَد هذه الأعداد من المواضيع الرئيسية للبرمجة الديناميكية، إذ أنّ المنظور التكراري التقليدي يتطلّب الكثير من الحسابات المكرّرة. سنستخدم في هذه الأمثلة الحالة الأساسية <code>‎f( 0) = f (1) =</code>1. فيما يلي مثال على شجرة تكرارية لـ <code>‎fibonacci(4)‎</code>، لاحظ أنّ هناك حسابات مكرّرة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="81268" href="https://academy.hsoub.com/uploads/monthly_2021_10/CLwKE.jpg.a4cc0a8b152ff0acc7b01f2f98b9f955.jpg" rel="" data-fileext="jpg"><img alt="CLwKE.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="81268" data-unique="uq1dnuz36" style="width: 600px; height: auto;" src="https://academy.hsoub.com/uploads/monthly_2021_10/CLwKE.jpg.a4cc0a8b152ff0acc7b01f2f98b9f955.jpg"></a>
</p>

<p>
	في البرمجة غير الديناميكية، يساوي التعقيد الزمني <code>‎O(2^n)‎</code>، فيما يساوي تعقيد المكدّس Stack complexity القيمة <code>‎O(n)‎</code>.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5272_61" style=""><span class="pln">def fibonacci</span><span class="pun">(</span><span class="pln">n</span><span class="pun">):</span><span class="pln">
     </span><span class="kwd">if</span><span class="pln"> n </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">2</span><span class="pun">:</span><span class="pln">
          </span><span class="kwd">return</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
     </span><span class="kwd">return</span><span class="pln"> fibonacci</span><span class="pun">(</span><span class="pln">n</span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> fibonacci</span><span class="pun">(</span><span class="pln">n</span><span class="pun">-</span><span class="lit">2</span><span class="pun">)</span></pre>

<p>
	هذه هي الطريقة البديهية لحلّ المشكلة، حيث لن تتجاوز مساحة المكدّس stack space القيمة <code>‎O(n)‎</code> عندما تنزل إلى الفرع الأول التكراري recursive branch مجريًا استدعاءات لـ <code>‎fibonacci(n-1)‎</code> تباعًا إلى أن تصل إلى الحالة الأساسية (أي <code>‎n &lt; 2‎</code>).
</p>

<p>
	النقطة الرئيسية هنا هي أنّ وقت التشغيل أسّي exponential، ما يعني أنّه سيتضاعف في كل خطوة، حيث سيستغرق <code>‎fibonacci(15)‎</code> مثلًا ضعف المدة التي يستغرقها <code>‎fibonacci(14)‎</code>
</p>

<ul>
	<li>
		الخوارزمية التذكيرية Memoized: التعقيد الزمني يساوي <code>O(n)‎‎</code>، ويساوي تعقيد المساحة Space complexity القيمة O(n)<code>‎‎</code>، فيما يساوي تعقيد المكدّس <code>O(n)‎‎</code>.
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5272_63" style=""><span class="pln">memo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[]</span><span class="pln">
memo</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="com"># f(1) = 1</span><span class="pln">
memo</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="com"># f(2) = 1</span><span class="pln">
def fibonacci</span><span class="pun">(</span><span class="pln">n</span><span class="pun">):</span><span class="pln">
   </span><span class="kwd">if</span><span class="pln"> len</span><span class="pun">(</span><span class="pln">memo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> n</span><span class="pun">:</span><span class="pln">
      </span><span class="kwd">return</span><span class="pln"> memo</span><span class="pun">[</span><span class="pln">n</span><span class="pun">]</span><span class="pln">
    result </span><span class="pun">=</span><span class="pln"> fibonacci</span><span class="pun">(</span><span class="pln">n</span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> fibonacci</span><span class="pun">(</span><span class="pln">n</span><span class="pun">-</span><span class="lit">2</span><span class="pun">)</span><span class="pln">
    memo</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">result</span><span class="pun">)</span><span class="pln"> </span><span class="com"># f(n) = f(n-1) + f(n-2)</span><span class="pln">
   </span><span class="kwd">return</span><span class="pln"> result</span></pre>

<p>
	نقدّم باستخدام المنظور التذكيري memoized approach مصفوفةً تمثّل جميع استدعاءات الدوال السابقة ، ويكون الموقع <code>‎memo[n]‎</code> نتيجةً لاستدعاء الدالة <code>‎fibonacci(n)‎</code>. يتيح لنا هذا مقايضة تعقيد مساحة <code>‎O(n)‎</code> بوقت تشغيل <code>‎O(n)‎</code>، إذ ستنتفي الحاجة إلى إعادة حساب استدعاءات الدوالّ المكررة.
</p>

<ul>
	<li>
		البرمجة الديناميكية التكرارية وقت التشغيل يساوي <code>‎O(n)‎</code>، وتعقيد المساحة هو <code>‎O(n)‎</code> بدون مكدّس تكراري recursive stack.
	</li>
</ul>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5272_65" style=""><span class="pln">def fibonacci</span><span class="pun">(</span><span class="pln">n</span><span class="pun">):</span><span class="pln">
    memo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="com"># f(0) = 1, f(1) = 1</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> i in range</span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">+</span><span class="lit">1</span><span class="pun">):</span><span class="pln">
         memo</span><span class="pun">.</span><span class="pln">append</span><span class="pun">(</span><span class="pln">memo</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> memo</span><span class="pun">[</span><span class="pln">i</span><span class="pun">-</span><span class="lit">2</span><span class="pun">])</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> memo</span><span class="pun">[</span><span class="pln">n</span><span class="pun">]</span></pre>

<p>
	إذا قسّمت المشكلة إلى عناصرها الأساسية فستلاحظ أنّه لحساب <code>‎fibonacci(n)‎</code>. تحتاج إلى حساب <code>‎fibonacci(n-1)‎</code> و<code>‎fibonacci(n-2)‎</code>، كما يمكن ملاحظة أنّ الحالة الأساسية ستظهر في نهاية تلك الشجرة التكرارية كما هو موضّح أعلاه.
</p>

<p>
	صار من المنطقي الآن باستخدام هذه المعلومات أن نحسب الحل من الخلف، أي بدءًا من الحالات الأساسية، ثمّ الصعود إلى الأعلى. ولكي نحسب الآن <code>‎fibonacci(n)‎</code>، sنحتاج إلى حساب جميع أعداد فيبوناتشي الخاصة بكل الأعداد الأصغر من <code>‎n‎</code>.
</p>

<p>
	الفائدة الرئيسية لهذا المنظور هي أنّنا لم نَعُد نحتاج إلى مكدّس تكراري، مع الحفاظ على وقت التشغيل <code>‎O(n)‎</code> في نفس الوقت. لا يزال تعقيد المساحة هو <code>‎O(n)‎</code>، لكن يمكن تغيير ذلك أيضًا.
</p>

<ul>
	<li>
		البرمجة الديناميكية التكرارية المتقدمة Advanced Iterative Dynamic Programming: يساوي وقت التشغيل <code>‎O(n)‎</code>، أما تعقيد المساحة فهو <code>‎O(1)‎</code>، وبدون مكدّس تكراري recursive stack.
	</li>
</ul>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5272_67" style=""><span class="pln">def fibonacci</span><span class="pun">(</span><span class="pln">n</span><span class="pun">):</span><span class="pln">
    memo </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[</span><span class="lit">1</span><span class="pun">,</span><span class="lit">1</span><span class="pun">]</span><span class="pln"> </span><span class="pun">#</span><span class="pln"> f</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> f</span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> i in range </span><span class="pun">(</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> n</span><span class="pun">):</span><span class="pln">
        memo</span><span class="pun">[</span><span class="pln">i</span><span class="pun">%</span><span class="lit">2</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> memo</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> memo</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span><span class="pln">
    </span><span class="kwd">return</span><span class="pln"> memo</span><span class="pun">[</span><span class="pln">n</span><span class="pun">%</span><span class="lit">2</span><span class="pun">]</span></pre>

<p>
	يبدأ منظور البرمجة الديناميكية التكرارية من الحالات الأساسية كما لوحظ أعلاه، وتصعد انطلاقًا منها إلى النتيجة النهائية. تنطبق نفس الملاحظة التي أشرنا لها سابقًا بخصوص المكدّس التكراري هنا، فلأجل تحويل تعقيد المساحة إلى <code>‎O(1)‎</code> (أي تعقيد ثابت)، لن نحتاج إلّا إلى <code>‎fibonacci(n-1)‎</code> و<code>‎fibonacci(n-2)‎</code> لبناء قيمة فيبوناتشي <code>‎fibonacci(n)‎</code>، وهذا يعني أننا سنكتفي بحفظ نتيجتي <code>‎(n-1)‎</code> و<code>‎(n-2)‎</code> وحسب في كلّ مرة.
</p>

<p>
	لتخزين آخر نتيجتين، نستخدم مصفوفة ثنائية مع تغيير قيمة الفهرس الذي سنعيّنه باستخدام الصيغة <code>‎i % 2‎</code>، والتي تتراوح قيمتها بين 0 و1 كما يلي: <code>0، 1، 0، 1، 0، 1، ...، i ‎% 2</code>.
</p>

<p>
	وقد أضفنا فهرسي المصفوفة معًا لعلمنا أنّ الإضافة تبادلية (<code>‎5 + 6 = 11‎</code> و <code>6 + 5 =‎11</code>)، ثم عيّنّا النتيجة إلى أقدم النقطتين (المُشار إليها بواسطة i ‎% 2<code>‎</code>)، وخزّنّا النتيجة النهائية بعد ذلك في الموضع <code>‎n%2‎</code>.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		ملاحظة: قد يكون من الأفضل في بعض الأحيان استخدام التذكير التكراري iterative memoized لأجل الدوال التي تجري الكثير من الحسابات المتكرّرة، إذ تُخزَّن النتائج السابقة في ذاكرة تخزين مؤقت، مما قد يجعل تعقيد الاستدعاءات اللاحقة المكرّرة ثابتًا ( يساوي <code>‎O(1)‎</code>.
	</p>
</blockquote>

<p>
	ترجمة -بتصرّف- للفصلين 14 و 15 من كتاب <a href="https://goalkicker.com/AlgorithmsBook/" rel="external nofollow">Algorithms Notes for Professionals</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقالة السابقة: <a href="https://academy.hsoub.com/programming/advance/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-%D8%AA%D8%AD%D8%AF%D9%8A%D8%AF-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1-%D8%A7%D9%84%D9%86%D8%AC%D9%85%D9%8A%D8%A9-a-path%EF%AC%81nding-r1363/" rel="">خوارزمية تحديد المسار النجمية A* Pathﬁnding</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D9%83%D9%8A%D9%81-%D8%AA%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r17/" rel="">كيف تتعلم البرمجة</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-r662/" rel="">تعلم البرمجة</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1365</guid><pubDate>Wed, 20 Oct 2021 15:00:00 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x62A;&#x62D;&#x644;&#x64A;&#x644; &#x627;&#x644;&#x62E;&#x648;&#x627;&#x631;&#x632;&#x645;&#x64A;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/advanced/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1345/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/61653eb4b7952_-.png.dd00196a9f1236770e87a6f69533ba18.png" /></p>
<p>
	كما رأينا في مقالة <a href="https://academy.hsoub.com/programming/java/%D8%B7%D8%B1%D9%8A%D9%82%D8%A9-%D8%B9%D9%85%D9%84-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-r1344/" rel="">طريقة عمل الواجهات بلغة جافا</a>، تُوفِّر جافا تنفيذين implementations للواجهة <code>List</code>، هما <code>ArrayList</code> و<code>LinkedList</code>، حيث يكون النوع <code>LinkedList</code> أسرع بالنسبة لبعض التطبيقات، بينما يكون النوع <code>ArrayList</code> أسرع بالنسبة لتطبيقاتٍ أخرى.
</p>

<p>
	وإذا أردنا أن نُحدِّد أيهما أفضل للاستخدام في تطبيق معين، فيمكننا تجربة كلٍّ منهما على حدةٍ لنرى الزمن الذي سيَستغرِقه. يُطلَق على هذا الأسلوب اسم التشخيص profiling، ولكنّ له بعض الإشكاليّات:
</p>

<ol>
	<li>
		أننا سنضطّر إلى تنفيذ الخوارزميتين كلتيهما لكي نتمكَّن من الموازنة بينهما.
	</li>
	<li>
		قد تعتمد النتائج على نوع الحاسوب المُستخدَم، فقد تعمل خوارزمية معينة بكفاءةٍ عالية على حاسوب معين، في حين قد تَعمَل خوارزميةٌ أخرى بكفاءةٍ عاليةٍ على حاسوب مختلف.
	</li>
	<li>
		قد تعتمد النتائج على حجم المشكلة أو البيانات المُدْخَلة.
	</li>
</ol>

<p>
	يُمكِننا معالجة بعض هذه النقاط المُشكلةِ بالاستعانة بما يُعرَف باسم <a href="https://academy.hsoub.com/programming/advance/%D8%AF%D9%84%D9%8A%D9%84-%D8%B4%D8%A7%D9%85%D9%84-%D8%B9%D9%86-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%AA%D8%B9%D9%82%D9%8A%D8%AF-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-r1247/" rel="">تحليل الخوارزميات</a>، الذي يُمكِّننا من الموازنة بين عدة خوارزمياتٍ دون الحاجة إلى تنفيذها فعليًا، ولكننا سنضطّر عندئذٍ لوضع بعض الافتراضات:
</p>

<ol>
	<li>
		فلكي نتجنَّب التفاصيل المتعلقة بعتاد الحاسوب، سنُحدِّد العمليات الأساسية التي تتألف منها أي خوارزميةٍ مثل الجمع والضرب وموازنة عددين، ثم نَحسِب عدد العمليات التي تتطلّبها كل خوارزمية.
	</li>
	<li>
		ولكي نتجنَّب التفاصيل المتعلقة بالبيانات المُدْخَلة، فإن الخيار الأفضل هو تحليل متوسط الأداء للمُدْخَلات التي نتوقع التعامل معها. فإذا لم يَكُن ذلك متاحًا، فسيكون تحليل الحالة الأسوأ هو الخيار البديل الأكثر شيوعًا.
	</li>
	<li>
		أخيرًا، سيتعيّن علينا التعامل مع احتمالية أن يكون أداء خوارزميةٍ معينةٍ فعّالًا عند التعامل مع مشكلات صغيرة وأن يكون أداء خوارزميةٍ أخرى فعّالًا عند التعامل مع مشكلاتٍ كبيرة. وفي تلك الحالة، عادةً ما نُركِّز على المشكلات الكبيرة، لأن الاختلاف في الأداء لا يكون كبيرًا مع المشكلات الصغيرة، ولكنه يكون كذلك مع المشكلات الكبيرة.
	</li>
</ol>

<p>
	يقودنا هذا النوع من التحليل إلى تصنيف بسيط <a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA/" rel="">للخوارزميات</a>. على سبيل المثال، إذا كان زمن تشغيل خوارزمية A يتناسب مع حجم المدخلات n، وكان زمن تشغيل خوارزمية أخرى B يتناسب مع n<sup>2</sup>‎، فيُمكِننا أن نقول إن الخوارزمية A أسرع من الخوارزمية B لقيم n الكبيرة على الأقل.
</p>

<p>
	يُمكِن <a href="https://wiki.hsoub.com/Algorithms" rel="external">تصنيف غالبية الخوارزميات</a> البسيطة إلى إحدى التصنيفات التالية:
</p>

<ul>
	<li>
		ذات زمن ثابت: تكون الخوارزمية ثابتة الزمن إذا لم يعتمد زمن تشغيلها على حجم المدخلات. على سبيل المثال، إذا كان لدينا مصفوفةٌ مكوَّنةٌ من عدد n من العناصر، واستخدمنا العامل <code>[]</code> لقراءة أيٍّ من عناصرها، فإن ذلك يتطلَّب نفس عدد العمليات بغضّ النظر عن حجم المصفوفة.
	</li>
	<li>
		ذات زمن خطّي: تكون الخوارزمية خطيّةً إذا تناسب زمن تشغيلها مع حجم المدخلات. فإذا كنا نحسب حاصل مجموع العناصر الموجودة ضمن مصفوفة مثلًا، فعلينا أن نسترجع قيمة عدد n من العناصر، وأن نُنفِّذ عدد n-1 من عمليات الجمع، وبالتالي يكون العدد الكليّ للعمليات (الاسترجاع والجمع) هو 2‎*‎n-1، وهو عددٌ يتناسب مع n.
	</li>
	<li>
		ذات زمن تربيعي: تكون الخوارزمية خطيةً إذا تناسب زمن تشغيلها مع n<sup>2</sup>‎. على سبيل المثال، إذا كنا نريد أن نفحص ما إذا كان هنالك أيُّ عنصرٍ ضمن قائمةٍ معينةٍ مُكرَّرًا، فإن بإمكان خوارزميةٍ بسيطةٍ أن توازن كل عنصرٍ ضمن القائمة بجميع العناصر الأخرى، وذلك نظرًا لوجود عدد n من العناصر، والتي لا بُدّ من موازنة كُلٍّ منها مع عدد n-1 من العناصر الأخرى، يكون العدد الكليّ لعمليات الموازنة هو n<sup>2</sup>-n، وهو عددٌ يتناسب مع n<sup>2</sup>‎.
	</li>
</ul>

<h2>
	الترتيب الانتقائي Selection sort
</h2>

<p>
	تُنفِّذ الشيفرة المثال التالية خوارزميةً بسيطةً تُعرَف باسم <a href="https://ar.wikipedia.org/wiki/%D8%AA%D8%B1%D8%AA%D9%8A%D8%A8_%D8%A7%D9%86%D8%AA%D9%82%D8%A7%D8%A6%D9%8A" rel="external nofollow">الترتيب الانتقائي</a>:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9669_8" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">SelectionSort</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="com">/**
     * بدل العنصرين الموجودين بالفهرس‫ i والفهرس j
     */</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> swapElements</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> array</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> j</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> temp </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
        array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">j</span><span class="pun">];</span><span class="pln">
        array</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> temp</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="com">/**
     * ‫اعثر على فهرس أصغر عنصر بدءًا من الفهرس المُمرَّر 
     * عبر المعامل‫ index وحتى نهاية المصفوفة
     */</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> indexLowest</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> array</span><span class="pun">,</span><span class="pln"> </span><span class="typ">int</span><span class="pln"> start</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">int</span><span class="pln"> lowIndex </span><span class="pun">=</span><span class="pln"> start</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> start</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> array</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">array</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">lowIndex</span><span class="pun">])</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                lowIndex </span><span class="pun">=</span><span class="pln"> i</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> lowIndex</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="com">/**
     * رتب المصفوفة باستخدام خوارزمية الترتيب الانتقائي
     */</span><span class="pln">
    </span><span class="kwd">public</span><span class="pln"> </span><span class="kwd">static</span><span class="pln"> </span><span class="kwd">void</span><span class="pln"> selectionSort</span><span class="pun">(</span><span class="typ">int</span><span class="pun">[]</span><span class="pln"> array</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="typ">int</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> array</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="typ">int</span><span class="pln"> j </span><span class="pun">=</span><span class="pln"> indexLowest</span><span class="pun">(</span><span class="pln">array</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">);</span><span class="pln">
            swapElements</span><span class="pun">(</span><span class="pln">array</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> j</span><span class="pun">);</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يُبدِّل التابع الأول <code>swapElements</code> عنصرين ضمن المصفوفة، وتَستغرِق عمليتا قراءة العناصر وكتابتها زمنًا ثابتًا؛ لأننا لو عَرَفنا حجم العناصر وموضع العنصر الأول ضمن المصفوفة، فسيكون بإمكاننا حساب موضع أي عنصرٍ آخرَ باستخدام عمليتي ضربٍ وجمعٍ فقط، وكلتاهما من العمليات التي تَستغرِق زمنًا ثابتًا. ولمّا كانت جميع العمليات ضمن التابع <code>swapElements</code> تَستغرِق زمنًا ثابتًا، فإن التابع بالكامل يَستغرِق بدوره زمنًا ثابتًا.
</p>

<p>
	يبحثُ التابع الثاني <code>indexLowest</code> عن فهرسِ index أصغرِ عنصرٍ في المصفوفة بدءًا من فهرسٍ معينٍ يُخصِّصه المعامل <code>start</code>، ويقرأ كل تكرارٍ ضمن الحلقة التكراريّة عنصرين من المصفوفة ويُوازن بينهما، ونظرًا لأن كل تلك العمليات تستغرِق زمنًا ثابتًا، فلا يَهُمّ أيُها نَعُدّ. ونحن هنا بهدف التبسيط سنحسب عدد عمليات الموازنة:
</p>

<ol>
	<li>
		إذا كان <code>start</code> يُساوِي الصفر، فسيَمُرّ التابع <code>indexLowest</code> عبر المصفوفة بالكامل، وبالتالي يكون عدد عمليات الموازنة المُجراة مُساويًا لعدد عناصر المصفوفة، وليكن <code>n</code>.
	</li>
	<li>
		إذا كان <code>start</code> يُساوِي 1، فإن عدد عمليات الموازنة يُساوِي <code>n-1</code>.
	</li>
	<li>
		في العموم، يكون عدد عمليات الموازنة مساويًا لقيمة <code>n-start</code>، وبالتالي، يَستغرِق التابع <code>indexLowest</code> زمنًا خطّيًا.
	</li>
</ol>

<p>
	يُرتِّب التابع الثالث <code>selectionSort</code> المصفوفة. ويُنفِّذ التابع حلقة تكرار من 0 إلى n-1، أي يُنفذِّ الحلقة عدد n من المرات. وفي كل مرة يَستدعِي خلالها التابع <code>indexLowest</code>، ثم يُنفِّذ العملية <code>swapElements</code> التي تَستغرِق زمنًا ثابتًا.
</p>

<p>
	عند استدعاء التابع <code>indexLowest</code> لأوّلِ مرة، فإنه يُنفِّذ عددًا من عمليات الموازنة مقداره n، وعند استدعائه للمرة الثانية، فإنه يُنفِّذ عددًا من عمليات الموازنة مقداره n-1، وهكذا. وبالتالي سيكون العدد الإجمالي لعمليات الموازنة هو:
</p>

<pre class="ipsCode">n + n-1 + n-2 + ... + 1 + 0
</pre>

<p>
	يبلُغ مجموع تلك السلسلة مقدارًا يُساوِي n(n+1)/2، وهو مقدارٌ يتناسب مع n<sup>2</sup>‎، مما يَعنِي أن التابع <code>selectionSort</code> يقع تحت التصنيف التربيعي.
</p>

<p>
	يُمكِننا الوصول إلى نفس النتيجة بطريقة أخرى، وهي أن ننظر للتابع <code>indexLowest</code> كما لو كان حلقة تكرارٍ متداخلةً nested، ففي كل مرة نَستدعِي خلالها التابع <code>indexLowest</code>، فإنه يُنفِّذ مجموعةً من العمليات يكون عددها متناسبًا مع n، ونظرًا لأننا نَستدعيه عددًا من المرات مقداره n، فإن العدد الكليّ للعمليات يكون متناسبًا مع n<sup>2</sup>‎.
</p>

<h2>
	ترميز Big O
</h2>

<p>
	تنتمي جميع الخوارزميات التي تَستغرِق زمنًا ثابتًا إلى مجموعةٍ يُطلَق عليها اسم O(1)‎، فإذا قلنا إن خوارزميةً معينةً تنتمي إلى المجموعة O(1)‎، فهذا يعني ضمنيًّا أنها تستغرِق زمنًا ثابتًا. وعلى نفس المنوال، تنتمي جميع الخوارزميات الخطيّة -التي تستغرِق زمنًا خطيًا- إلى المجموعة O(n)‎، بينما تنتمي جميع الخوارزميات التربيعية إلى المجموعة O(n<sup>2</sup>‎)‎. تطلَق على تصنيف الخوارزميات بهذا الأسلوب تسمية ترميز Big O.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<bold>ملحوظة.</bold> لقد عرَّفنا هنا ترميز big O تعريفًا عارضًا، ولكن لو أردت التعمّق في الجزء الرياضيّ منه فبإمكانك الاطلاع على <a href="https://academy.hsoub.com/programming/advance/%D8%AA%D8%B1%D9%85%D9%8A%D8%B2-big-o-%D9%81%D9%8A-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1290/" rel="">ما هو ترميز Big O </a> .
	</p>
</blockquote>

<p>
	يُوفِّر هذا الترميز أسلوبًا سهلًا لكتابة القواعد العامة التي تسلُكها الخوارزميات في العموم. فلو نفَّذنا خوارزميةً خطيةً وتبعناها بخوارزميةٍ ثابتة الزمن على سبيل المثال، ، فإن زمن التشغيل الإجمالي يكون خطيًا. وننبّه هنا إلى أنّ ‎∈‎ تَعنِي "ينتمي إلى":
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9669_12" style=""><span class="typ">If</span><span class="pln"> f </span><span class="pun">∈</span><span class="pln"> O</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> g </span><span class="pun">∈</span><span class="pln"> O</span><span class="pun">(</span><span class="lit">1</span><span class="pun">),</span><span class="pln"> f</span><span class="pun">+</span><span class="pln">g </span><span class="pun">∈</span><span class="pln"> O</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span></pre>

<p>
	إذا أجرينا عمليتين خطيتين، فسيكون المجموع الإجمالي خطيًا:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9669_14" style=""><span class="typ">If</span><span class="pln"> f </span><span class="pun">∈</span><span class="pln"> O</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> g </span><span class="pun">∈</span><span class="pln"> O</span><span class="pun">(</span><span class="pln">n</span><span class="pun">),</span><span class="pln"> f</span><span class="pun">+</span><span class="pln">g </span><span class="pun">∈</span><span class="pln"> O</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span></pre>

<p>
	في الحقيقة، إذا أجرينا عمليةً خطيّةً أي عددٍ من المرات، وليكن k، فإن المجموع الإجمالي سيبقى خطيًا طالما أن k قيمة ثابتة لا تعتمد على n:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9669_16" style=""><span class="typ">If</span><span class="pln"> f </span><span class="pun">∈</span><span class="pln"> O</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> k is constant</span><span class="pun">,</span><span class="pln"> kf </span><span class="pun">∈</span><span class="pln"> O</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span></pre>

<p>
	في المقابل، إذا أجرينا عمليةً خطيةً عدد n من المرات، فستكون النتيجة تربيعيةً:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9669_20" style=""><span class="typ">If</span><span class="pln"> f </span><span class="pun">∈</span><span class="pln"> O</span><span class="pun">(</span><span class="pln">n</span><span class="pun">),</span><span class="pln"> nf </span><span class="pun">∈</span><span class="pln"> O</span><span class="pun">(</span><span class="pln">n</span><span class="pun">^</span><span class="lit">2</span><span class="pun">)</span></pre>

<p>
	وفي العموم، ما يهمنا هو أكبر أسٍّ للأساس n، فإذا كان العدد الكليّ للعمليات يُساوِي 2n+1، فإنه إجمالًا ينتمي إلى O(n)‎، ولا أهمية للثابت 2 ولا للقيمة المضافة 1 في هذا النوع من تحليل الخوارزميات. وبالمثل، ينتمي n<sup>2</sup>+100n+1000 إلى O( n<sup>2</sup>)‎. ولا أهمّية للأرقام الكبيرة التي تراها.
</p>

<p>
	يُعدّ ترتيب النمو Order of growth طريقةً أخرى للتعبير عن نفس الفكرة، ويشير ترتيبُ نموٍّ معين إلى مجموعة الخوارزميات التي ينتمي زمن تشغيلها إلى نفس تصنيف ترميز big O، حيث تنتمي جميع الخوارزميات الخطية مثلًا إلى نفس ترتيب النمو؛ وذلك لأن زمن تشغيلها ينتمي إلى المجموعة O(n)‎.
</p>

<p>
	ويُقصَد بكلمة "ترتيب" ضمن هذا السياق "مجموعة"، مثل اِستخدَامنا لتلك الكلمة في عبارةٍ مثل "ترتيب فرسان المائدة المستديرة". ويُقصَد بهذا أنهم مجموعة من الفرسان، وليس طريقة صفّهم أو ترتيبهم، أي يُمكِنك أن تنظر إلى ترتيب الخوارزميات الخطية وكأنها مجموعة من الخوارزميات التي تتمتّع بكفاءةٍ عالية.
</p>

<h2>
	تمرين 2
</h2>

<p>
	يشتمل التمرين التالي على تنفيذ الواجهة <code>List</code> باستخدام مصفوفةٍ لتخزين عناصر القائمة.
</p>

<p>
	ستجد الملفات التالية في مستودع الشيفرة الخاص بالكتاب -انظر القسم 0.1-:
</p>

<ul>
	<li>
		<code>MyArrayList.java</code> : يحتوي على تنفيذ جزئي للواجهة <code>List</code>، فهناك أربعةُ توابعَ غير مكتملة عليك أن تكمل كتابة شيفرتها.
	</li>
	<li>
		<code>MyArrayListTest.java</code>: يحتوي على مجموعة من اختبارات JUnit، والتي يُمكِنك أن تَستخدِمها للتحقق من صحة عملك.
	</li>
</ul>

<p>
	كما ستجد الملف <code>build.xml</code>. يُمكِنك أن تُنفِّذ الأمر <code>ant MyArrayList</code>؛ لكي تتمكَّن من تشغيل الصنف <code>MyArrayList.java</code> وأنت ما تزال في المجلد code الذي يحتوي على عدة اختباراتٍ بسيطة. ويُمكِنك بدلًا من ذلك أن تُنفِّذ الأمر <code>ant MyArrayListTest</code> لكي تُشغِّل اختباراتِ JUnit.
</p>

<p>
	عندما تُشغِّل تلك الاختبارات فسيفشل بعضها، والسبب هو وجود توابع ينبغي عليك إكمالها. إذا نظرت إلى الشيفرة، فستجد 4 تعليقات <code>TODO</code> تشير إلى هذه موضع كل من هذه التوابع.
</p>

<p>
	ولكن قبل أن تبدأ في إكمال تلك التوابع، دعنا نلق نظرةً سريعةً على بعض أجزاء الشيفرة. تحتوي الشيفرة التالية على تعريف الصنف ومتغيراتِ النُّسَخ instance variables وباني الصنف constructor:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9669_22" style=""><span class="kwd">public</span><span class="pln"> </span><span class="kwd">class</span><span class="pln"> </span><span class="typ">MyArrayList</span><span class="pun">&lt;</span><span class="pln">E</span><span class="pun">&gt;</span><span class="pln"> implements </span><span class="typ">List</span><span class="pun">&lt;</span><span class="pln">E</span><span class="pun">&gt;</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="typ">int</span><span class="pln"> size</span><span class="pun">;</span><span class="pln">                    </span><span class="com">// احتفظ بعدد العناصر</span><span class="pln">
    </span><span class="kwd">private</span><span class="pln"> E</span><span class="pun">[]</span><span class="pln"> array</span><span class="pun">;</span><span class="pln">           </span><span class="com">// خزِّن العناصر</span><span class="pln">

    </span><span class="kwd">public</span><span class="pln"> </span><span class="typ">MyArrayList</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        array </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">E</span><span class="pun">[])</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Object</span><span class="pun">[</span><span class="lit">10</span><span class="pun">];</span><span class="pln">
        size </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	يحتفظ المتغير <code>size</code> -كما يُوضِّح التعليق- بعدد العناصر التي يَحمِلها كائنٌ من النوع <code>MyArrayList</code>، بينما يُمثِل المتغير <code>array</code> المصفوفة التي تحتوي على تلك العناصر ذاتها.
</p>

<p>
	يُنشِئ الباني مصفوفةً مكوَّنةً من عشرة عناصر تَحمِل مبدئيًّا القيمة الفارغة <code>null</code>، كما يَضبُط قيمة المتغير <code>size</code> إلى 0. غالبًا ما يكون طول المصفوفة أكبر من قيمة المتغير <code>size</code>، مما يَعنِي وجود أماكنَ غير مُستخدَمةٍ في المصفوفة.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<bold>ملحوظة متعلقة بقواعد لغة جافا:</bold> لا يُمكِنك إنشاء مصفوفة باستخدام معامل نوع type parameter، وهكذا فالتعليمة التالية مثلًا لن تَعمَل:
	</p>
</blockquote>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_9669_24" style=""><span class="pln">        array </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> E</span><span class="pun">[</span><span class="lit">10</span><span class="pun">];</span></pre>

<p>
	لكي تتمكَّن من تخطِي تلك العقبة، عليك أن تُنشِئ مصفوفةً من النوع <code>Object</code>، ثم تُحوِّل نوعها typecast. يُمكِنك قراءة المزيد عن ذلك في <a href="http://thinkdast.com/generics" rel="external nofollow">ما المقصود بالأنواع المعمّمة (باللغة الإنجليزية)</a>.
</p>

<p>
	ولنُلقِ نظرةً الآن على التابع المسؤول عن إضافة العناصر إلى القائمة:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_9669_30" style=""><span class="pln">    public boolean add</span><span class="pun">(</span><span class="pln">E element</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">size </span><span class="pun">&gt;=</span><span class="pln"> array</span><span class="pun">.</span><span class="pln">length</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="pun">//</span><span class="pln"> </span><span class="pun">أنشئ</span><span class="pln"> </span><span class="pun">مصفوفة</span><span class="pln"> </span><span class="pun">أكبر</span><span class="pln"> </span><span class="pun">وانسخ</span><span class="pln"> </span><span class="pun">إليها</span><span class="pln"> </span><span class="pun">العناصر</span><span class="pln">
            E</span><span class="pun">[]</span><span class="pln"> bigger </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">E</span><span class="pun">[])</span><span class="pln"> new </span><span class="typ">Object</span><span class="pun">[</span><span class="pln">array</span><span class="pun">.</span><span class="pln">length </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pun">];</span><span class="pln">
            </span><span class="typ">System</span><span class="pun">.</span><span class="pln">arraycopy</span><span class="pun">(</span><span class="pln">array</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> bigger</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> array</span><span class="pun">.</span><span class="pln">length</span><span class="pun">);</span><span class="pln">
            array </span><span class="pun">=</span><span class="pln"> bigger</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln"> 
        array</span><span class="pun">[</span><span class="pln">size</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> element</span><span class="pun">;</span><span class="pln">
        size</span><span class="pun">++;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	في حالة عدم وجود المزيد من الأماكن الشاغرة في المصفوفة، سنضطّر إلى إنشاء مصفوفةٍ أكبر نَنسَخ إليها العناصر الموجودة سابقًا، وعندئذٍ سنتمكَّن من إضافة العنصر الجديد إلى تلك المصفوفة، مع زيادة قيمة المتغير <code>size</code>.
</p>

<p>
	يعيد ذلك التابع قيمةً من النوع <code>boolean</code>. قد لا يكون سبب ذلك واضحًا، فلربما تظن أنه سيعيد القيمة <code>true</code> دائمًا. قد لا تتضح لنا الكيفية التي ينبغي أن نُحلِّل أداء التابع على أساسها. في الأحوال العاديّة يستغرق التابع زمنًا ثابتًا، ولكنه في الحالات التي نضطّر خلالها إلى إعادة ضبط حجم المصفوفة سيستغرِق زمنًا خطيًا. وسنتطرّق إلى كيفية معالجة ذلك في جزئية لاحقة من هذه السلسلة.
</p>

<p>
	في الأخير، لنُلقِ نظرةً على التابع <code>get</code>، وبعدها يُمكِنك البدء في حل التمرين:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9669_35" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> T get</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> index</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">index </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">||</span><span class="pln"> index </span><span class="pun">&gt;=</span><span class="pln"> size</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">throw</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">IndexOutOfBoundsException</span><span class="pun">();</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> array</span><span class="pun">[</span><span class="pln">index</span><span class="pun">];</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	كما نرى، فالتابع <code>get</code> بسيطٌ للغاية ويعمل كما يلي: إذا كان الفهرس المطلوب خارج نطاق المصفوفة، فسيُبلِّغ التابع عن اعتراض exception؛ أما إذا ضمن نطاق المصفوفة، فإن التابع يسترجع عنصر المصفوفة ويعيده. لاحِظ أن التابع يَفحَص ما إذا كانت قيمة الفهرس أقل من قيمة <code>size</code> لا قيمة <code>array.length</code>، وبالتالي لا يعيد التابع قيم عناصر المصفوفة غير المُستخدَمة.
</p>

<p>
	ستجد التابع <code>set</code> في الملف <code>MyArrayList.java</code> على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_9669_37" style=""><span class="pln">    </span><span class="kwd">public</span><span class="pln"> T </span><span class="typ">set</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> index</span><span class="pun">,</span><span class="pln"> T element</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="com">// TODO: fill in this method.</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> null</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	اقرأ <a href="http://thinkdast.com/listset" rel="external nofollow">توثيق set باللغة الإنجليزية</a>، ثم أكمل متن التابع. لا بُدّ أن ينجح الاختبار <code>testSet</code> عندما تُشغِّل <code>MyArrayListTest</code> مرةً أخرى.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<bold>ملحوظة:</bold> تجنَّب تكرار الشيفرة المسؤولة عن فحص الفهرس.
	</p>
</blockquote>

<p>
	الخطوة التالية هي إكمال التابع <code>indexOf.</code> وقد وفَّرنا لك أيضًا التابع المساعد <code>equals</code> للموازنة بين قيمة عنصر ضمن المصفوفة وبين قيمة معينة أخرى. يعيد ذلك التابع القيمة <code>true</code> إذا كانت القيمتان متساويتين كما يُعالِج القيمة الفارغة null بشكل سليم. لاحِظ أن هذا التابع مُعرَّف باستخدام المُعدِّل <code>private</code>؛ لأنه ليس جزءًا من الواجهة <code>List</code>، ويُستخدَم فقط داخل الصنف.
</p>

<p>
	شغِّل الاختبار <code>MyArrayListTest</code> مرة أخرى عندما تنتهي، والآن ينبغي أن ينجح الاختبار <code>testIndexOf</code> وكذلك الاختبارات الأخرى التي تعتمد عليه.
</p>

<p>
	ما يزال هناك تابعان آخران عليك إكمالهما لكي تنتهي من التمرين، حيث أن التابع الأول هو عبارة عن بصمة أخرى من التابع <code>add</code>. تَستقبِل تلك البصمة فهرسًا وتُخزِّن فيه قيمةً جديدة. قد تضطّر أثناء ذلك إلى تحريك العناصر الأخرى لكي تُوفِّر مكانًا للعنصر الجديد.
</p>

<p>
	مثلما سبق، اقرأ <a href="http://thinkdast.com/listadd" rel="external nofollow">التوثيق باللغة الإنجليزية</a> أولًا ثم نفِّذ التابع، بعدها شغِّل الاختبارات لكي تتأكّد من أنك تنفيذك سليم.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p data-gramm="false">
		<bold>ملحوظة:</bold> تجنَّب تكرار الشيفرة المسؤولة عن زيادة/إعادة ضبط حجم المصفوفة.
	</p>
</blockquote>

<p>
	لننتقل الآن إلى التابع الأخير. أكمل متن التابع <code>remove</code> وعندما تنتهي من إكمال هذا التابع، فالمتوقع أن تنجح جميع الاختبارات. وبعد أن تُنهِي جميع التوابع وتتأكَّد من أنها تَعمَل بكفاءة، يُمكِنك الاطلاع على <a href="http://thinkdast.com/myarraylist" rel="external nofollow">الشيفرة</a>.
</p>

<p>
	ترجمة -بتصرّف- للفصل <a href="https://greenteapress.com/thinkdast/html/thinkdast003.html" rel="external nofollow">Chapter 2: Analysis of Algorithms</a> من كتاب <a href="https://greenteapress.com/thinkdast/html/index.html" rel="external nofollow">Think Data Structures: Algorithms and Information Retrieval in Java</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقال التالي: <a href="https://academy.hsoub.com/programming/advanced/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%B2%D9%85%D9%86-%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D9%82%D9%88%D8%A7%D8%A6%D9%85-%D8%A7%D9%84%D9%85%D9%86%D9%81%D8%B0%D8%A9-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D9%85%D8%B5%D9%81%D9%88%D9%81%D8%A9-r1348/" rel="">تحليل زمن تشغيل القوائم المنفذة باستخدام مصفوفة</a>
	</li>
	<li>
		المقال السابق: <a href="https://academy.hsoub.com/programming/java/%D8%B7%D8%B1%D9%8A%D9%82%D8%A9-%D8%B9%D9%85%D9%84-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D9%81%D9%8A-%D9%84%D8%BA%D8%A9-%D8%AC%D8%A7%D9%81%D8%A7-r1344/" rel="">طريقة عمل الواجهات في لغة جافا</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/java/%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7-r1313/" rel="">تحليل الخوارزميات في جافا</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advance/%D8%A7%D9%84%D8%B1%D8%B3%D9%88%D9%85-%D8%A7%D9%84%D8%AA%D8%AE%D8%B7%D9%8A%D8%B7%D9%8A%D8%A9-graphs-%D9%81%D9%8A-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1293/" rel="">الرسوم التخطيطية Graphs في الخوارزميات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advance/%D8%AA%D8%B9%D9%82%D9%8A%D8%AF-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-algorithms-complexity-r1284/" rel="">تعقيد الخوارزميات Algorithms Complexity</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advance/%D8%A7%D9%84%D8%A3%D8%B4%D8%AC%D8%A7%D8%B1-trees-%D9%81%D9%8A-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1292/" rel="">الأشجار Trees في الخوارزميات</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1345</guid><pubDate>Mon, 18 Oct 2021 15:05:00 +0000</pubDate></item><item><title>&#x62E;&#x648;&#x627;&#x631;&#x632;&#x645;&#x64A;&#x629; &#x62A;&#x62D;&#x62F;&#x64A;&#x62F; &#x627;&#x644;&#x645;&#x633;&#x627;&#x631; &#x627;&#x644;&#x646;&#x62C;&#x645;&#x64A;&#x629; A* Path&#xFB01;nding</title><link>https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-%D8%AA%D8%AD%D8%AF%D9%8A%D8%AF-%D8%A7%D9%84%D9%85%D8%B3%D8%A7%D8%B1-%D8%A7%D9%84%D9%86%D8%AC%D9%85%D9%8A%D8%A9-a-path%EF%AC%81nding-r1363/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/617bc71ae9638_-01.jpg.76c3253b5c2ea306a85c1b2698ff113d.jpg" /></p>

<p>
	خوارزمية البحث النجمي (*A) هي خوارزمية تهدف إلى تحديد أفضل مسار من عقدة إلى أخرى، لذا تشبه إلى حد ما خوارزميات البحث بالوسع أولًا Breadth First Search أو Dijkstra أو "البحث بالعمق أولًا Depth First Search" أو "خوارزمية البحث بالتخمين Best First Search".
</p>

<p>
	تتميّز خوارزمية البحث النجمي بكفاءة ودقة عالية خاصّة في الحالات التي يتعذّر فيها معالجة المخطط معالجة مُسبقة، وهي حالة خاصّة من خوارزمية البحث بالتخمين Best First Search، مع تعريف دالة التقييم f بطريقة معيّنة، إذ تساوي <code>f(n) = g(n) + h(n)‎‎</code> الكلفة الدنيا، حيث تمثّل<code>g (n)</code> ‎‎ التكلفة الدنيا من العقدة الأولية إلى n، فيما تمثّل <code>h (n)‎‎</code> الكلفة الدنيا من <code>n</code> إلى أقرب هدف من <code>n</code>.
</p>

<p>
	وتقوم خوارزمية *A على التخمين، وتضمن دائمًا العثور على أقصر مسار -المسار الذي له أقل تكلفة- في أقل وقت ممكن، لذلك فهي مثالية. يوضح الرسم البياني التالي آلية العمل لها‎‎:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="81200" href="https://academy.hsoub.com/uploads/monthly_2021_10/im.png.f4a51ef06c84fc1c49b24386f607fbc6.png" rel=""><img alt="im.png" class="ipsImage ipsImage_thumbnailed" data-fileid="81200" data-unique="pnal2jamr" src="https://academy.hsoub.com/uploads/monthly_2021_10/im.thumb.png.dd9fae74ea5170da4b1ed36fdfa3e773.png" style="width: 350px; height: auto;"></a>
</p>

<h3>
	خوارزمية البحث عن المسارات *A عبر متاهة لا تحتوي على عقبات
</h3>

<p>
	انظر الشبكة التالية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="81198" href="https://academy.hsoub.com/uploads/monthly_2021_10/9pe82.png.8b20a7bf6cf57a7d290d18e3db8cddd8.png" rel=""><img alt="9pe82.png" class="ipsImage ipsImage_thumbnailed" data-fileid="81198" data-unique="oxwadxjdj" src="https://academy.hsoub.com/uploads/monthly_2021_10/9pe82.thumb.png.3c5d666f5a47564c28532be93b33b23d.png" style="width: 350px; height: auto;"></a>
</p>

<p>
	لنفترض أنّ هذه متاهة، لاحظ أنّه لا توجد فيها أيّ جدران أو عوائق، وإنما لدينا نقطة انطلاقٍ -المربع الأخضر- ونقطة وصول ممثلة في المربع الأحمر. لنفترض أيضًا أنّه لا يمكننا التحرك قطريًا diagonally من أجل الانتقال من المربّع الأخضر إلى المربع الأحمر.
</p>

<p>
	يبيّن الرسم التالي المربعات التي يمكننا الانتقال إليها بدءًا من المربع الأخضر، والتي سنصبغُها باللون الأزرق.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="81206" href="https://academy.hsoub.com/uploads/monthly_2021_10/vDqkY.png.2e49bdcbf8336cd70e998b77c6d4a687.png" rel=""><img alt="vDqkY.png" class="ipsImage ipsImage_thumbnailed" data-fileid="81206" data-unique="ckvdl3kis" src="https://academy.hsoub.com/uploads/monthly_2021_10/vDqkY.png.2e49bdcbf8336cd70e998b77c6d4a687.png" style="width: 350px; height: auto;"></a>
</p>

<p>
	من أجل اختيار المربع التالي، نحتاج إلى مراعاة بعض المقاييس، وهي الآتية:
</p>

<ul>
<li>
		<strong>قيمة g</strong> - تمثّل بُعد هذه العقدة عن المربع الأخضر.
	</li>
	<li>
		<strong>قيمة h</strong> - تمثّل بُعد هذه العقدة عن المربع الأحمر.
	</li>
	<li>
		<strong>قيمة f</strong> - تساوي مجموع قيمتي g وh. هذا هو العدد النهائي الذي سنستعين به لتحديد العقدة التي ينبغي أن ننتقل إليها.
	</li>
</ul>
<p>
	لحساب هذه القيم، سنستخدم هذه الصيغة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_3459_17" style="">
<span class="pln">distance </span><span class="pun">=</span><span class="pln"> abs</span><span class="pun">(</span><span class="kwd">from</span><span class="pun">.</span><span class="pln">x </span><span class="pun">-</span><span class="pln"> to</span><span class="pun">.</span><span class="pln">x</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> abs</span><span class="pun">(</span><span class="kwd">from</span><span class="pun">.</span><span class="pln">y </span><span class="pun">-</span><span class="pln"> to</span><span class="pun">.</span><span class="pln">y</span><span class="pun">)</span></pre>

<p>
	تُعرَف هذه الصيغة بصيغة مسافة مانهاتن Manhattan Distance formula، حيث نستخدم الصيغة أعلاه لحساب قيمة g الخاصّة بالمربع الأزرق الموجود على يسار المربع الأخضر: <code>‎abs(3 - 2) + abs(2 -‎ 2 ‎) = 1‎</code>، ونحصل على القيمة 1. سنحاول الآن حساب قيمة h بنفس الصيغة: <code>‎abs(2 - ‎ 0) + abs (2 - 0) = 4</code>. قيمة f تساوي <code>‎1 + 4 = 5‎</code>، لذا فإنّ القيمة النهائية لهذه العقدة تساوي 5.
</p>

<p>
	علينا فعل نفس الأمر مع جميع المربعات الزرقاء الأخرى. يمثّل الرقم الكبير في وسط المربعات في الرسم أدناه قيمة f، بينما يمثّل العدد الموجود أعلى اليسار قيمة g، ويمثّل العدد الموجود أعلى اليمين قيمة h.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="81204" href="https://academy.hsoub.com/uploads/monthly_2021_10/RoGbr.png.c3419e7f9b58897e3434edec99e5c441.png" rel=""><img alt="RoGbr.png" class="ipsImage ipsImage_thumbnailed" data-fileid="81204" data-unique="ei5bn6zn9" src="https://academy.hsoub.com/uploads/monthly_2021_10/RoGbr.png.c3419e7f9b58897e3434edec99e5c441.png" style="width: 350px; height: auto;"></a>
</p>

<p>
	لقد حسبنا قيم g وh وf الخاصّة بجميع العُقد الزرقاء. الآن، أيّها نختار؟ سنختار العقدة التي لها أصغر قيمة لـ f.
</p>

<p>
	لدينا في هذه الحالة عقدتان لهما نفس قيمة f (هذه القيمة تساوي 5)، كيف نختار من بينهما؟ إمّا أن تختار إحداهما عشوائيًا، أو تضع قواعد للأولويات.
</p>

<p>
	فمثلا، يمكن أن تحدّد قاعدة للأولويات من قبيل: <strong>أيمن &gt; أسفل &gt; أيسر &gt; أعلى</strong>. لو طبّقنا هذه القاعدة على مثالنا، فإنّ إحدى العقدتين التي تساوي قيمة f الخاصة بها 5 تذهب إلى أسفل، وتذهب الأخرى إلى اليسار. وبما أن أولوية الاتجاه الأسفل أكبر من أولوية اليسار (أسفل&gt;أيسر)، فسنختار المربع الذي يأخذنا إلى أسفل.
</p>

<p>
	سنلوّن المربعات التي حسبنا قيمها دون أن نتحرّك إليها باللون البرتقالي، ونلوّن العقدة التي اخترناها باللون الأزرق السماوي:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="81199" href="https://academy.hsoub.com/uploads/monthly_2021_10/Dunrn.png.41857ce10e55f89060f0daa11635cd35.png" rel=""><img alt="Dunrn.png" class="ipsImage ipsImage_thumbnailed" data-fileid="81199" data-unique="bwd1bloj1" src="https://academy.hsoub.com/uploads/monthly_2021_10/Dunrn.png.41857ce10e55f89060f0daa11635cd35.png" style="width: 350px; height: auto;"></a>
</p>

<p>
	سنحسب الآن نفس المقاييس التي حسبناها من قبل للعقد المحيطة بالعقدة ذات اللون الأزرق السماوي (التي اخترناها سابقًا):
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="81207" href="https://academy.hsoub.com/uploads/monthly_2021_10/WuCwv.png.ee4a2c85d726a330f417f54a1d27db47.png" rel=""><img alt="WuCwv.png" class="ipsImage ipsImage_thumbnailed" data-fileid="81207" data-unique="ryru5vzig" src="https://academy.hsoub.com/uploads/monthly_2021_10/WuCwv.png.ee4a2c85d726a330f417f54a1d27db47.png" style="width: 350px; height: auto;"></a>
</p>

<p>
	سنختار العقدة الموجودة أسفل العقدة السماوية، ذلك أنّ جميع الخيارات لها نفس قيمة f:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="81202" href="https://academy.hsoub.com/uploads/monthly_2021_10/nlywy.png.a3cd9d5578a1e43fb51ed8184741ee68.png" rel=""><img alt="nlywy.png" class="ipsImage ipsImage_thumbnailed" data-fileid="81202" data-unique="bc74d0e9h" src="https://academy.hsoub.com/uploads/monthly_2021_10/nlywy.png.a3cd9d5578a1e43fb51ed8184741ee68.png" style="width: 350px; height: auto;"></a>
</p>

<p>
	لنحسب الآن مقاييس الجار الوحيد للعقدة السماوية:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="81196" href="https://academy.hsoub.com/uploads/monthly_2021_10/2rf8P.png.2d3cdcaf6c578d695433b9e8cbd83e50.png" rel=""><img alt="2rf8P.png" class="ipsImage ipsImage_thumbnailed" data-fileid="81196" data-unique="1z38miu7y" src="https://academy.hsoub.com/uploads/monthly_2021_10/2rf8P.png.2d3cdcaf6c578d695433b9e8cbd83e50.png" style="width: 350px; height: auto;"></a>
</p>

<p>
	نتّبع نفس النمط الذي اتبعناه من قبل:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="81197" href="https://academy.hsoub.com/uploads/monthly_2021_10/8UBoB.png.98dfc534deadf49c977b8deddc166268.png" rel=""><img alt="8UBoB.png" class="ipsImage ipsImage_thumbnailed" data-fileid="81197" data-unique="7xqvrjjrr" src="https://academy.hsoub.com/uploads/monthly_2021_10/8UBoB.png.98dfc534deadf49c977b8deddc166268.png" style="width: 350px; height: auto;"></a>
</p>

<p>
	سنحسب مرّةً أخرى مقاييس جار العقدة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="81205" href="https://academy.hsoub.com/uploads/monthly_2021_10/TuXrO.png.cadb13b2839cbb7d4e7130acf00e9ac1.png" rel=""><img alt="TuXrO.png" class="ipsImage ipsImage_thumbnailed" data-fileid="81205" data-unique="7902lc74k" src="https://academy.hsoub.com/uploads/monthly_2021_10/TuXrO.png.cadb13b2839cbb7d4e7130acf00e9ac1.png" style="width: 350px; height: auto;"></a>
</p>

<p>
	دعنا ننتقل إلى هناك:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="81203" href="https://academy.hsoub.com/uploads/monthly_2021_10/r8MJd.png.a66379726cf7f81ba3255259b9210b21.png" rel=""><img alt="r8MJd.png" class="ipsImage ipsImage_thumbnailed" data-fileid="81203" data-unique="6rcz3x57i" src="https://academy.hsoub.com/uploads/monthly_2021_10/r8MJd.png.a66379726cf7f81ba3255259b9210b21.png" style="width: 350px; height: auto;"></a>
</p>

<p>
	أخيرًا وصلنا إلى المربع المنشود، وأنهينا المهمّة.
</p>

<h2>
	حل لغز باستخدام خوارزمية البحث النجمي *A
</h2>

<p>
	لغز الثمانية 8 puzzle هي لعبة بسيطة تُلعب على شبكة تحتوي 9 مربعات (3 × 3). إحدى هذه المربعات فارغة، والهدف هو نقل المربعات إلى أن تتصافّ الأرقام وفق الترتيب المُراد.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="81201" href="https://academy.hsoub.com/uploads/monthly_2021_10/M2n1h.png.12e3061c14263eb35ba2ea83f371fac7.png" rel=""><img alt="M2n1h.png" class="ipsImage ipsImage_thumbnailed" data-fileid="81201" data-unique="jd7km6aqi" src="https://academy.hsoub.com/uploads/monthly_2021_10/M2n1h.png.12e3061c14263eb35ba2ea83f371fac7.png"></a>
</p>

<p>
	تريد هذه اللعبة البحث عن المسار الأقل كلفة، والذي ينطلق من حالة أولية للعبة ألغاز الثمانية، ويصل إلى الحالة المنشودة.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		اقتباس
	</div>

	<p>
		مثلا: لتكن هذه هي الحالة الأولية التي سنبدأ منها.
	</p>
</blockquote>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3459_19" style="">
<span class="pln">_ </span><span class="lit">1</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="lit">7</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="lit">6</span></pre>

<p>
	وهذه هي الحالة النهائية التي نريد الوصول إليها:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3459_21" style="">
<span class="lit">1</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
</span><span class="lit">7</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> _</span></pre>

<p>
	لنحسب مسافة مانهاتن بين الحالة الحالية والحالة النهائية.
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3459_23" style="">
<span class="pln">h</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> x </span><span class="pun">-</span><span class="pln"> p </span><span class="pun">|</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> y </span><span class="pun">-</span><span class="pln"> q </span><span class="pun">|</span></pre>

<p>
	x وy يمثّلان إحداثيات co-ordinates الحالة الراهنة، فيما تمثّل p وq إحداثيات الحالة النهائية.
</p>

<p>
	تحقّق دالة التكلفة الإجمالية <code>‎f(n)‎</code> الشرط التالي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3459_25" style="">
<span class="pln">f</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> g</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> h</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span></pre>

<p>
	حيث تمثّل g كلفة الوصول إلى الحالة الراهنة انطلاقًا من حالة أولية معيّنة، ولحل المشكلة سنحسب أولًا مسافة مانهاتن المطلوبة للوصول إلى الحالة النهائية انطلاقًا من الحالة الأولية. ستساوي دالة التكلفة <code>g (n) = 0</code>، لأنّنا ما نزال عند الحالة الأولية:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_3459_27" style="">
<span class="pln">h</span><span class="pun">(</span><span class="pln">n</span><span class="pun">)</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">8</span></pre>

<p>
	لو نظرت إلى الحالة الأولية ستلاحظ أنّ 1 موجود على بعد مربّع واحد على يمين المكان الذي يُفترض أن يكون فيه عند الوصول إلى الحالة المنشودة، وينطبق الأمر ذاته على <code>‎2‎</code> و<code>‎5‎</code> و<code>‎6‎</code>. توجد <code>‎_‎</code> على مسافة مربعين أُفقيين ومربّعين عموديين، لذا فإن القيمة الإجمالية لـ <code>‎h(n)‎</code> هي 1 + 1 + 1 + 1 + 2 + 2 = 8، بينما تساوي دالة التكلفة الإجمالية <code>‎f(n)‎</code> القيمة 8 + 0 = 8.
</p>

<p>
	والآن نكون قد عثرنا على الحالات المحتملة التي يمكن الوصول إليها انطلاقًا من الحالة الأولية، كما أنّه لا يمكننا تحريك <code>‎_‎</code> إلّا إلى اليمين أو إلى الأسفل، لذا فإنّ الحالات التي يمكن الوصول إليها بعد التحريك هي:
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5699_12" style="">
<span class="lit">1</span><span class="pln"> _ </span><span class="lit">3</span><span class="pln">    </span><span class="lit">4</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">5</span><span class="pln">    _ </span><span class="lit">2</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="lit">7</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="lit">6</span><span class="pln">    </span><span class="lit">7</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
 </span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">      </span><span class="pun">(</span><span class="lit">2</span><span class="pun">)</span></pre>

<p>
	مرّةً أخرى، سنحسب دالة التكلفة الإجمالية لهذه الحالات كما فعلنا أعلاه، وسنجد أنها تساوي 6 و7 على التوالي. لقد اخترنا الحالة ذات التكلفة الأقل، وهي الحالة (1).
</p>

<p>
	النقلة المحتملة التالية يمكن أن تكون إمّا يسارًا أو يمينًا أو لأسفل. لن ننتقل إلى اليسار لأنّنا كنّا هناك سابقًا، لذا بقي لنا التحرك يمينًا أو إلى أسفل.
</p>

<p>
	ومرّةً أخرى، وجدنا الحالات التي يمكن الوصول إليها من (1).
</p>

<pre class="ipsCode prettyprint lang-c prettyprinted" id="ips_uid_5699_10" style="">
<span class="lit">1</span><span class="pln"> </span><span class="lit">3</span><span class="pln"> _    </span><span class="lit">1</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
</span><span class="lit">4</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">5</span><span class="pln">    </span><span class="lit">4</span><span class="pln"> _ </span><span class="lit">5</span><span class="pln">
</span><span class="lit">7</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="lit">6</span><span class="pln">    </span><span class="lit">7</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="lit">6</span><span class="pln">
 </span><span class="pun">(</span><span class="lit">3</span><span class="pun">)</span><span class="pln">      </span><span class="pun">(</span><span class="lit">4</span><span class="pun">)</span></pre>

<p>
	دالة تكلفة (3) تساوي 6، فيما تساوي دالة تكلفة (4) القيمة 4. خذ بالحسبان أيضًا (2) التي حصلنا عليها من قبل، والتي تساوي دالة تكلفتها 7، وهنا سنختار الحالة (4) لأن لها أقل تكلفة. يمكن أن تكون النقلات المحتملة التالية إمّا يسارًا أو يمينًا أو لأسفل.
</p>

<p>
	سنحصل على الحالات التالية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5699_8" style="">
<span class="lit">1</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">3</span><span class="pln">    </span><span class="lit">1</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">3</span><span class="pln">    </span><span class="lit">1</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">3</span><span class="pln">
_ </span><span class="lit">4</span><span class="pln"> </span><span class="lit">5</span><span class="pln">    </span><span class="lit">4</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> _    </span><span class="lit">4</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="lit">5</span><span class="pln">
</span><span class="lit">7</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="lit">6</span><span class="pln">    </span><span class="lit">7</span><span class="pln"> </span><span class="lit">8</span><span class="pln"> </span><span class="lit">6</span><span class="pln">    </span><span class="lit">7</span><span class="pln"> _ </span><span class="lit">6</span><span class="pln">
 </span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span><span class="pln">      </span><span class="pun">(</span><span class="lit">6</span><span class="pun">)</span><span class="pln">      </span><span class="pun">(</span><span class="lit">7</span><span class="pun">)</span></pre>

<p>
	تكاليف الحالات (5) و(6) و(7) تساوي 5 و2 و4 على الترتيب، كذلك لدينا حالتان سابقتان (3) و(2) ذواتا تكلفتين 6 و7 على الترتيب، لكننا سنختار الحالة (6) ذات التكلفة الأقل. يمكن أن تكون التحركات المحتملة التالية إما إلى أعلى أو أسفل، ولا يحتاج الأمر إلى تفكير طويل، إذ سيقودنا النزول إلى أسفل إلى الحالة النهائية، وهذا سيجعل مسافة مانهاتن تساوي 0.
</p>

<p>
	ترجمة -بتصرّف- للفصلين 13 و 12 من كتاب <a href="https://goalkicker.com/AlgorithmsBook/" rel="external nofollow">Algorithms Notes for Professionals</a>.
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
<li>
		المقالة السابقة: <a href="http://xn--https-cdhh4euc/academy.hsoub.com/programming/advance/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-%D8%AF%D9%8A%D9%83%D8%B3%D8%AA%D8%B1%D8%A7-dijkstra%E2%80%99s-algorithm-r1336/" rel="external nofollow">خوارزمية ديكسترا Dijkstra’s Algorithm</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advance/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1282/" rel="">مدخل إلى الخوارزميات</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advance/%D8%AF%D9%84%D9%8A%D9%84-%D8%B4%D8%A7%D9%85%D9%84-%D8%B9%D9%86-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%AA%D8%B9%D9%82%D9%8A%D8%AF-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-r1247/" rel="">دليل شامل عن تحليل تعقيد الخوارزمية</a>
	</li>
</ul>
]]></description><guid isPermaLink="false">1363</guid><pubDate>Wed, 13 Oct 2021 15:00:00 +0000</pubDate></item><item><title>&#x62E;&#x648;&#x627;&#x631;&#x632;&#x645;&#x64A;&#x629; &#x62F;&#x64A;&#x643;&#x633;&#x62A;&#x631;&#x627; Dijkstra&#x2019;s Algorithm</title><link>https://academy.hsoub.com/programming/advanced/%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-%D8%AF%D9%8A%D9%83%D8%B3%D8%AA%D8%B1%D8%A7-dijkstra%E2%80%99s-algorithm-r1336/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2021_10/615ec782ae487_DijkstrasAlgorithm-01-01.jpg.fbd430216a5dd985190b6dcce382c784.jpg" /></p>
<p>
	تُعرف خوارزمية ديكسترا بخوارزمية أقصر مسار أحادي المصدر single-source shortest path algorithm، وتُستخدم للعثور على أقصر المسارات بين العقد في مخطط، وقد ابتُكرت هذه الخوارزمية على يد إدجستر ديكسترا Edsger W. Dijkstra -النطق من الهولندية- عام 1956، ونُشِرت بعدها بثلاث سنوات.
</p>

<p>
	يمكننا العثور على أقصر مسار باستخدام خوارزمية البحث بالوُسع أو العرض أولًا Breadth First Search اختصارًا BFS. وتعمل هذه الخوارزمية جيدًا لكنّها محدودة، إذ تفترض أنّ تكلفة cost اجتياز كل مسار لا تتغيّر، أي أنّ أوزان جميع الأضلاع متساوية. تساعدنا خوارزمية ديكسترا على العثور على أقصر مسار حتى لو كانت تكاليف المسارات مختلفة.
</p>

<p>
	سنتعلّم في البداية كيفية تعديل خوارزمية BFS لكتابة خوارزمية Dijkstra، ثم سنضيف طابور الأولويات priority queue لجعلها خوارزمية Dijkstra كاملة.
</p>

<p>
	لنفترض أنّ المسافة بين كل عقدة وبين المصدر مُخزّنة في مصفوفة <code>d[]‎‎</code>، حيث تمثّل <code>d[3]‎‎</code> مثلًا الوقت اللازم للوصول إلى العقدة 3 من المصدر، وإذا لم نعرف المسافة فسنضع قيمة ما لا نهاية inﬁnity في <code>d[3]‎‎</code>. لنفترض أن <code>cost</code> مصفوفة تخزّن التكاليف، بحيث تحتوي <code>cost[‎u][v]‎‎</code> على كلفة مجموع أوزان الأضلاع التي تؤلف المسار <code>u-v</code>، أي أنّ الانتقال من العقدة <code>u</code> إلى العقدة <code>v</code> يتطلب تكلفة <code>cost[‎u][v]‎‎</code>.
</p>

<p style="text-align: center;">
	<img alt="R6Tva.png" class="ipsImage ipsImage_thumbnailed" data-fileid="79069" data-unique="4e8ggsn6o" src="https://academy.hsoub.com/uploads/monthly_2021_10/R6Tva.png.adda5df3f5342294d981fe52e42c1619.png">
</p>

<p>
	قبل أن نواصل، سنوضّح مفهوم تخفيف الضلع Edge Relaxation.
</p>

<p>
	لنفترض أنّك تحتاج 10 دقائق للانتقال من منزلك (المصدر) إلى المكان A، بينما يستغرق الانتقال إلى المكان B حوالي 25 دقيقة. سيكون لدينا إذًا الآتي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_104_6" style=""><span class="pln">d</span><span class="pun">[</span><span class="pln">A</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">10</span><span class="pln">
d</span><span class="pun">[</span><span class="pln">B</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">25</span></pre>

<p>
	لنفترض الآن أنّك تحتاج 7 دقائق للانتقال من A إلى B، هذا يعني أنّ:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_104_8" style=""><span class="pln">cost</span><span class="pun">[</span><span class="pln">A</span><span class="pun">][</span><span class="pln">B</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">7</span></pre>

<p>
	يمكننا الذهاب إلى B عبر الانتقال من المصدر (منزلك) إلى A، ثمّ من A إلى B، وسيستغرق هذا 10 + 7 = 17 دقيقة بدلًا من 25 دقيقة:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_104_12" style=""><span class="pln">d[A] + cost[A][B] &lt; d[B]</span></pre>

<p>
	نحدّث الجدول على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_104_17" style=""><span class="pln">d</span><span class="pun">[</span><span class="pln">B</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> d</span><span class="pun">[</span><span class="pln">A</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">A</span><span class="pun">][</span><span class="pln">B</span><span class="pun">]</span></pre>

<p>
	يسمّى هذا تخفيفًا relaxation، إذ نذهب من u إلى v، فإذا وجدنا أنّ <code>&lt; d[‎u] + cost[‎u][v] &lt; d[v]‎‎</code>، فسنحدّث المصفوفة بالقيمة <code>d[v] = d[‎u] + cost[‎u][v]‎‎</code>.
</p>

<p>
	لم نكن بحاجة إلى زيارة أيّ عقدة مرتين في خوارزمية البحث بالوُسع أولًا BFS، فقد اكتفينا بالتحقّق ممّا إذا تمّت زيارة العقدة أم لا، فإن لم تُزَر، فسنضع العقدة في الطابور ثمّ نحددها على أنّها "تمت زيارتها"، بعدها نزيد المسافة بمقدار 1؛ أما في خوارزمية Dijkstra، فإننا نضع العقدة في الطابور، لكن بدلًا من تحديثها وتحديدها على أنّها مُزارة، فسنخفّف الضلع الجديد relax أو نحدّثه.
</p>

<p>
	انظر المثال التالي:
</p>

<p style="text-align: center;">
	<img alt="aQ4Nc.png" class="ipsImage ipsImage_thumbnailed" data-fileid="79068" data-unique="42m537ema" src="https://academy.hsoub.com/uploads/monthly_2021_10/aQ4Nc.png.3fb173c37df71f6d905444c69be6e660.png">
</p>

<p>
	لنفترض أنّ العقدة 1 هي المصدر، إذًا:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_104_19" style=""><span class="pln">d[1] = 0
d[2] = d[3] = d[4] = infinity (or a large value)</span></pre>

<p>
	لقد عيّنا قيم <code>d [2]‎‎</code> و<code>d [3]‎‎</code> و<code>d [4]‎‎</code> إلى ما لا نهاية لأنّنا لا نعرف المسافة بعد،‎‎‎‎ أمّا مسافة المصدر فتُساوي 0 بالطبع. سننتقل الآن إلى العُقد الأخرى انطلاقًا من المصدر، وإذا كانت هناك حاجة لتحديثها فسنضيفها إلى الطابور. لنقل على سبيل المثال أنّنا سنجتاز الضلع 1-2، وبما أن <code>d[1] + 2 &lt; d[2]‎‎</code>، فسنضع <code>d[2] = 2</code>، وبالمثل نجتاز الضلع 1-3، وتبعًا لذلك نكتب <code>d [3] = 5</code>.
</p>

<p>
	يمكن أن ترى بوضوح أنّ 5 ليست أقصر مسافة يمكننا عبورها للذهاب إلى العقدة 3، لذا فإنّ اجتياز العقدة مرّةً واحدةً فقط كما في خوارزمية BFS، ليس صالحًا هنا. ويمكننا إضافة التحديث d [3] = d [2] + 1 = 3 إذا انتقلنا من العقدة 2 إلى العقدة 3 باستخدام الضلع 2-3. وكما ترى، فمن الممكن تحديث العقدة الواحدة عدّة مرات.
</p>

<p>
	قد تسأل عن عدد المرات التي يمكن أن نفعل فيها ذلك، والإجابة هنا هي أن الحد الأقصى لعدد مرات تحديث العقدة هو الدرجة الداخلية in-degree لتلك العقدة.
</p>

<p>
	فيما يلي شيفرة عامّة لزيارة أيّ عقدة عدّة مرات، هذه الشيفرة هي تعديل لخوارزمية BFS:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_104_21" style=""><span class="pln">procedure </span><span class="typ">BFSmodified</span><span class="pun">(</span><span class="pln">G</span><span class="pun">,</span><span class="pln"> source</span><span class="pun">):</span><span class="pln">
Q </span><span class="pun">=</span><span class="pln"> queue</span><span class="pun">()</span><span class="pln">
distance</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> infinity
Q</span><span class="pun">.</span><span class="pln">enqueue</span><span class="pun">(</span><span class="pln">source</span><span class="pun">)</span><span class="pln">
distance</span><span class="pun">[</span><span class="pln">source</span><span class="pun">]=</span><span class="lit">0</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> Q is </span><span class="kwd">not</span><span class="pln"> empty
    u </span><span class="pun">&lt;-</span><span class="pln"> Q</span><span class="pun">.</span><span class="pln">pop</span><span class="pun">()</span><span class="pln">
   </span><span class="kwd">for</span><span class="pln"> all edges from u to v </span><span class="kwd">in</span><span class="pln"> G</span><span class="pun">.</span><span class="pln">adjacentEdges</span><span class="pun">(</span><span class="pln">v</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
        </span><span class="kwd">if</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln">
            distance</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span><span class="pln">
        </span><span class="kwd">end</span><span class="pln"> </span><span class="kwd">if</span><span class="pln">
  </span><span class="kwd">end</span><span class="pln"> </span><span class="kwd">for</span><span class="pln">
</span><span class="kwd">end</span><span class="pln"> </span><span class="kwd">while</span><span class="pln">
</span><span class="typ">Return</span><span class="pln"> distance</span></pre>

<p>
	يمكن استخدام هذا للعثور على أقصر مسار إلى جميع العقدة انطلاقًا من المصدر، ولا يُعد تعقيد هذه الشيفرة جيدًا، ذلك أننا في خوارزمية BFS نتبّع طريقة أوّل من يأتي هو أوّل من يُخدم "ﬁrst come, ﬁrst serve" عندما تنتقل من العقدة 1 إلى أي عقدة أخرى.
</p>

<p>
	فمثلًا، نحن ذهبنا إلى العقدة 3 من المصدر قبل معالجة العقدة 2، وعليه سنحدّث العقدة 4 إذا ذهبنا إلى العقدة 3 من المصدر، وذلك لأنّ 5 + 3 = 8. وعندما نحدّث العقدة 3 مرّةً أخرى من العقدة 2، فسيكون علينا تحديث العقدة 4 بالقيمة 3 + 3 = 6 مرّةً أخرى، وعليه تكون العقدة 4 قد حُدِّثَت مرتين.
</p>

<p>
	وقد اقترح Dijkstra طريقة أخرى بدلًا من طريقة أوّل من يأتي أوّل من يُخدَم، فإذا حدّثنا العُقَد الأقرب أولًا سنستطيع إجراء عدد أقل من التحديثات، وإذا كنا قد عالجنا العقدة 2 من قبل، فإنّ العقدة 3 ستكون قد حُدِّثت كذلك من قبل، وسنحصل على أقصر مسافة بسهولة بعد تحديث العقدة 4 وفقًا لذلك.
</p>

<p>
	الفكرة هنا هي أن نختار أقرب عقدة إلى المصدر من الطابور، لذلك سنستخدم طابور أولويات Priority Queue، وعندما ننزع عنصرًا من الطابور، سنحصل على أقرب عقدة <code>u</code> من المصدر عبر التحقق من قيمة <code>d[‎u]‎‎</code>.
</p>

<p>
	انظر الشيفرة التوضيحية التالية:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_104_23" style=""><span class="pln">procedure dijkstra</span><span class="pun">(</span><span class="pln">G</span><span class="pun">,</span><span class="pln"> source</span><span class="pun">):</span><span class="pln">
Q </span><span class="pun">=</span><span class="pln"> priority_queue</span><span class="pun">()</span><span class="pln">
distance</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> infinity
Q</span><span class="pun">.</span><span class="pln">enqueue</span><span class="pun">(</span><span class="pln">source</span><span class="pun">)</span><span class="pln">
distance</span><span class="pun">[</span><span class="pln">source</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pln">
</span><span class="kwd">while</span><span class="pln"> Q is </span><span class="kwd">not</span><span class="pln"> empty
    u </span><span class="pun">&lt;-</span><span class="pln"> nodes </span><span class="kwd">in</span><span class="pln"> Q with minimum distance</span><span class="pun">[]</span><span class="pln">
    remove u from the Q
   </span><span class="kwd">for</span><span class="pln"> all edges from u to v </span><span class="kwd">in</span><span class="pln"> G</span><span class="pun">.</span><span class="pln">adjacentEdges</span><span class="pun">(</span><span class="pln">v</span><span class="pun">)</span><span class="pln"> </span><span class="kwd">do</span><span class="pln">
         </span><span class="kwd">if</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln">
            distance</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> distance</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> cost</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span><span class="pln">
            Q</span><span class="pun">.</span><span class="pln">enqueue</span><span class="pun">(</span><span class="pln">v</span><span class="pun">)</span><span class="pln">
        </span><span class="kwd">end</span><span class="pln"> </span><span class="kwd">if</span><span class="pln">
    </span><span class="kwd">end</span><span class="pln"> </span><span class="kwd">for</span><span class="pln">
</span><span class="kwd">end</span><span class="pln"> </span><span class="kwd">while</span><span class="pln">
</span><span class="typ">Return</span><span class="pln"> distance</span></pre>

<p>
	تعيد الشيفرة التوضيحية مسافةَ جميعِ العقد الأخرى من المصدر، فإذا أردنا معرفة مسافة عقدة <code>v</code>، فيمكننا ببساطة إعادة القيمة الناتجة عن أخذ <code>v</code> من الطابور.
</p>

<p>
	السؤال الآن هو: هل تعمل خوارزمية ديكسترا حال وجود ضلع سالب negative edge؟ إذا كانت هناك دورة سالبة فستحدث حلقة لا نهائية، وذلك لأنها ستستمر في تخفيض التكلفة إلى الأبد، ولن تعمل خوارزمية ديكسترا حتى لو كان لدينا ضلع سالب إلا إذا عدنا مباشرةً بعد أخذ الهدف من الطابور، لكن لن تكون الخوارزمية حينئذ خوارزميةَ Dijkstra، وسنحتاج إلى خوارزمية بيلمن فورد Bellman-Ford لمعالجة الأضلاع أو الدورات السالبة.
</p>

<p>
	يتساوى تعقيد خوارزمية BFS مع <code>O(log(V+E))‎‎</code>، حيث يمثّل <code>V</code> عدد العقد، ويمثّل <code>E</code> عدد الأضلاع، والتعقيد مقارب لهذه القيمة فيما يخصّ خوارزمية Dijkstra، لكنّ ترتيب طابور الأولويات يأخذ <code>O (logV)‎‎</code>، لذا فإنّ التعقيد الكلي يساوي: <code>O (V log (V) + E‎‎)‎‎</code>.
</p>

<p>
	المثال أدناه هو تطبيق بلغة جافا لخوارزمية Dijkstra باستخدام مصفوفة التجاور:
</p>

<pre class="ipsCode prettyprint lang-ruby prettyprinted" id="ips_uid_104_26" style=""><span class="pln">import java</span><span class="pun">.</span><span class="pln">util</span><span class="pun">.*;</span><span class="pln">
import java</span><span class="pun">.</span><span class="pln">lang</span><span class="pun">.*;</span><span class="pln">
import java</span><span class="pun">.</span><span class="pln">io</span><span class="pun">.*;</span><span class="pln">
</span><span class="kwd">class</span><span class="pln"> </span><span class="typ">ShortestPath</span><span class="pln">
</span><span class="pun">{</span><span class="pln">
   static final int V</span><span class="pun">=</span><span class="lit">9</span><span class="pun">;</span><span class="pln">
   int minDistance</span><span class="pun">(</span><span class="pln">int dist</span><span class="pun">[],</span><span class="pln"> </span><span class="typ">Boolean</span><span class="pln"> sptSet</span><span class="pun">[])</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
int min </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Integer</span><span class="pun">.</span><span class="pln">MAX_VALUE</span><span class="pun">,</span><span class="pln"> min_index</span><span class="pun">=-</span><span class="lit">1</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">int v </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> v </span><span class="pun">&lt;</span><span class="pln"> V</span><span class="pun">;</span><span class="pln"> v</span><span class="pun">++)</span><span class="pln">
           </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">sptSet</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> dist</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> min</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">{</span><span class="pln">
               min </span><span class="pun">=</span><span class="pln"> dist</span><span class="pun">[</span><span class="pln">v</span><span class="pun">];</span><span class="pln">
               min_index </span><span class="pun">=</span><span class="pln"> v</span><span class="pun">;</span><span class="pln">
           </span><span class="pun">}</span><span class="pln">
       </span><span class="kwd">return</span><span class="pln"> min_index</span><span class="pun">;</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   void printSolution</span><span class="pun">(</span><span class="pln">int dist</span><span class="pun">[],</span><span class="pln"> int n</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="str">"Vertex Distance from Source"</span><span class="pun">);</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">int i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> V</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln">
           </span><span class="typ">System</span><span class="pun">.</span><span class="pln">out</span><span class="pun">.</span><span class="pln">println</span><span class="pun">(</span><span class="pln">i</span><span class="pun">+</span><span class="str">" \t\t "</span><span class="pun">+</span><span class="pln">dist</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   void dijkstra</span><span class="pun">(</span><span class="pln">int graph</span><span class="pun">[][],</span><span class="pln"> int src</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
       </span><span class="typ">Boolean</span><span class="pln"> sptSet</span><span class="pun">[]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> new </span><span class="typ">Boolean</span><span class="pun">[</span><span class="pln">V</span><span class="pun">];</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">int i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> V</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           dist</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Integer</span><span class="pun">.</span><span class="pln">MAX_VALUE</span><span class="pun">;</span><span class="pln">
           sptSet</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       dist</span><span class="pun">[</span><span class="pln">src</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
       </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">int count </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> count </span><span class="pun">&lt;</span><span class="pln"> V</span><span class="pun">-</span><span class="lit">1</span><span class="pun">;</span><span class="pln"> count</span><span class="pun">++)</span><span class="pln">
       </span><span class="pun">{</span><span class="pln">
           int u </span><span class="pun">=</span><span class="pln"> minDistance</span><span class="pun">(</span><span class="pln">dist</span><span class="pun">,</span><span class="pln"> sptSet</span><span class="pun">);</span><span class="pln">
           sptSet</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
           </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="pln">int v </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> v </span><span class="pun">&lt;</span><span class="pln"> V</span><span class="pun">;</span><span class="pln"> v</span><span class="pun">++)</span><span class="pln">
               </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(!</span><span class="pln">sptSet</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln"> graph</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]!=</span><span class="lit">0</span><span class="pln"> </span><span class="pun">&amp;&amp;</span><span class="pln">
                       dist</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="typ">Integer</span><span class="pun">.</span><span class="pln">MAX_VALUE </span><span class="pun">&amp;&amp;</span><span class="pln">
                       dist</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]+</span><span class="pln">graph</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> dist</span><span class="pun">[</span><span class="pln">v</span><span class="pun">])</span><span class="pln">
                   dist</span><span class="pun">[</span><span class="pln">v</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> dist</span><span class="pun">[</span><span class="pln">u</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> graph</span><span class="pun">[</span><span class="pln">u</span><span class="pun">][</span><span class="pln">v</span><span class="pun">];</span><span class="pln">
       </span><span class="pun">}</span><span class="pln">
       printSolution</span><span class="pun">(</span><span class="pln">dist</span><span class="pun">,</span><span class="pln"> V</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
   public static void main </span><span class="pun">(</span><span class="typ">String</span><span class="pun">[]</span><span class="pln"> args</span><span class="pun">)</span><span class="pln">
   </span><span class="pun">{</span><span class="pln">
   int graph</span><span class="pun">[][]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> new int</span><span class="pun">[][]{{</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">},</span><span class="pln">
                               </span><span class="pun">{</span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">11</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">},</span><span class="pln">
                               </span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">},</span><span class="pln">
                               </span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">14</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">},</span><span class="pln">
                               </span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">9</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">},</span><span class="pln">
                               </span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln"> </span><span class="lit">14</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">},</span><span class="pln">
                               </span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">},</span><span class="pln">
                               </span><span class="pun">{</span><span class="lit">8</span><span class="pun">,</span><span class="pln"> </span><span class="lit">11</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">},</span><span class="pln">
                               </span><span class="pun">{</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">6</span><span class="pun">,</span><span class="pln"> </span><span class="lit">7</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">}</span><span class="pln">
                               </span><span class="pun">};</span><span class="pln">
       </span><span class="typ">ShortestPath</span><span class="pln"> t </span><span class="pun">=</span><span class="pln"> new </span><span class="typ">ShortestPath</span><span class="pun">();</span><span class="pln">
t</span><span class="pun">.</span><span class="pln">dijkstra</span><span class="pun">(</span><span class="pln">graph</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">
   </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هذا هو الخرج المتوقّع:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_104_29" style=""><span class="typ">Vertex</span><span class="pln">   </span><span class="typ">Distance</span><span class="pln"> from </span><span class="typ">Source</span><span class="pln">
</span><span class="lit">0</span><span class="pln">                </span><span class="lit">0</span><span class="pln">
</span><span class="lit">1</span><span class="pln">                </span><span class="lit">4</span><span class="pln">
</span><span class="lit">2</span><span class="pln">                </span><span class="lit">12</span><span class="pln">
</span><span class="lit">3</span><span class="pln">                </span><span class="lit">19</span><span class="pln">
</span><span class="lit">4</span><span class="pln">                </span><span class="lit">21</span><span class="pln">
</span><span class="lit">5</span><span class="pln">                </span><span class="lit">11</span><span class="pln">
</span><span class="lit">6</span><span class="pln">                </span><span class="lit">9</span><span class="pln">
</span><span class="lit">7</span><span class="pln">                </span><span class="lit">8</span><span class="pln">
</span><span class="lit">8</span><span class="pln">                </span><span class="lit">14</span></pre>

<p>
	ترجمة -بتصرّف- للفصل 11 من كتاب <a href="https://goalkicker.com/AlgorithmsBook/" rel="external nofollow">Algorithms Notes for Professionals</a>
</p>

<h2>
	اقرأ أيضًا
</h2>

<ul>
	<li>
		المقالة السابقة: <a href="https://academy.hsoub.com/programming/advance/%D8%A7%D9%84%D8%B1%D8%B3%D9%88%D9%85-%D8%A7%D9%84%D8%AA%D8%AE%D8%B7%D9%8A%D8%B7%D9%8A%D8%A9-graphs-%D9%81%D9%8A-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1293/" rel=""><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline">الرسوم التخطيطية Graphs في الخوارزميات</span></span></span></span></span></span></span></a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advanced/%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA/" rel="">المرجع الشامل إلى تعلم الخوارزميات للمبتدئين</a>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advance/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A7%D8%AA-r1282/" rel=""><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline">مدخل إلى الخوارزميات</span></span></span></span></span></span></span></a><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"> </span></span></span></span></span></span></span>
	</li>
	<li>
		<a href="https://academy.hsoub.com/programming/advance/%D8%AF%D9%84%D9%8A%D9%84-%D8%B4%D8%A7%D9%85%D9%84-%D8%B9%D9%86-%D8%AA%D8%AD%D9%84%D9%8A%D9%84-%D8%AA%D8%B9%D9%82%D9%8A%D8%AF-%D8%A7%D9%84%D8%AE%D9%88%D8%A7%D8%B1%D8%B2%D9%85%D9%8A%D8%A9-r1247/" rel=""><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline">دليل شامل عن تحليل تعقيد الخوارزمية</span></span></span></span></span></span></span></a><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"> </span></span></span></span></span></span></span>
	</li>
	<li>
		<a href="https://academy.hsoub.com/files/17-%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%A7%D9%84%D8%B0%D9%83%D8%A7%D8%A1-%D8%A7%D9%84%D8%A7%D8%B5%D8%B7%D9%86%D8%A7%D8%B9%D9%8A-%D9%88%D8%AA%D8%B9%D9%84%D9%85-%D8%A7%D9%84%D8%A2%D9%84%D8%A9/" rel=""><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline">مدخل إلى الذكاء الاصطناعي وتعلم الآلة</span></span></span></span></span></span></span></a><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"><span style="text-decoration:underline"> </span></span></span></span></span></span></span>
	</li>
</ul>
]]></description><guid isPermaLink="false">1336</guid><pubDate>Wed, 06 Oct 2021 15:00:00 +0000</pubDate></item></channel></rss>
