Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

البحث بالعمق أولاً (DFS)

آخر تحديث

يستكشف البحث بالعمق أولاً الرسم البياني بالذهاب إلى أعمق نقطة ممكنة على طول كل فرع قبل التراجع. بدءًا من عقدة المصدر، يزور جارًا، ثم جار ذلك الجار، وهكذا حتى يصل إلى طريق مسدود (عقدة بلا جيران غير مُزارين)، وعندها يتراجع ويجرب الفرع التالي. اضغط تشغيل في الأعلى لتراه ينزل عبر مسار واحد، ويصل إلى القاع، ثم يخرج راجعًا.

يُعبَّر عن DFS بشكل طبيعي باستخدام مكدس - إما مكدس صريح (كما هو متحرك هنا) أو مكدس الاستدعاءات عبر التعاود. يزور كل عقدة وحافة مرة واحدة، لذا يعمل بزمن O(V + E) لرسم بياني يحوي V رأسًا وE حافة.

تعقيد الزمن والمساحة

المقياسالتعقيدملاحظات
الزمنO(V + E)كل رأس وحافة تُزار مرة واحدة
المساحةO(V)المكدس + مجموعة المُزارين، في أسوأ الحالات كل العقد
الاجتيازالأعمق أولًايتبع فرعًا واحدًا حتى نهايته قبل الأفرع الأخرى
بنية البياناتمكدس (أو تعاود)ترتيب LIFO يقود السلوك بالعمق أولًا

خطوة بخطوة

الخطوةماذا يحدث
1ادفع عقدة المصدر إلى المكدس.
2اسحب عقدة؛ إن كانت مُزارة سابقًا فتجاوزها.
3علّمها كمُزارة وسجّل الحافة التي وصلت إليها.
4ادفع كل جيرانها غير المُزارين إلى المكدس.
5كرّر حتى يصبح المكدس فارغًا.

مثال محلول

DFS تكراري من A على الرسم البياني A → [B, C]، B → [D]، C → [E]، مع دفع الجيران بالترتيب المذكور (يسحب مكدس LIFO آخر ما دُفع أولًا):

الخطوةالمكدس (القمة يمينًا)المُزارونالإجراء
1[A]{}ادفع المصدر A.
2[B, C]{A}اسحب A، علّمها مُزارة، ادفع الجارين B ثم C.
3[B, E]{A, C}اسحب C، علّمها مُزارة، ادفع الجار E.
4[B]{A, C, E}اسحب E، علّمها مُزارة، لا جيران.
5[D]{A, C, E, B}اسحب B، علّمها مُزارة، ادفع الجار D.
6[]{A, C, E, B, D}اسحب D، علّمها مُزارة، المكدس فارغ: انتهى.

متى تستخدم DFS

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

تنفيذ نظيف وقابل للتشغيل لخوارزمية Depth-First Search بلغات Python, JavaScript, Java, C++, C. اختر لغة، وانسخ الكود، أو افتحه محمّلًا مسبقًا في ساحة تجربة Coddy.

كود Depth-First Search بلغة Python

Python
1def dfs(graph, node, visited):2    visited.add(node)3    order = [node]4    for neighbor in graph[node]:5        if neighbor not in visited:6            order.extend(dfs(graph, neighbor, visited))7    return order8
9
10graph = {11    "A": ["B", "C"],12    "B": ["D", "E"],13    "C": ["F"],14    "D": [],15    "E": ["F"],16    "F": [],17}18
19order = dfs(graph, "A", set())20print("DFS order:", " -> ".join(order))
شغّل هذا الكود في ساحة تجربة Python

الأسئلة الشائعة حول البحث بالعمق أولاً

ما هو تعقيد زمن DFS؟
يعمل DFS بزمن O(V + E)، حيث V عدد الرؤوس وE عدد الحواف، لأنه يزور كل رأس مرة واحدة وينظر إلى كل حافة مرة واحدة. يستخدم مساحة O(V) للمكدس ومجموعة المُزارين.
ما الفرق بين DFS وBFS؟
يستخدم DFS مكدسًا ويغوص عميقًا على طول فرع واحد قبل التراجع، بينما يستخدم BFS طابورًا ويستكشف مستوى تلو الآخر، الأقرب أولًا. يجد BFS أقصر مسار في رسم بياني غير موزون؛ أما DFS فلا، لكنه يستخدم ذاكرة أقل على الرسوم العريضة وهو طبيعي لمهام مثل كشف الدورات والترتيب الطوبولوجي.
هل DFS تعاودي أم تكراري؟
كلاهما يعمل. النسخة التعاودية تستخدم مكدس استدعاءات البرنامج ضمنيًا وهي موجزة جدًا؛ والنسخة التكرارية تستخدم مكدسًا صريحًا (مثل الرسوم المتحركة هنا) وتتجنب فيضان المكدس الناتج عن التعاود العميق على الرسوم الكبيرة.
متى ينبغي أن أستخدم DFS بدلًا من BFS؟
استخدم DFS عندما تحتاج إلى استكشاف مسارات كاملة: كشف الدورات، والترتيب الطوبولوجي، والمكوّنات المتصلة، أو البحث بالتراجع مثل حل متاهة. كما يستخدم ذاكرة أقل على الرسوم العريضة، لأن المكدس يحتفظ بحدود فرع واحد فقط في كل مرة. الجأ إلى BFS عندما تحتاج إلى أقصر مسار في رسم بياني غير موزون أو إلى العقد بترتيب المسافة من المصدر.
هل يستطيع DFS إيجاد أقصر مسار؟
ليس بشكل موثوق. يُرجع DFS أول مسار يصادفه، وهو غالبًا ليس صاحب أقل عدد من الحواف، لأنه يلتزم بالغوص عميقًا بدلًا من التوسع بالتساوي. لأقصر المسارات في رسم بياني غير موزون استخدم BFS، وللرسوم الموزونة استخدم خوارزمية Dijkstra.
لماذا يحتاج DFS إلى مجموعة مُزارين؟
بدون مجموعة مُزارين، سيعيد DFS زيارة العقد التي يمكن الوصول إليها عبر مسارات متعددة، وفي رسم بياني دوري سيدور إلى الأبد. تعليم العقدة كمُزارة عند سحبها (وتجاوز عمليات السحب المُزارة سابقًا) يضمن معالجة كل عقدة مرة واحدة ويُبقي زمن التشغيل عند O(V + E). من الأخطاء الشائعة تعليم العقد كمُزارة عند السحب فقط مع الاستمرار في دفع المكررات، وهو صحيح لكنه قد يترك مدخلات قديمة في المكدس يجب تجاوزها.
Coddy programming languages illustration

أتقن الخوارزميات مع Coddy

ابدأ الآن