أحمد حايس
الرئيسيةمن أناالدوراتالمدونةسوق الأوامرالمناهج والباقاتالشركاء
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

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

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • المناهج والباقات
  • سوق الأوامر
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالمناهجالمدونةالدخول
البرمجة بالعربي

الـ Hash Map: إزاي القاموس بيلاقي أي مفتاح في خطوة واحدة

مبتدئ16 يوليو 20265 دقائق قراءة
الـ Hash Map: إزاي القاموس بيلاقي أي مفتاح في خطوة واحدة

المستوى: مبتدئ — المقال ده مكتوب لحد لسه بادئ في البرمجة وسمع كلمة "Hash Map" أو "dict" ومش فاهم ليه الناس بتحبها. مش محتاج تعرف رياضيات، بس تعرف تكتب حلقة بسيطة.

الـ Hash Map: إزاي القاموس بيلاقي أي مفتاح في خطوة واحدة

لو عندك مليون مستخدم وعايز تلاقي واحد منهم بالإيميل، الـ Hash Map بيوصّلك له في خطوة واحدة تقريبًا، مش مليون خطوة. ده الفرق اللي بيخلّي كودك يشتغل في جزء من الثانية بدل ما يتجمّد.

مخطط يوضح تحويل المفتاح ahmed عبر دالة hash إلى الفهرس رقم 5 داخل مصفوفة خانات الـ Hash Map

المشكلة باختصار

تخيّل عندك قائمة فيها مليون إيميل، وعايز تعرف هل إيميل معيّن موجود ولا لأ. لو بتدوّر بحلقة عادية، الكمبيوتر بيقارن عنصر ورا عنصر. في أسوأ حالة بيعمل مليون مقارنة عشان سؤال واحد. لو بتسأل السؤال ده آلاف المرات، السيرفر بيقف. الـ Hash Map بيحل ده: بيديك الإجابة من غير ما يمشي على القائمة كلها.

الأول بمثال بسيط: خزانة المعاطف

تخيّل انت داخل مسرح، وقدام الباب في خزانة معاطف. لما بتسلّم معطفك، الموظف مبيحطّوش في أول مكان فاضي ويسيبك. لأ، هو بياخد رقم تذكرتك، يقول 27، وعلى طول بيعلّق المعطف في الشمّاعة رقم 27.

لما ترجع، انت مش بتدوّر على معطفك في كل الشمّاعات واحدة واحدة. بتدّي الموظف رقم 27، وهو بيروح للشمّاعة 27 دُغري. مش مهم الخزانة فيها 10 معاطف ولا 10 آلاف، الخطوة واحدة: من الرقم للمكان مباشرة.

الـ Hash Map بيشتغل بنفس الفكرة بالظبط. المفتاح (الإيميل مثلًا) هو زي التذكرة، والقيمة (بيانات المستخدم) هي المعطف. في حاجة في النص بتحوّل المفتاح لرقم مكان، وبتوديك له على طول.

دلوقتي بشكل علمي: دالة الـ hash والخانات

الـ Hash Map جوّاه مصفوفة (array) من الخانات، كل خانة ليها رقم فهرس (index). لما تضيف مفتاح، بيمر بخطوتين:

  1. دالة الـ hash: بتاخد المفتاح (نص أو رقم) وتطلّع منه رقم ثابت. مثلًا المفتاح "ahmed" ممكن يطلّع الرقم 91.
  2. باقي القسمة: بنقسم الرقم ده على عدد الخانات وناخد الباقي، فيطلع لنا رقم خانة صالح. لو عندنا 8 خانات: 91 % 8 = 3، يبقى المفتاح مكانه الخانة رقم 3.

وقت البحث بنعمل نفس الحساب بالظبط، فنوصل لنفس الخانة على طول من غير ما نلف على باقي الخانات. علشان كده بنقول إن التكلفة O(1)، يعني زمن ثابت لا علاقة له بحجم البيانات. الافتراض هنا إن دالة الـ hash بتوزّع المفاتيح بشكل جيد على الخانات؛ لو التوزيع وحش، القصة بتختلف (هنشوف ده تحت).

اقيس بنفسك: list مقابل dict

الكلام ده مش نظري. جرّب الكود ده في بايثون، هو بيدوّر على نفس القيمة مرة في قائمة (list) ومرة في قاموس (dict) فيه مليون عنصر:

