خوارزمية Dijkstra: دليلك لإيجاد أقصر الطرق في عالم البيانات (مع أمثلة Python)

مقدمة: ضعت في شوارع نابلس… والحل كان في خوارزمية!

بتذكر مرة، كنت في نابلس، الله وكيلكم، ومش عارف أوصل لمحل الكنافة اللي صحابي مدحولي إياه. الشوارع متداخلة وزحمة، وكل واحد بيعطيني طريق شكل. حسيت حالي تايه في متاهة! وقتها خطر ببالي: لو في خوارزمية بتساعدني ألاقي أسرع طريق زي ما بتعمل خرائط جوجل! هادا الموقف خلاني أتعمق أكتر في خوارزمية Dijkstra، اللي هي الأساس في كتير من تطبيقات تحديد المسارات.

في هالمقالة، رح نشرح خوارزمية Dijkstra بالتفصيل، وكيف ممكن نطبقها بلغة Python. سواء كنت مبرمج مبتدئ أو محترف، رح تلاقي فيها معلومات مفيدة وتساعدك في مشاريعك.

ما هي خوارزمية Dijkstra؟

خوارزمية Dijkstra (نسبة للعالم الهولندي Edsger W. Dijkstra) هي خوارزمية تستخدم لإيجاد أقصر المسارات بين عقدة بداية معينة وبقية العقد في رسم بياني (Graph). الرسم البياني هو عبارة عن مجموعة من العقد (Nodes) مرتبطة ببعضها البعض عن طريق حواف (Edges)، وكل حافة ممكن يكون عليها وزن (Weight) يمثل المسافة أو التكلفة للانتقال بين العقدتين.

ببساطة، الخوارزمية بتشتغل عن طريق استكشاف العقد الأقرب لعقدة البداية، وبعدين بتوسع الاستكشاف تدريجياً لحد ما توصل لكل العقد التانية. الأهم إنها بتضمن إنك في كل مرة بتختار أقصر طريق ممكن لحد اللحظة.

كيف تعمل خوارزمية Dijkstra؟

الخوارزمية بتعتمد على الخطوات التالية:

  1. تهيئة:
    • حدد عقدة البداية.
    • خصص قيمة “مسافة” لكل عقدة في الرسم البياني، قيمتها مبدئياً “مالا نهاية” (Infinity)، باستثناء عقدة البداية اللي قيمتها صفر.
    • حدد مجموعة “العقد التي لم تتم زيارتها” (Unvisited Nodes) تحتوي على جميع العقد في الرسم البياني.
  2. التكرار:
    • طالما أن هناك عقد لم تتم زيارتها:
    • اختر العقدة التي لم تتم زيارتها والتي لديها أقصر “مسافة” حالية من عقدة البداية.
    • لكل جار (Neighbor) لهذه العقدة:
      • احسب المسافة من عقدة البداية إلى هذا الجار من خلال العقدة الحالية.
      • إذا كانت هذه المسافة أقصر من المسافة الحالية المسجلة للجار، فقم بتحديث المسافة المسجلة للجار.
    • ضع علامة على العقدة الحالية على أنها “تمت زيارتها” (Visited).
  3. النتيجة: بعد انتهاء التكرار، سيكون لديك أقصر مسافة من عقدة البداية إلى كل عقدة أخرى في الرسم البياني.

مثال عملي بلغة Python

خلينا نشوف مثال بسيط لكيفية تطبيق خوارزمية Dijkstra بلغة Python:


import heapq

def dijkstra(graph, start):
    distances = {node: float('inf') for node in graph}
    distances[start] = 0
    pq = [(0, start)]  # Priority queue: (distance, node)

    while pq:
        dist, node = heapq.heappop(pq)

        if dist > distances[node]:
            continue  # Skip if we've found a shorter path

        for neighbor, weight in graph[node].items():
            distance = dist + weight
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(pq, (distance, neighbor))

    return distances

# Example graph represented as a dictionary of dictionaries
graph = {
    'A': {'B': 5, 'C': 1},
    'B': {'A': 5, 'C': 2, 'D': 1},
    'C': {'A': 1, 'B': 2, 'D': 4, 'E': 8},
    'D': {'B': 1, 'C': 4, 'E': 3},
    'E': {'C': 8, 'D': 3}
}

start_node = 'A'
shortest_distances = dijkstra(graph, start_node)

print(f"Shortest distances from {start_node}: {shortest_distances}")

في هالمثال، استخدمنا مكتبة `heapq` عشان نعمل “قائمة أولوية” (Priority Queue)، واللي بتساعدنا نختار العقدة اللي الها أقصر مسافة بشكل فعال. الرسم البياني تم تمثيله كقاموس (Dictionary) بحيث كل مفتاح يمثل عقدة، والقيمة المقابلة هي قاموس تاني بيمثل الجيران والأوزان بين العقد.

