هياكل البيانات والخوارزميات / العقود والتسلسلات والبحث / الدرس 5
خرائط التجزئة والعضوية والقيم المتكررة
استخدم التجزئة لتمثيل الهوية والعد، مع الحفاظ على دلالة التكرار وذكر شروط ادعاءات الزمن المتوقع.
في هذه الصفحة
أهداف الدرس
- اختر المفتاح وفقا لعقد المساواة الفعلي
- عد مرات الظهور بدلا من إسقاطها
- افحص القيمة المكملة قبل تسجيل العنصر الحالي
اختر المفتاح وفقا لعقد المساواة الفعلي
تربط خريطة التجزئة مفتاحا بقيمة، بينما تسجل المجموعة عضوية المفاتيح. وينبغي أن يمثل المفتاح الهوية أو علاقة التكافؤ التي تحتاجها المهمة. فالتسميات الحساسة لحالة الأحرف والتسميات المطبّعة تنتج مجموعات مختلفة؛ لذلك يجب أن يكون التطبيع مقصودا. يجب أن تكون مفاتيح Python قابلة للتجزئة، وأن تتساوى قيم التجزئة للكائنات المتساوية القابلة للتجزئة. ولا يعني تصادم التجزئة بين مفتاحين غير متساويين أنهما يصبحان مفتاحا واحدا؛ إذ تظل الحاوية تتحقق من المساواة. قد تبطل حقول الهوية القابلة للتعديل تصميم مفتاح مخصص. فضّل مفاتيح أولية ثابتة أو مفاتيح tuple للمهام المصطنعة البسيطة، ووثّق معنى كل مكوّن منها.
عد مرات الظهور بدلا من إسقاطها
يبني البرنامج الأول خريطة للتكرارات. قبل كل تكرار، يسجل counts بالضبط عدد مرات ظهور كل رمز زارته الحلقة سابقا. وتحافظ زيادة إدخال واحد على هذا الثابت. أما تحويل المدخل مباشرة إلى مجموعة فيجيب عن الرموز الموجودة، لكنه يفقد عدد مرات ظهورها. العرض المرتب النهائي منفصل عن بناء الخريطة، ويضيف كلفة فرز المفاتيح المختلفة. لا تصف الدالة كاملة بأنها خطية إذا كان الناتج المرتب المطلوب يتضمن فرزا بكلفة O(k log k) لعدد k من المفاتيح الفريدة. يستخدم المثال المصطنع نصوصا عادية قصيرة ومقارنات محدودة الكلفة.
def frequencies(tokens):
counts = {}
for token in tokens:
counts[token] = counts.get(token, 0) + 1
return counts
print(sorted(frequencies(["map", "river", "map"]).items()))
print(frequencies([]))
[('map', 2), ('river', 1)]
{}
تحفظ الخريطة تعدد الظهور، ويجعل الفرز ترتيب العرض صريحا دون الاعتماد على ترتيب المرور في مجموعة.
افحص القيمة المكملة قبل تسجيل العنصر الحالي
يعيد البرنامج الثاني فهرسي زوج واحد يساوي مجموع قيمتيه الهدف. وعند فحص المكمل، لا تحوي الخريطة سوى المواضع السابقة، فلا يستطيع العنصر نفسه تحقيق طرفي الزوج. تحفظ setdefault أول ظهور لقيمة موجودة، فتجعل اختيار الفهرس الأسبق محددا. وتظل القيم المتكررة نافعة: يمكن لقيمتي 3 منفصلتين أن تجمعا إلى 6، بينما لا تستطيع قيمة 3 واحدة فعل ذلك. تعيد الخوارزمية أول زوج يكتشفه المسح وفقا لسياستها المعلنة، وليس جميع الأزواج أو نتيجة مثلى في الترتيب المعجمي. وتحتاج عقود النتائج المختلفة إلى طرق مختلفة لحفظ المعلومات.
def two_sum_indices(values, target):
first = {}
for index, value in enumerate(values):
complement = target - value
if complement in first:
return first[complement], index
first.setdefault(value, index)
return None
print(two_sum_indices([3], 6))
print(two_sum_indices([3, 3], 6))
print(two_sum_indices([2, 4, 7, 9], 11))
None
(0, 1)
(1, 2)
لا يُخزن الفهرس الحالي إلا بعد البحث، فيُفرض اختلاف الموضعين. وتعثر العينة الأخيرة على 4+7 قبل الوصول إلى القيمة 9.
يحتاج الزمن المتوقع الثابت إلى افتراضات
يُحلل البحث بالتجزئة والإدراج عادة بزمن ثابت متوقع عند افتراض تجزئة وحمل مناسبين؛ وقد يكون السلوك في الحالة الأسوأ أبطأ، كما أن لتجزئة مفتاح طويل كلفة خاصة بها. تؤثر تفاصيل تنفيذ Python ودوال المساواة المخصصة في السلوك العملي. فمصفوفة أعداد صحيحة صغيرة ومجموعة مفاتيح كبيرة متداخلة ليستا نمط العمل نفسه. تجنب الوعد بزمن استجابة ثابت عام للوصول إلى القاموس. وميّز أيضا السلوك المتوقع للتجزئة من الكلفة المستهلكة لتغيير السعة: قد يجتمعان في تنفيذ واحد، لكنهما يفسران مصدرين مختلفين لأداء يبدو متوسطا. اذكر النموذج المستخدم للخوارزمية كاملة.
لا تخلط الترتيب بالهوية
يفيد حفظ ترتيب الإدراج في القاموس بإصدارات Python المدعومة، لكنه لا يفرز قيم المجال ولا يحدد أي ظهور مكرر ينبغي أن يفوز. ولا ينبغي استخدام مجموعة لإنتاج ترتيب عرض محدد مطلوب دون خطوة ترتيب صريحة. وإذا تشاركت سجلات تسمية واحدة وكانت لها معرّفات مختلفة، فقد تستبدل خريطة مفتاحها التسمية وحدها سجلات مشروعة. اختر قائمة قيم تؤدي دور خريطة متعددة القيم، أو عدادا للتكرار، أو مفتاحا مركبا، بحسب المهمة. يظل الاستبدال الصامت قرارا دلاليا، حتى عندما تكون عملية القاموس نفسها صحيحة.
تحقّق من التعدد واشتراط اختلاف الموضعين
قارن two_sum_indices بمرجع يبحث بالقوة الشاملة على مصفوفات صغيرة تشمل السالب والصفر والتكرار والفراغ وغياب الحل. تحقّق من اختلاف الموضعين المعادين ووقوعهما ضمن الحدود ومساواة مجموع القيمتين للهدف، بدلا من فرض زوج اعتباطي واحد عند وجود عدة أزواج صحيحة. وإذا وُعدت سياسة اكتشاف معينة فاختبرها مستقلة. وفي خرائط التكرار اجمع جميع الأعداد وتأكد من مساواتها لطول المدخل. تكشف خصائص الحفظ والصلاحية هذه الاستبدال العرضي أو حذف التكرار. ولا تحتاج فحوص الصحة المحلية الآمنة إلى هجوم تصادم عشوائي أو خدمة خارجية أو اختبار تحميل.
الأخطاء الشائعة وإصلاحها
اقتران قيمة واحدة بنفسها
- لماذا يحدث؟
- أُدرجت القيمة الحالية قبل فحص مكملها.
- كيف تصلحه؟
- ابحث بين المواضع السابقة قبل إدراج القيمة الحالية.
- كيف تتجنب تكراره؟
- اختبر [3] و[3,3] بصورة منفصلة عندما يكون الهدف 6.
فقد مجموعة لأعداد مرات ظهور مطلوبة
- لماذا يحدث؟
- استُخدمت العضوية بدلا من حفظ تعدد مرات الظهور.
- كيف تصلحه؟
- استخدم خريطة تكرارات أو قوائم تحفظ مرات الظهور.
- كيف تتجنب تكراره؟
- قارن مجموع أعداد الظهور بطول المدخل.
الوعد بوصول تجزئة ثابت الزمن في الحالة الأسوأ
- لماذا يحدث؟
- أُهملت افتراضات الزمن المتوقع وكلفة المفتاح.
- كيف تصلحه؟
- اذكر شروط التحليل، واحتسب كلفتي التجزئة والمساواة.
- كيف تتجنب تكراره؟
- وثّق تمثيل المفتاح ونمط العمل.
اختبر فهمك
1. لماذا تعيد العينة الأخيرة لمسألة مجموع اثنين الزوج (1,2)، بدلا من (0,3)؟
اعرض الحل المشروح
يصل المسح إلى القيمة 7 عند الفهرس 2، ويجد مكملها 4 موجودا بالفعل عند الفهرس 1؛ لذلك يرجع قبل زيارة 9. كلا الزوجين صحيح لعقد يطلب إيجاد أي زوج. وإذا طُلب أصغر فهرسين في الترتيب المعجمي، فيجب تغيير الخوارزمية وبرهانها.
2. ماذا ينبغي استخدامه عندما يشترك سجلان في العنوان نفسه، ويجب الاحتفاظ بكليهما؟
اعرض الحل المشروح
استخدم هوية مستقرة للسجل مفتاحا إذا أردت البحث عن السجلات منفردة، أو اربط العنوان بقائمة عند التجميع حسب العنوان. يؤدي إسناد سجل واحد إلى كل عنوان إلى استبدال أحد الظهورين وتغيير المشكلة. اختر بناء على دلالة الاسترجاع، لا لمجرد سهولة الصياغة.
أهم ما تعلمته
- اختر المفتاح وفقا لعقد المساواة الفعلي
- تحقّق من التعدد واشتراط اختلاف الموضعين