• الإعلانات

    • فيصل الحربي

      تسجيل عضوية جديدة في المنتدى   01/31/2016

      السلام عليكم ورحمة الله وبركاته  عزيزي العضو الجديد :  حاليا رسالة الإيميل لتأكيد صحة إيميلكم تذهب للبريد العشوائي ( جاري حل المشكلة )  فإذا لم تجد رسالة التحقق من إيميلكم في صندوق الوارد لديكم إتجه للبريد العشوائي ( JUNK)  وقم بتفعيل إشتراككم من هناك   

البحث في المنتدى

Showing results for tags 'Algorithm'.

  • البحث بالتاقات

    اكتب الكلمات المفتاحيه بينها علامه الفاصله
  • البحث بكاتب الموضوع

تم إيجاد 5 نتيجة

  1. السلام عليكم ورحمة الله وبركاته ترتيب المشط خوارزمية ترتيب بسيطةً نسبياً , صممها في البداية Włodzimierz Dobosiewicz في عام 1980. ثم أعاد اكتشافها Stephen Lacey و Richard Box في عام 1991. وتعد تحسيناً لخوارزمية ترتيب الفقاعات. الخوارزمية الفكرة الأساسية هي إزالة السلاحف, أو القيم الصغيرة الفريبة من نهاية القائمة, فهي سبب رئيسي في بطء خوارزمية ترتيب الفقاعات . في حين لا تسبب الأرانب, القيم الكبيرة في بداية القائمة, أي مشكلة في ترتيب الفقاعات.   عند مقارنة أي عنصرين في ترتيب الفقاعات يكون بينهما فجوة (مسافة بين عنصرين) قيمتها 1. الفكرة الأساسية في ترتيب المشط هي : إمكانية جعل هذه الفجوة أكبر من 1. بكلام أكثر تخصصاً, تم تعديل الحلقة الداخلية في ترتيب الفقاعات, حيث تتم عملية الـتبديل الفعلية, بحيث تتناقص قيمة الفجوة بين العناصر التي تتم مقارنتها (خلال كل دورة للحقة الخارجية) بخطوات يحددها عامل الانكماش . يتم ذلك كما يلي: [ حجم الدخل\عامل الانكماش , حجم الدخل\عامل الانكماش^2, حجم الدخل\عامل الانكماش^3, ...., 1 ]. وذلك على عكس ترتيب الفقاعات, حيث تكون قيمة الفجوة ثابتة أي 1.   تبدأ قيمة الفجوة من حجم القائمة مقسوماً على عامل الانكماش (عادةً 1.3), ويتم ترتيب القائمة بهذه القيمة للفجوة (بعد تقريبها لأقرب عدد صحيح أصغر منها إن لزم الأمر) . ثم يتم تقسيم قيمة الفجوة على عامل الانكماش مرة أخرى ,ثم إعادة ترتيب المقائمة بقيمة الفجوة الجديدة , وهكذا يتم تكرار العملية حتى وصول قيمة الفجوة إلى 1. عند هذه المرحلة , تتابع خوارزمية ترتيب المشط بقيمة الفجوة 1 حتى إتمام عملية الترتيب كلّيّاً . بالتالي فهي مكافئة لترتيب الفقاعات خلال هذه المرحلة , ولكن معظم السلاحف الموجودة يكون قد تم التعامل معها , ولذلك سيكون ترتيب الفقاعات فعالاً خلال هذه المرحلة.   يؤثّر معامل الانكماش بشكل كبير على ترتيب المشط . وقد اقترح المؤلف في مقاله الأصلي عن الخوارزمية قيمة 1.3 للهذا العامل .فالقيمة الصغيرة للمعامل تسبب بطء الخوارزمية لاحتياجها للمزيد من المقارنات , بينما تسبب القيمة الكبيرة للمعامل عدم حدوث أي مقارنة .وقد وجد Lacey و Box بالتجربة (عبر اختبار ترتيب المشط على أكثر من 200,000 قائمة عشوائية )أن القيمة 1.3 هي الأفضل لعامل الانكماش. الصورة المتحركة التالية توضح الترتيب لقائمة من أعمدة مختلفة الأطوال :   شبه الكود ================================================================================    تابع    ترتيب_المشط(  مصفوفة   الدخل )     الفجوة    :=    الدخل.الحجم \\تهيئة حجم الفجوة     الانكماش    :=    1.3 \\تعيين قيمة عامل الانكماش        كرر حتى تصبح    الفجوة   =   1  و  المبادَل   =    غ يرصحيح         \\تحديث قيمة الفجوة لمشط جديد. ما يلي مجرد مثال          الفجوة   :=  عددصحيح( الفجوة  \  الانكماش  )\\قسمة صحيحة         إذا كانت  الفجوة  < 1           \\أصغر قيمة للفجوة هي 1            الفجوة  := 1         نهاية جملة الشرط                   س    :=   0          المبادَل   :=    غيرصحيح \\انظر ترتيب الفقاع ات للتوضيح                  \\"مشطٌ" واحد على قائمة الدخل          كرر حتى تصبح   س  + الفجوة >=  الدخل.الحجم              إذا كانت  الدخل[س] > الدخل[س+الفجوة]                  مبادلة (الدخل[س], الدخل[س+الفجوة])                 المبادَل  :=  صحيح \\ ضع علامة بأن عملية تبادل  قد تمّت مما يعني                                 \\ أن القائمة ليست مرتبة بالضرورة             نهاية جملة الشرط             س := س + 1         نهاية جملة الشرط     نهاية حلقة التكرار نهاية التابع ================================================================================     وإليكم كود بسيط بلغة ++C هو مجرد ترجمة مباشرة لشبة الكود: #include <iostream>using namespace std;int*CombSort(int*input,int input_size){    int gap=input_size;    double shrink=1.3;    bool swapped;    while (!( gap==1 and swapped==false )){//repeate until gap==1 and swapped==false        gap=int(gap/shrink);        if(gap<1)        {            gap=1;        }//end if        int i=0;        swapped=false;        while(!(    i+gap>=input_size    )){            if(input[i]>input[i+gap]){                swap(input[i],input[i+gap]);                swapped=true;            }//end if            i=i+1;        }//end while    }//end while    return input;}//end combSortint main(){    int A[10]={9,7,1,8,6,4,5,2,4,1};    for(int i=0;i<10;i++)        cout<<A[i]<<" ";    cout<<endl;    CombSort(A,10);    for(int i=0;i<10;i++)        cout<<A[i]<<" ";    cout<<endl;    return 0;}خاتمة : أخي الكريم , لقد قمت أثناء كتابة هذه المقالة بالرجوع إلى صفحة ويكيبيديا الانكليزية كمرجع رئيسي , ولكن رغبة مني في تحسين المقال الذي بين يديك الآن , ورغبة مني في تحقيق الأمنية الغالية وهي وجود مرجع عربي ممتاز لعلوم الحاسب بشكل رئيسي , فقد قمت بكتابة صفحة ويكيبيديا العربية الخاصة بترتيب المشط , أرجو من أن تساهم في تحسينها لأنك تفيدنا جميعاً بذلك , كما أرجو أن يكون هذا المقال بذرة لمقالات أخرى نساهم فيها جميعاً , ربما يتطوع أحدنا لتشكيل ُ ٌ ٍ ِ ُ بعض الكلمات , وآخر لتصحيح بعض الأخطاء الإملائية وآخر لاستبدال الكلمات المترجمة بترجمة أفضل , كل هذا ليس له علاقة بخبرتك في الموضوع بل بغيرتك على لغتنا العربية وحبك لها .   والله ولي التوفيق
  2. السلام عليكم ورحمة الله وبركاته اعتدنا أثناء الترتيب على البحث عن الخوارزمية ذات عدد المقارنات الأقل less comparisons , او على الخوارزمية ذات عدد الاستبدالات الأقل less swaps بين العناصر , ولكن ماذا لو كان لدينا كومة من الفطائر المكدسة فوق بعضها البعض وذات أقطار مختلفة .. ونريد ترتيبها . إن سبب تعدد خوارزميات الترتيب هو اختلاف الخوارزمية المثالية لبنية المعطيات التي لدينا , وهذا مبدأ هام جداً في دراسة الخوارزميات , فقد تكون عملية الاستبدال swap مكلفة في بنية ما , بينما تكون (O(1 في بنية أخرى , لذلك علينا العثور على خوارزمية تشمل العمليات الأقل كلفة حسب البنية المعطاة لنرجع إلى فطائرنا .. إن عملية استبدال فطيرتين مكلفة ! فهي تسبب اتساخ اليد بالـ"sauce" الموجود عليها , كما ان استخدام الملاعق لاستبدال الفطيرتين ... لك أن تتخيل ذلك , رفع ما فوق الفطيرة السفلى ثم رفع ما فوق الفطيرة العليا ثم التبديل ثم انزال الكدسات المرفوعة ... عملية مكلفة بكل ما تعني الكلمة ولكن ماذا عن عملية القلب flip  ؟ يمكننا وضع ملعقة بداخل الكدسة ثم قلب كل ما فوق هذه الكدسة , الشكل التالي يوضح كدسة فطائر قبل وبعد القلب واضح ان العملية بسيطة جداً , وغير مكلفة , ولذلك تم عمل خوارزمية الترتيب Flip Sort او ما يسمى Pancake Sort التي تعتمد على هذه الـ operator غير المكلفة , الـ FLIP operator في هذه الخورازمية يمكننا فقط القيام بعملية الـ flip هذه , ولترتيب القائمة التي لدينا علينا اتباع الخطوات التالية :   إذا كان لدينا n عنصر , فعلينا تكرار ما يلي n  مرة ولنضع عدادا i يبدأ من 1 : 1- العثور على العنصر الأكبر خلال المجال من i إلى n 2- وضع الملعقة على موضع العنصر الأكبر وقلب الكدسة التي فوقه . 3- وضع الملعقة في الموضع i وقلب الكدسة التي فوقه 4- زيادة العداد i والتوقف إذا كان i==n   للتوضيح : عملية قلب الكدسة هي عملية flip للعناصر من موضع القلب إلى القمة (أي إلى n ) هذا المقطع يوضح هذه الخوارزمية   الخوارزمية السابقة , يمكن تحسينها حيث لا نحتاج لعمليتي القلب إن كان العنصر في مكانه , كما لا نحتاج عملية القلب الأولى إن كان العناصر أصلاً في القمة (أي في الموضع n ) وبذلك يمكننا تحسينها إلى :   إذا كان لدينا n عنصر , فعلينا تكرار ما يلي n  مرة ولنضع عدادا i يبدأ من 1 : 1- العثور على العنصر الأكبر خلال المجال من i إلى n 2-    2.1- إذا كان العنصر الأكبر في الموضع i نتركه كما هو    2.2- إذا كان العنصر الأكبر في الموضع n نقوم بوضع الملعقة في الموضع i ونقلب الكدسة رأساً على عقب    2.3- إذا لم يكن العنصر الأكبر هو العنصر i  ولا  العنصر n  فعلينا وضع المعقة في موضع العنصر الأكبر وليكن j وقلب الكدسة التي فوقها عندها سيصبح في الموضع n ثم ننفذ 2.2 3-نزيد قيمة i (عند هذه النقطة يكون كل العناصر من الأسفل وحتى i مرتبة ) ونتوقف إذا كان i==n   إذا اعتبرنا عملية الـ flip هي العملية الوحيدة فإن أكبر عدد من الـ flip تحتاجه الكدسة حتى يتم ترتيبها هو 2*n (مرتان لكل موضع ) ولا ننسى أننا بحاجة إلى العثور على العنصر الأكبر في الكدسة , مما يعني (O(n للبحث كل مرة , وبذلك يكون التعقيد الزمني للخوارزمية لو كانت عملية القلب (O(1 هي (O(n2 ولكن عملية القلب حوسبياً هي عملية (O(n وبالتالي تعقيد الخوارزمية حسابياً هو (O(n3 إذا هي فعالة في الحياة العملية أكثر منها في الحاسوب .   كانت هذه لمحة موجزة و سريعة عن هذه الخوارزمية , أرجو أن تكون مفيدة والله ولي التوفيق     المصادر : Wikipedia GeeksForGeeks
  3. السلام عليكم ورحمة الله وبركاته حديثنا اليوم عن خوارزمية ترتيب ممتعة , بالرغم من كون تعقيدها الزمني (O(n2 , إلا أنها ملفتة للنظر بفكرتها , ومعرفتُها (قد) تؤدي بنا إلى تطوير خوارزميات أخرى أو على الأقل التفكير بطريقة جديدة , والهدف من استهداف هذه الخوارزمية في هذه المقالة هو جماليتها لا فاعليتها . خوارزمية خلّاط الكوكتيل ! أو باسمها الرسمي الترتيب الفقاعي ثنائي الاتجاه . تعتمد خوارزمية الترتيب الفقاعي على مقارنة كل زوجين متجاورين وتبديل مكانيهما إن كان شرط الترتيب غير محققاً (حيث شرط الترتيب هو الذي يحدد طريقة الترتيب تصاعدي أو تنازلي) ويتم الترتيب الفقاعي بالمرور على عناصر القائمة أو المصفوفة بجهة واحدة وإجراء المقارنة والاستبدال إن لزم , ثم تكرار عملية المرور بنفس الجهة عدداً n من المرات (حيث n هو عدد عناصر القائمة ). مثال (على الترتيب الفقاعي) :لدينا القائمة نريد ترتيبها تصاعدياً بحيث يكون الأصغر على اليسار والأكبر على اليمين لذلك نقوم بعمل n-1 مقارنة (حيث n هنا هو 6 ) كما يلي بعد المقارنة نقوم بتبديل مكاني العددين إن كان الأيسر أكبر من الأيمن (أي بعكس الهدف الذي نريد الوصول إليه ) فتصبح ثم نقوم بمقارنة الزوج الثاني ونقوم بالاستبدال لأن الأيسر أكبر من الأيمن وهكذا سينتج لدينا بعد كل مقارنة واستبدال التسلسل التالي والآن انتهى المرور الأول (احتاج إلى 5 عمليات استبدال)  لاحظ كيف أن الرقم 9 انتقل من أقصى اليمين إلى أقصى اليسار  ,ولكن الرقم الأصغر 1 انتقل خطوة واحدة فقط لليمين وهذا ما يسمى بمشكلة السلحفاة ,  أي أن الرقم الصغير يسير ببطء شديد نحو موضعه الحقيقي , فالترتيب الفقاعي للقائمة السابقة (بعد انتهاء المرور الثاني , يحتاج إلى 3 عمليات استبدال ) سيكون : لاحظوا أن النتيجة ظهرت وكأننا قمنا بعمل insertion sort بحيث وضعنا الـ 4 في مكانها وأزحنا الباقي لليسار بعد المرور الثالث (عمليتا استبدال) : وبعد المرور الرابع ( عملية استبدال واحدة ) احتجنا إلى 11 عملية استبدال أما ترتيب الكوكتيل , فالاختلاف الوحيد بينه وبين الترتيب الفقاعي هو أن المرور ذو الرقم الزوجي ( مثلاً المرور الثاني والرابع .. ) يكون من اليمين لليسار (بعكس جهة المرور الفردي ) لنرجع إلى القائمة نفسها : المرور الأول مطابق تماماً للترتيب الفقاعي (يحتاج 5 عمليات استبدال ) وسيعطي : والآن إلى المرور الثاني : نبدأ من اليمين إلى اليسار (سنرمز بالمقارنة التي لا ينتج عنها استبدال بخط , والتي ينتج عنها استبدال بسهمين متعاكسين) انتهى المرور الثاني (احتاج 3 عمليات استبدال ) بوضع 1 في البداية , وبذلك تخلصنا من أثر السلحفاة .  بعد انتهاء المرور الثالث (باستخدام عمليتي استبدال )سيكون لدينا : وبانتهاء المرور الرابع (بعملية استبدال واحدة )   كلا الخوارزميتين احتاج 11 عملية استبدال , وكلاهما قام بـ 4 مرات مرور على المصفوفة . ملاحظة : في المراجع يتم اعتبار المرورين (من اليسار لليمين ثم من اليمين لليسار كمرور واحد للكوكتيل) فأين هو التحسين ؟ أحياناً تحتاج خوارزمية الكوكتيل عدداً أقل من عمليات المرور مثلاً المصفوفة (2,3,4,5,1) , وفي الحالة الوسطية فإن ترتيب الكوكتيل يكون أسرع بأقل من مرتين تقريباً من الترتيب الفقاعي . ولكن ربما يمكننا الاستفادة من أن الخوارزمية تقوم بنقل العناصر ذات القيمة المتوسطة إلى المنتصف كل دورتين , أي أنه يمكننا اعتبار المصفوفة مرتبة بشكل جزئي , فلو اضطررنا لإنهاء الترتيب للبيانات فسيكون لدينا البداية والنهاية مرتبة وهذا عملي أكثر من ترتيب النهاية فقط . كما ذكرت في بداية المقالة , فالهدف هو رؤية جمالية الخوارزمية , لذلك أترككم مع فيديو يوضح عملية ترتيب قائمة ( حيث تم تمثيل قيمة العناصر بارتفاع العمود ) الفيديو يستحق المشاهدة بالفعل http://www.youtube.com/watch?v=njClLBoEbfI http://www.youtube.com/watch?v=JiJXnEpDk5o   المراجع : http://en.wikipedia.org/wiki/Cocktail_sort http://www.codingunit.com/cocktail-sort-algorithm-or-shaker-sort-algorithm http://en.algoritmy.net/article/40270/Shaker-sort   والله ولي التوفيق
  4. السلام عليكم و رحمة الله   الموضوع هو طلب شرح Segmented Sieve of Eratosthenes، قرأت مواضيع عديده و أكواد كثيرة لها و لكن حتى الأن لا أستطيع فهمها؟!!   إن استطاع أحد أن يضع شرح لها هنــا - مع مثال بسيط إن كان بالإمكان - فجزاه الله خيرا.     و الله ولي التوفيق
  5. السلام عليكم ورحمة الله وبركاته تعتبر خوارزمية Depth First Search أحد الخوارزميات للمرور على جميع النقاط المتصلة connected nodes في مخطط Graph ما .. لا أريد التكرار فالموضوع عليه الكثير من الشروحات الواضحة على youTube  كما أن صفحة wikipedia فيها شرح ممتاز (وفيديو ملحق لإنشاء متاهة أيضاً :) ) ولكن لتبسيط الأمر .. تخيل أن لدينا شجرة كثيرة الفروع , حتى أن فروعها متداخلة , يعني يمكن أن يتقاطع فرعان ويندمجا ! تخيل أن هذه شجرة : هذه الأشجاء التخيلية التي تحوي فروعاً وتقاطعات تُسمّى Graphs (مخططات ) المهم .. تخيل أننا نريد المرور على جميع فروع الشجرة . سنبدأ من الجذر ونصعد .. ثم سيتفرع الجذع الى عدة فروع .. وكل فرع سيتفرع لاحقاً وهكذا .. هناك عدة طرق يمكننا من خلالها ضمان المرور على جميع الفروع .(المرور على جميع الفروع والتقاطعات(العقد) يُسمّى traversing ) إحداها طريقة Depth first Search تحتاج لتطبيقها إلى مكدّس ومعرفة بسيطة في الحلقات والشروط . خوارزمية DFS : 0-نضع الجذر في المكدس ونبدأ الحلقة طالما أن المكدس غير فارغ : 1- نقوم بوضع علامة على العنصر في قمة المكدس للدلالة على انه قد تمت زيارته 2- نقوم باختبار وجود عناصر مرتبطة بالعنصر الحالي(قمة المكدس ) وهل هي صالحة للزيارة (تكون صالحة للزيارة إن كانت مرتبطة بالعنصر ولم تتم زيارتها من قبل ) 3- كل عنصر يحقق الشرط في الخطوة 2 نضعه في المكدس 4- إن لم يحقق أي عنصر الشرط في الخطوة 2 نقوم بإخراج العنصر الحالي من المكدس 5- ان كان المكدس غير فارغ نذهب للخطوة 1   لنحول الخوارزمية إلى كود نحتاج إلى آلية تكديس وسنستعمل std::stack, وآلية loop ويمكن أن نستعمل for  , وسنحتاج آلية لإعادة القيام بالعملية على العقدة الجديدة (يمكن أن نستعمل العودية recursion ولكن سنطبق اليوم بواسطة حلقة while) كما أننا نحتاج وجود المخطط وبه العقد المتصلة (النقاط المتصلة) وسنستعمل ببساطة مصفوفة من بعدين , كل عنصرين متجاورين فيها يكونان مرتبطين مثال للمصفوفة : 1 2 3 4 5 6 7 8 9 نقول أن 1 مع 4 و 2 مرتبطة , وكذلك :  9 مع 6 و 8 وهكذا (يمكن لك أن تعتبر وجود ارتباطات بالمائل مثل 5 و 9 ان أردت ) يمكننا وضع علامة على النقطة التي تمت زيارتها ببساطة بتغيير قيمة المصفوفة مثلاً من 0 إلى 1 أخيراً  : نلاحظ أن الخطوة 4 لم تعد تحتاج إلى for loop  لأن العقد المرتبطة في حالة المصفوفة هي 4 كحد أقصى لذلك سنكتبها يدوياً   لنبدأ ..على بركة الله تحويل الخوارزمية إلى كود : أولا ودوماً أولاً : تطبيق بنية الـGraph ببساطة مصفوفة يمكن ان تحوي 0 أو 1 .. bool :) bool graph[30][30]={false}; القيمة false تعني أننا لم نزر أي عقدة بعد . ثانياً : كيفية الامساك بعقدة ما .. في حالتنا عن طريق الموضع في المصفوفة سنكتب  struct بسيط يُمثّل الموضع struct coord{     int x;     int y;     coord(int x1,int y1){         x=x1;         y=y1;     } }; ولا ننسى آلية التكديس stack <coord> s;والآن  الحلقة التي سنعمل بداخلها الخطوات من 1 إلى 5 , وبها سنتابع بقية العمل , ولكن قبل الدخول إليها علينا دفع الجذر إلى المكدس (أو أي عقدة نرغب في البدء منها ) while(!s.empty()){ }سنقوم بملء التابع السابق كما توضّح الخوارزمية   1-عملية وضع علامة على الفرع الذي تمت زيارته         graph[s.top().y][s.top().x]=true;2-اختبار صلاحية زيارة جميع العقد المرتبطة , وبعد انتهاء العقد المرتبطة ( أو عدم وجودها فالأمر سيان ) أخرج العقدة الحالية من stack سنختبر كل جهة على حدة كما يلي: //look at left        if(valid(s.top().y,s.top().x-1)){            s.push(coord(s.top().y,s.top().x-1));        }        //look at right        else if(valid(s.top().y,s.top().x+1)){            s.push(coord(s.top().y,s.top().x+1));        }        //look up        else if(valid(s.top().y-1,s.top().x)){            s.push(coord(s.top().y-1,s.top().x));        }        //look down        else if(valid(s.top().y+1,s.top().x)){            s.push(coord(s.top().y+1,s.top().x));        }        else{            s.pop();        }الكود بصيغته النهائية : الكود : أولاً : البنى والتوابع المساعدة struct coord{    int x;    int y;    coord(int y1,int x1){        x=x1;        y=y1;    }};const int X=10,Y=10;bool graph[Y][X]={false};stack <coord> s;bool valid(int y,int x){    if(x<X&&x>=0)        if(y<Y&&y>=0)            if(graph[y][x]==false)                return true;    return false;}والتنفيذ في الدالةmain int main(){    //push the current node    s.push(coord(0,0));    while(!s.empty())    {        graph[s.top().y][s.top().x]=true;        //look at left        if(valid(s.top().y,s.top().x-1)){            s.push(coord(s.top().y,s.top().x-1));        }        //look at right        else if(valid(s.top().y,s.top().x+1)){            s.push(coord(s.top().y,s.top().x+1));        }        //look up        else if(valid(s.top().y-1,s.top().x)){            s.push(coord(s.top().y-1,s.top().x));        }        //look down        else if(valid(s.top().y+1,s.top().x)){            s.push(coord(s.top().y+1,s.top().x));        }        else{            s.pop();        }    }    return 0;}كي نتابع عملية السير سنكتب تابع بسيط لإظهار المخطط بعد كل تغيير هذا مثال void printGraph(){/*Put here any implementation to return the pointer to top left*/        cout << s.size() << " " << s.top().x <<" " <<s.top().y<< endl;    for(int i=0;i<Y;i++)    {        for(int j=0;j<X;j++)        {            cout<<(graph[i][j]?'#':' ');        }        cout <<endl;    }/*Put here any implementation to Sleep for 10-100 milli second*/    }في ويندوز سأستعمل تابعين من الـ API void printGraph(){    COORD topLeft={0,0};    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),topLeft);    cout << s.size() << " " << s.top().x <<" " <<s.top().y<< "     " << endl;    for(int i=0;i<Y;i++)    {        for(int j=0;j<X;j++)        {            cout<<(graph[i][j]?' ':'#');        }        cout <<endl;    }    Sleep(30);}ثم ضع استدعاء التابع داخل حلقة while الخاصة بالخوارزمية جرب الكود التالي  في ويندوز (++C) #include<stack>#include<iostream>#include<windows.h>using std::stack;using std::cout;using std::endl;struct coord{    int x;    int y;    coord(int y1,int x1){        x=x1;        y=y1;    }};const int X=10,Y=10;bool graph[Y][X]={false};stack <coord> s;void printGraph(){    COORD topLeft={0,0};    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),topLeft);    cout << s.size() << " " << s.top().x <<" " <<s.top().y<< "     " << endl;    for(int i=0;i<Y;i++)    {        for(int j=0;j<X;j++)        {            cout<<(graph[i][j]?' ':'#');        }        cout <<endl;    }    Sleep(30);}bool valid(int y,int x){    if(x<X&&x>=0)        if(y<Y&&y>=0)            if(graph[y][x]==false)                return true;    return false;}int main(){    //put flag on the visited node    int x=0,y=0;    //push the current node    s.push(coord(x,y));    while(!s.empty())    {        printGraph();        graph[s.top().y][s.top().x]=true;        //look at left        if(valid(s.top().y,s.top().x-1)){            s.push(coord(s.top().y,s.top().x-1));        }        //look at right        else if(valid(s.top().y,s.top().x+1)){            s.push(coord(s.top().y,s.top().x+1));        }        //look up        else if(valid(s.top().y-1,s.top().x)){            s.push(coord(s.top().y-1,s.top().x));        }        //look down        else if(valid(s.top().y+1,s.top().x)){            s.push(coord(s.top().y+1,s.top().x));        }        else{            s.pop();        }    }    return 0;}  تجدر الإشارة إلى فكرة هامّة جداً .. يعتمد المعالج في استدعاء التوابع على مكدّس خاص بالاستدعاءات ويمكننا الاستغناء عن مكدسنا std::stack والاستعانة بالمكدس الخاص بالاستعداءات وذلك عن طريق وضع العملية في تابع بدلاً من while , وبدلاً من عملية push سنقوم باستدعاء التابع مرة أخرى , وبمجرد انتهاء التابع أو عمل return  سيتم عمل pop للقيمة الحالية انظر الكود التالي(أبسط من السابق) #include<iostream>#include<windows.h>using std::cout;using std::endl;const int X=10,Y=10;bool graph[Y][X]={false};void printGraph(){    COORD topLeft={0,0};    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),topLeft);    for(int i=0;i<Y;i++)    {        for(int j=0;j<X;j++)        {            cout<<(graph[i][j]?' ':'#');        }        cout <<endl;    }    Sleep(30);}bool valid(int y,int x){    if(x<X&&x>=0)        if(y<Y&&y>=0)            if(graph[y][x]==false)                return true;    return false;}void function(int y,int x){    printGraph();    graph[y][x]=true;    //look at left    if(valid(y,x-1)){        //s.push(coord(s.top().y,s.top().x-1));        function(y,x-1);    }    //look at right    if(valid(y,x+1)){        //s.push(coord(s.top().y,s.top().x+1));        function(y,x+1);    }    //look up    if(valid(y-1,x)){        //s.push(coord(s.top().y-1,s.top().x));        function(y-1,x);    }    //look down    if(valid(y+1,x)){        //s.push(coord(s.top().y+1,s.top().x));        function(y+1,x);    }//        s.pop();        return ;}int main(){    function(0,0);    return 0;}ولكننا خسرنا ميزة تتبع المكدس فلم يعد بإمكاننا مثلاً كتابة cout << s.size() << " " << s.top().x <<" " <<s.top().y<< "     " << endl;إذا جربت الكود , فستلاحظ أنه يسير بطريقة عادية ليمر على جميع عناصر المصفوفة , ولكن جرب كتابة  function(5,5);وسيبدأ من المنتصف , وعندها ستلاحظ سلوكاً غير متوقع (ربما) في المرور على جميع العناصر .   والآن إلى إنشاء المتاهة: ببساطة سنتحرك خطوتين بدلاً من خطوة واحدة , وبذلك سنترك فراغات تُشكّل الحوائط ! #include<cstdio>#include<windows.h>const int X=21,Y=21;bool graph[Y][X]={false};void printGraph(){    COORD topLeft={0,0};    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),topLeft);    for(int i=0;i<Y;i++)    {        for(int j=0;j<X;j++)        {            putchar(graph[i][j]?' ':'#');        }        putchar('\n');    }}bool valid(int y,int x){    if(x<X&&x>=0)        if(y<Y&&y>=0)            if(graph[y][x]==false)                return true;    return false;}void function(int y,int x){    printGraph();    //look at left    if(valid(y,x-2)){        //s.push(coord(s.top().y,s.top().x-1));        graph[y][x-1]=true;        graph[y][x-2]=true;        function(y,x-2);    }    //look at right    if(valid(y,x+2)){        //s.push(coord(s.top().y,s.top().x+1));        graph[y][x+1]=true;        graph[y][x+2]=true;        function(y,x+2);    }    //look up    if(valid(y-2,x)){        //s.push(coord(s.top().y-1,s.top().x));        graph[y-1][x]=true;        graph[y-2][x]=true;        function(y-2,x);    }    //look down    if(valid(y+2,x)){        //s.push(coord(s.top().y+1,s.top().x));        graph[y+1][x]=true;        graph[y+2][x]=true;        function(y+2,x);    }//        s.pop();        return ;}int main(){    function(5,5);    Sleep(100000);    return 0;}جرب الكود , وستلاحظ أن المتاهة سهلة جداً  للحل ولجعلها صعبة وعشوائية سنغير فقط طريقة الرؤية للكود ! ماذا يعني هذا ؟ يعني أن نجعل اختبارات (اليسارواليمين .. ) غير ثابته , فمثلاً يمكن أن نختبر المرور للأسفل قبل اليمين وهكذا .. لاحظ اختلافات الكود : #include<cstdio>#include<cstdlib>#include<ctime>#include<windows.h>const int X=31,Y=31;bool graph[Y][X]={false};void printGraph(){    COORD topLeft={0,0};    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),topLeft);    for(int i=0;i<Y;i++)    {        for(int j=0;j<X;j++)        {            putchar(graph[i][j]?' ':'#');        }        putchar('\n');    }}bool valid(int y,int x){    if(x<X&&x>=0)        if(y<Y&&y>=0)            if(graph[y][x]==false)                return true;    return false;}void function(int y,int x){    printGraph();    for(int i=0;i<10;i++){//to ensure passing all valid moves        int dx=0,dy=0;        while(dx^dy==0){            dy=rand()%2;//zero or one            dx=rand()%2;//zero or one        }        if(rand()%2==1)            dx*=-1,            dy*=-1;        if(valid(y+2*dy,x+2*dx)){            //s.push(coord(s.top().y,s.top().x-1));            graph[y+dy][x+dx]=true;            graph[y+2*dy][x+2*dx]=true;            function(y+2*dy,x+2*dx);        }    }        return ;}int main(){    srand(time(0));    function(5,5);    Sleep(100000);    return 0;{في الختام أود لفت الانتباه إلى أنه من الأمور الهامة جداً عند دراسة الخوارزميات عدم خلط الخورازمية بالتطبيق , مثلاً فتطبيق رسم المتاهة هو أحد التطبيقات لخوارزمية DFS وليس هو الخوارزمية , وقد وضعته كمثال رسومي جيد لبيان جمال الخوارزمية ليس أكثر .   والله ولي التوفيق