شرح الكود بالتفصيل

  • `dijkstra(graph, start)`: هي الدالة الرئيسية اللي بتنفذ الخوارزمية. بتاخد الرسم البياني وعقدة البداية كمدخلات.
  • `distances = {node: float(‘inf’) for node in graph}`: بتهيء قاموس `distances` عشان يخزن أقصر المسافات لكل عقدة. كل المسافات مبدئياً بتكون “مالا نهاية” باستثناء عقدة البداية اللي بتكون صفر.
  • `pq = [(0, start)]`: بتهيء “قائمة الأولوية” `pq` عشان تخزن العقد اللي لازم نزورها بالترتيب بناءً على المسافة. العنصر الأول في القائمة هو (المسافة، العقدة).
  • `while pq:`: حلقة التكرار الرئيسية اللي بتستمر طالما في عقد لازم نزورها.
  • `dist, node = heapq.heappop(pq)`: بتسحب العقدة اللي الها أقصر مسافة من “قائمة الأولوية”.
  • `if dist > distances[node]: continue`: هذا الشرط مهم عشان نتجنب معالجة العقد اللي لقينا الها طريق أقصر بالفعل.
  • `for neighbor, weight in graph[node].items():`: بتمر على كل الجيران للعقدة الحالية.
  • `distance = dist + weight`: بتحسب المسافة من عقدة البداية للجار من خلال العقدة الحالية.
  • `if distance < distances[neighbor]:`: بتقارن المسافة المحسوبة بالمسافة المسجلة حالياً للجار. إذا كانت المسافة المحسوبة أقصر، بيتم تحديث المسافة المسجلة.
  • `heapq.heappush(pq, (distance, neighbor))`: بتضيف الجار لـ “قائمة الأولوية” عشان نزوره لاحقاً.
  • `return distances`: بترجع قاموس بيحتوي على أقصر المسافات من عقدة البداية لكل عقدة تانية في الرسم البياني.

نصائح عملية من أبو عمر

  • استخدم هياكل بيانات مناسبة: اختيارك لهياكل البيانات (Dictionaries, Priority Queues) بيلعب دور كبير في كفاءة الخوارزمية.
  • تعامل مع الحالات الخاصة: تأكد إنك بتتعامل مع الرسوم البيانية اللي فيها أوزان سالبة (Negative Weights) بحذر. خوارزمية Dijkstra مش بتشتغل صح في هاي الحالات. ممكن تستخدم خوارزمية Bellman-Ford بدلاً منها.
  • جرب الخوارزمية على أمثلة مختلفة: عشان تفهم الخوارزمية بشكل كامل، حاول تطبقها على رسوم بيانية مختلفة ومعقدة.
  • ابحث عن المكتبات الجاهزة: في كتير من الحالات، بتكون في مكتبات جاهزة بتنفذ خوارزمية Dijkstra بشكل فعال. استخدمها لو مشروعك كبير وبحاجة لأداء عالي.

الخلاصة: Dijkstra مش بس خوارزمية… هي طريقة تفكير! 🚀

خوارزمية Dijkstra مش بس خوارزمية لإيجاد أقصر الطرق، هي طريقة تفكير بتساعدك تحل مشاكل معقدة عن طريق تقسيمها لخطوات بسيطة ومنطقية. تعلمك كيف تبحث عن الحل الأمثل خطوة بخطوة، وهاي المهارة بتفيدك في كل مجالات البرمجة وحتى في حياتك اليومية. جرب طبقها في مشاريعك، واستكشف إمكانياتها، ورح تشوف كيف رح تسهل عليك كتير!

نصيحة أخيرة: لا تخاف من الكود! جرب عدل عليه، غير فيه، وشوف شو بصير. هيك بتتعلم أحسن وأسرع. يلا يا معلم، انطلق! 💪

أبو عمر

سجل دخولك لعمل نقاش تفاعلي

كافة المحادثات خاصة ولا يتم عرضها على الموقع نهائياً

آراء من النقاشات

لا توجد آراء منشورة بعد. كن أول من يشارك رأيه!

آخر المدونات

التكنلوجيا المالية Fintech

كنا نخزن بطاقات الائتمان مباشرة… قصة تسريب بيانات وكيف أنقذني الترميز (Tokenization)

أشارككم قصة حقيقية من بداياتي في عالم التكنولوجيا المالية، حين كاد خطأ بسيط في تخزين بيانات بطاقات الائتمان أن يدمر شركتنا. اكتشفوا كيف كانت تقنية...

15 مارس، 2026 قراءة المزيد
أتمتة العمليات

استيقظتُ في الثالثة فجراً لإعادة تشغيل سيرفر: كيف علّمتُ نظامي أن يشفي نفسه بنفسه عبر الأتمتة؟

هل سئمت من الاستيقاظ في منتصف الليل لإصلاح مشاكل متكررة في خوادمك؟ في هذه المقالة، أشارككم قصتي مع كوابيس الدعم الفني وكيف انتقلت منها إلى...

14 مارس، 2026 قراءة المزيد
تسويق رقمي

إعلاناتي كانت تستهدف الجميع… وبالتالي لم تصل لأحد: كيف استخدمتُ نماذج التجزئة (Clustering) لاكتشاف شرائح عملاء لم أكن أعرف بوجودها؟

في هذه المقالة، أشارككم تجربتي الشخصية كـ "أبو عمر"، مبرمج فلسطيني، وكيف انتقلت من إعلانات عشوائية فاشلة إلى حملات تسويقية ناجحة. اكتشفوا معي كيف استخدمت...

13 مارس، 2026 قراءة المزيد
التوسع والأداء العالي والأحمال

قاعدة بياناتي كانت تتوسل للرحمة: كيف أنقذتني استراتيجية التخزين المؤقت (Caching) من الانهيار؟

أتذكر ذلك اليوم جيدًا، قاعدة البيانات تكاد تنهار تحت ضغط الطلبات المتزايدة. في هذه المقالة، أشارككم قصة حقيقية وكيف كانت استراتيجية التخزين المؤقت، وتحديداً Redis،...

11 مارس، 2026 قراءة المزيد
البودكاست