Python
import time

n = 1_000_000
data_list = list(range(n))        # قائمة عادية
data_set  = set(range(n))         # مبنية على Hash

target = n - 1                    # آخر عنصر: أسوأ حالة للقائمة

# البحث في القائمة: بيمشي عنصر ورا عنصر
start = time.perf_counter()
target in data_list
print("list :", round((time.perf_counter() - start) * 1000, 3), "ms")

# البحث في الـ set/dict: خطوة واحدة تقريبا
start = time.perf_counter()
target in data_set
print("set  :", round((time.perf_counter() - start) * 1000, 3), "ms")

على جهاز عادي، البحث في القائمة بياخد حوالي 8 إلى 15 مللي ثانية، والبحث في الـ set بياخد أقل من 0.001 مللي ثانية. الفرق مش شوية: القائمة أبطأ بآلاف المرات، والفجوة بتكبر كل ما البيانات تكبر. ده اللي بيحصل فعلاً ورا الكواليس لما تكتب if email in users والـ users عبارة عن dict.

لو مفتاحين وقعوا في نفس الخانة: التصادم

فيه سؤال منطقي: طب لو مفتاحين مختلفين طلّعوا نفس رقم الخانة؟ ده بيحصل فعلاً، واسمه تصادم (Collision). مثلًا "ali" و"omar" الاتنين ممكن ينتهوا للخانة رقم 3.

أشهر حل اسمه chaining: كل خانة مش بتشيل عنصر واحد، بتشيل قائمة صغيرة. لما يحصل تصادم، بنحط العنصر الجديد في نفس قائمة الخانة. وقت البحث بنروح للخانة الصح، وبعدين نمر على العناصر القليلة اللي فيها بس، مش على الـ map كله. طول ما التصادمات قليلة، القائمة دي بتفضل عنصر أو اتنين، فالسرعة بتفضل قريبة من الثابت.

معامل التحميل وإعادة التوزيع

عشان التصادمات تفضل قليلة، الـ Hash Map بيراقب حاجة اسمها load factor = عدد العناصر ÷ عدد الخانات. في Java مثلًا القيمة الافتراضية 0.75. أول ما العناصر تعدّي النسبة دي، الـ map بيعمل resize: بيضاعف عدد الخانات ويعيد توزيع كل المفاتيح من جديد.

ده بيحافظ على السرعة، بس الـ trade-off هنا: عملية الـ resize نفسها غالية لأنها بتلمس كل العناصر، والذاكرة المستهلكة أكبر من مجرد تخزين البيانات، لأن في خانات فاضية محجوزة. يعني بتكسب سرعة بحث ثابتة، وبتخسر شوية ذاكرة زيادة ولحظات بطء نادرة وقت التوسيع.

متى لا تستخدم الـ Hash Map

  • لو محتاج ترتيب أو مدى (range): زي "هاتلي كل المستخدمين اللي أعمارهم بين 20 و30 مرتبين". الـ Hash Map مبيحافظش على ترتيب مفيد للاستعلامات دي؛ استخدم شجرة متوازنة أو هيكل مرتّب.
  • لو البيانات صغيرة جدًا: عناصر قليلة (10 مثلًا)، القائمة العادية أبسط وفرقها مش محسوس.
  • لو المفاتيح دالة الـ hash بتاعتها سيّئة: لو كل المفاتيح بتوقع في خانة واحدة، بترجع لـ O(n) وتفقد الميزة كلها.

الخطوة التالية

روح على أقرب مكان في كودك بتعمل فيه if x in my_list جوّه حلقة، وعدّل my_list لـ set أو dict، وبعدين قيس الزمن بالكود اللي فوق قبل وبعد. لو الحلقة كانت بتلف على القائمة كل مرة، هتلاقي فرق واضح مباشرة.

مصادر

  • توثيق بايثون الرسمي عن نوع dict: docs.python.org — Dictionaries
  • Python Time Complexity (تكلفة عمليات dict وset): wiki.python.org — TimeComplexity
  • مقالة Hash table على ويكيبيديا (دالة الـ hash، التصادم، chaining): en.wikipedia.org — Hash table
  • توثيق Java HashMap (معامل التحميل الافتراضي 0.75 وإعادة التوزيع): docs.oracle.com — HashMap

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة