الفرز الطوبولوجي يجيب عن ترتيب يحترم اعتماد المهام، لا عن زمن إنجازها. سنختار رسمًا موجهًا من ستة أسماء ونراجع ترتيبات متعددة وجولات جاهزية، ثم نضيف دورة لنفصل أعضاءها من المهام التي تنتظرها. الكود والنتائج أمثلة أصلية منفذة محليًا على بيانات مؤلفة.
الخلاصة السريعة
الفرز الطوبولوجي يرتب رؤوس رسم موجه بحيث يسبق كل متطلب المهمة التي تعتمد عليه. قد توجد ترتيبات متعددة، ولا يعني الترتيب أن العمل نُفذ بالفعل.
- في مثالنا A يسبق B و D، و B يسبق C، و C و D يسبقان E، بينما F معزول. الترتيب A,F,B,D,C,E صالح، لكنه ليس الوحيد.
- قاموس TopologicalSorter في Python يكتب لكل مهمة متطلباتها السابقة. الخانة B:{A}تعني أن A ينجز قبل B، لا أن B يسبق A.
- في الجولات المتزامنة المبسطة تكون مجموعات الجاهزية{A,F}ثم{B,D}ثم{C}ثم{E}. الجاهزية تعني زوال المتطلبات المسجلة، لا نهاية المهمة.
- إبلاغ done عن مهمة يؤكد للمنظم أنها عولجت؛ على الجهة التي تنفذ العمل التحقق من النجاح قبل ذلك. وجود اسم في get_ready لا ينفذ العمل تلقائيًا.
- في رسم ذي دورة A→B→C→A، قد يبقى D و E محجوبين بسببها دون أن يكونا جزءًا من الدورة. فهرس المتبقي ليس قائمة أعضاء دورة بالضرورة.
- يمكن أن تعمل F المعزولة حتى عند وجود دورة في جزء آخر. بعد إنهائها قد تتوقف الجاهزية مع بقاء خمس مهام غير مرتبة؛ لا نقرأ توقف التقدم على أنه إنجاز كامل.
- التكرار لنفس المتطلب يعامل كعلاقة واحدة في نموذج المجموعات، والمتطلب الذي لم يذكر كمفتاح يحتاج مراجعة معنى إضافته الضمنية في المكتبة.
- نثبت اتجاه الأسهم وكل أسماء المهام وعلاقاتها، ثم نفحص ترتيبًا مقترحًا على كل حافة. لا نستنتج مدة أو توازيًا فعليًا أو أولوية وحيدة من الرسم وحده.
ما الذي يحدده الفرز الطوبولوجي؟
يصف مرجع NIST الفرز الطوبولوجي بأنه ترتيب عناصر بحسب ترتيب جزئي، أي إن بعض الأزواج قد لا يكون بينهما شرط يقرر السابق منهما. وتوضح وثائق Python أن الترتيب الخطي يضع كل رأس قبل الرؤوس التي يخرج إليها سهم، وأن الترتيب الكامل يتطلب رسمًا موجهًا بلا دورات. سنطبق هذه المعاني على رسم أصلي صغير، ثم نراجع النتائج بكود محلي.
نمثل المهمة باسم، والعلاقة بشرط أن تنجز مهمة قبل أخرى. لا نحول المسافة بين صندوقين في الرسم إلى وقت انتظار، ولا نعطي المهمة الموجودة أعلى الصفحة أولوية لمجرد مكانها. المعلومات التي سنستعملها هي الرؤوس والأسهم المعلنة، مع تفسير ثابت لاتجاه كل سهم. إذا احتجنا مدة أو موردًا أو شرط نجاح، فهذه بيانات أخرى غير موجودة في ترتيب الاعتماد وحده.
التعريف لا يطلب وجود سهم بين كل زوج، ولا يطلب أن تتصل جميع الرؤوس بمسار واحد. قد تكون مهمة مستقلة عن بقية الرسم، وتظل جزءًا من القائمة التي ينبغي أن يحويها الترتيب الكامل. تحديد ما يدخل في مجموعة المهام قبل البحث عن ترتيب يمنع اختفاء عمل مستقل لم يظهر في أي علاقة من علاقات الاعتماد.
رسم مؤلف من ست مهام
نختار أسماء A و B و C و D و E و F. المهمة A سابقة للمهمتين B و D. المهمة B سابقة لـ C، والمهمتان C و D سابقتان لـ E. لا نضع أي سهم يدخل إلى F أو يخرج منها، فهي معزولة في هذا النموذج. لدينا ستة رؤوس وخمس حواف موجهة، وكل سهم يقرأ من المتطلب إلى المهمة التي تحتاجه.
يمكن أن تمثل الحروف أعمالًا في مثال تعليمي، لكننا لا ندعي أنها مخطط مشروع حقيقي أو أن علاقاتها شاملة لكل اعتماد محتمل. يكفي أن تكون العلاقات معلنة كي نستطيع فحص ترتيب لها. الرسم الرئيسي يوضح اتجاه الأسهم، ويضع F في صندوق مستقل دون حذفها من مجموعة الرؤوس. غياب اتصالها لا يجعلها اسمًا زائدًا خارج النموذج.
نميز كذلك المهمة السابقة مباشرةً من السابقة عبر مسار. لا يوجد سهم مباشر من A إلى C، لكن A يسبق B و B يسبق C، لذلك أي ترتيب صالح يضع A قبل C. أما B و D فلا يحدد الرسم علاقة سبق بينهما. هذا الاختلاف هو ما يسمح بتبديل موضعي بعض المهام، بينما يمنع تبديل أزواج أخرى حتى لو لم نر بينهما سهمًا مباشرًا.
قاموس المتطلبات: اتجاه القراءة مهم
نكتب في قاموس المثال A بقائمة فارغة، و B بمتطلب A، و C بمتطلب B، و D بمتطلب A، و E بمتطلبين C و D، و F بقائمة فارغة. في TopologicalSorter تصف القيم المتطلبات السابقة للمفتاح الذي نسميه، وفق الوثائق. لذلك فإن كتابة B مع A تصف سهمًا من A إلى B، وليس سهمًا من B إلى A.
يمكن مراجعة القاموس بتحويل كل متطلب إلى سهم، ثم مقارنة الأسهم مع الرسم. خانة E تنتج سهمين، من C ومن D إلى E. والخانتان A و F لا تنتجان سهمًا داخلًا لأن قائمة المتطلبات فارغة. هذه المراجعة الصغيرة تكشف قلب الاتجاه قبل أن ينتج البرنامج ترتيبًا لا يصف النموذج الذي قصدناه.
لا نخلط بين قاموس يعدد أبناء كل رأس وقاموس يعدد أسلافه. كلاهما تمثيل ممكن للرسم، لكن الواجهة التي نستخدمها تحتاج النوع الثاني. إذا كان الملف الذي وصلنا يعدد المهام التابعة لكل مهمة، نحوله صراحةً أو نختار كودًا يقبل ذلك العقد. أسماء الحقول واتجاهها جزء من معنى البيانات، ولا تصححه مكتبة الفرز من مظهر الحروف وحده.
أكثر من ترتيب صالح لا يعني تعارضًا
الترتيب A ثم F ثم B ثم D ثم C ثم E صالح؛A قبل B و D، و B قبل C، و C و D قبل E. ويمكن كتابة F ثم A ثم D ثم B ثم C ثم E ويظل صالحًا. تغير موضع F وموضع D بالنسبة إلى B، بينما بقيت كل علاقات السبق التي طلبها الرسم. لا نرفض الترتيب الثاني لمجرد أنه لا يطابق القائمة الأولى حرفًا بحرف.
لفحص أي ترتيب، نعطي كل اسم موضعًا، ثم نراجع أن موضع بداية كل سهم أصغر من موضع نهايته. يجب أيضًا أن تظهر كل الرؤوس مرة واحدة، دون غياب أو تكرار. ترتيب يضع A قبل E قد يبدو مناسبًا، لكنه ليس كافيًا إذا وضع E قبل D؛ نحتاج جميع الحواف لا علاقة واحدة اخترناها من الرسم.
في مثالنا، إذا تجاهلنا F مؤقتًا، توجد ثلاثة ترتيبات للمهام الخمس: بعد A نستطيع وضع B ثم C ثم D، أو B ثم D ثم C، أو D ثم B ثم C، وتبقى E أخيرة. يمكن إدخال F في أي واحد من ستة مواضع حول كل قائمة، فيصبح العدد 18 ترتيبًا صالحًا. نتحقق من هذا العدد محليًا بتعداد التباديل، ولا نعممه على رسم آخر بعد تغيير علاقة أو رأس.
جولات الجاهزية في نموذج متزامن
في البداية لا متطلبات سابقة لـ A ولـ F، فتكون مجموعة الجاهزية منهما. إذا اعتبرنا أن الجولة تعالج كل ما كان جاهزًا عند بدايتها، ثم تعلم جميع أسمائه منتهية، تتحرر B و D في الجولة التالية. بعد معالجة هاتين تتحرر C، وبعد C تتحرر E لأن D انتهت في الجولة السابقة. هكذا نحصل على أربع مجموعات متتابعة.
هذا وصف لجولات منطقية، لا حساب لأربع وحدات زمن ولا إثبات أن لدينا معالجين أو منفذين يعملان في الوقت نفسه. عدد عناصر مجموعة الجاهزية قد يتجاوز الموارد المتاحة. كما أن انتهاء مهمتين في الجولة نفسها فرض وضعناه في طريقة العرض، وليس حدثًا سجله برنامج على معدات فعلية.
يمكن جمع المجموعات إلى ترتيب خطي، مع اختيار ترتيب داخلي لأي مجموعة. المجموعة B و D لا تحمل شرطًا بين الاسمين، لذلك نختار أحدهما أولًا في القائمة دون تغيير اعتماد C على B أو اعتماد E على D. احتفظ بالفرق بين طبقة من رؤوس متاحة وبين جدول تنفيذ بزمن بدء ونهاية. الأول يصف العلاقات، والثاني يحتاج بيانات وقدرات إضافية.
كود تعليمي يحذف المتطلبات المكتملة
الكود التالي نموذج مستقل لجولات الجاهزية على أسماء نصية قابلة للترتيب. ننسخ مجموعات المتطلبات حتى لا نغير مدخلات المثال. في كل دورة نختار الأسماء التي لم يبق لها متطلب، ثم نحذفها ونزيلها من متطلبات البقية. إذا بقيت أسماء دون أي اسم جاهز، نعيد الطبقات التي استطعنا استخراجها مع قائمة المتبقي.
اختيار ترتيب الأسماء داخل الطبقة يجعل عرضنا قابلًا للتكرار، لكنه ليس جزءًا ضروريًا من تعريف الفرز الطوبولوجي. كما أن مسح جميع المتطلبات في كل جولة طريقة تعليمية بسيطة؛ لا ندعي أنها تنفيذ محسّن من حيث الزمن أو أنها تستخدم البنية الداخلية للمكتبة. سنراجع صحة النتائج على رسمنا وحالات صغيرة مستقلة.
والقائمة الثانية التي يرجعها النموذج تسمى المتبقي، لا أعضاء الدورة. ربما تضم رؤوسًا في دورة ورؤوسًا تعتمد على تلك الدورة. نحتاج تحليلًا آخر إذا أردنا فصل المجموعتين أو استخراج جميع الدورات. توضيح اسم النتيجة منذ تعريف الدالة يمنع أن نعطي القارئ تشخيصًا أقوى مما حسبه الكود بالفعل.
def readiness_layers(prerequisites):
waiting = {node: set(deps) for node, deps in prerequisites.items()}
names = set(waiting)
for deps in waiting.values():
names.update(deps)
for node in names:
waiting.setdefault(node, set())
layers = []
while waiting:
ready = sorted(node for node, deps in waiting.items() if not deps)
if not ready:
return layers, sorted(waiting)
layers.append(ready)
for node in ready:
del waiting[node]
for deps in waiting.values():
deps.difference_update(ready)
return layers, []
تقدم المنظم لا ينفذ المهام
في تجربة محلية بأسماء المثال، نستعمل TopologicalSorter ثم prepare قبل طلب الجاهزية. أول طلب get_ready يعيد A و F. مجرد استلام الاسمين لا ينفذ العمل الذي قد تمثلانه. إذا طلبنا الجاهزية مرة أخرى دون إبلاغ انتهاء، لا نحصل على نسختين جديدتين من المهمة نفسها. نحتفظ بالأسماء المرسلة للعمل وبحالته، ثم نبلغ done لما اكتمل وفق معيارنا الخارجي.
بعد إبلاغ done عن A، تتحرر B و D، حتى لو كانت F لم تنته بعد. لا تعتمد هاتان على F في الرسم. وبعد إتمام B تتحرر C، ثم لا تتحرر E إلا بعد انتهاء C و D معًا. هذه متابعة لحالة منظم في بيانات مؤلفة، وليست سجل تنفيذ لمهام حقيقية. سننفذ استدعاءات المثال محليًا ونحفظ نتائجها ضمن المراجعة.
تضع الجهة المنفذة تأكيد النجاح الذي يتطلبه تطبيقه قبل أن يعلن done عن الاسم. المكتبة لا تعرف من اسم A هل كتابة ملف نجحت أو هل نتيجة خارجية صحيحة. لا نحول جاهزية أو خروج اسم من طابور إلى شهادة إنجاز. الترتيب يضبط من يجوز أن يبدأ بحسب الاعتمادات المسجلة، أما صحة العمل الذي يمثل الاسم فمسؤولية منفصلة في النموذج.
سجل حالة يفرق الجاهز من الجاري والمنتهي
يمكن تسجيل ثلاثة أعمدة منطقية: ما صار جاهزًا ولم يرسل، وما أرسل للعمل ولم يعلن منتهيًا، وما أعلن منتهيًا. في مثال A و F، ينتقل الاسمان من مجموعة جاهزية إلى مجموعة جارية عند استلامهما. وإذا أنهينا A وتركنا F جارية، يستطيع المنظم إرسال B و D. لا تتطابق مجموعة الجاري مع مجموعة المهام التي لها أسلافغير منتهية؛ كل مجموعة تحتاج تعريفًا مستقلًا.
قد ننهي B ثم C قبل D، فتظل E منتظرة D. وإذا أنهينا D بعد ذلك، تصبح E جاهزة. ثم بعد إنهاء E تظل F جارية إن لم نبلغ انتهاءها بعد، رغم أن سلسلة A إلى E اكتملت. يمكن أن يبقى is_active صحيحًا لهذا السبب في تجربة المنظم. نراجع الأسماء التي خرجت للمعالجة مقابل الأسماء التي أبلغناها منتهية، لا شكل الرسم وحده.
هذا السجل يفيد في فهم الاستدعاءات، لكنه لا يشترط بنية طوابير أو عمليات بعينها. لا نقيس توازيًا فعليًا، ولا نفترض أن استدعاء done يمكن تقديمه لمهمة لم ترجع من get_ready. نثبت معيار الإبلاغ وحالة الأسماء، ثم نراجع أي انتقال غير متوقع. كلمة نشط في واجهة منظم تحتاج عقدها، وليست وصفًا عامًا لكل ما نعتقد أنه يجب أن ينجز.
الدورة تجعل ترتيبًا كاملًا مستحيلًا
نعدل الرسم ليكون A سابقًا لـ B، و B سابقًا لـ C، و C سابقًا لـ A. لو افترضنا ترتيبًا كاملًا، لاحتجنا A قبل B قبل C قبل A، وهذا يطلب من A أن يسبق نفسه عبر سلسلة شروط. لا توجد قائمة خطية تحقق العلاقات الثلاث معًا. تغيير اسم ترتيب أو اختيار مهمة أولى اعتباطيًا لا يزيل التعارض الموجود في العلاقات.
نضع D بعد A، و E بعد C و D، ونبقي F معزولة. في الكود التعليمي تبدأ الجاهزية بـ F فقط. بعد إزالة F لا يبقى اسم دون متطلب، فتتوقف الطبقات ويعود المتبقي A و B و C و D و E. الرسم الداخلي يميز الدورة الثلاثية عن المهمتين الواقعتين بعدها، كي لا نسمي كل متبقٍ عضوًا في دورة.
إذا أردت إزالة التعارض، تحتاج إلى مراجعة معنى علاقة من العلاقات في النموذج أو تعديل تعريف المهام. لا نقدم حذف سهم بوصفه إصلاحًا آليًا صحيحًا؛ ربما يمثل شرطًا فعليًا لا يمكن إسقاطه. مثالنا يثبت أن العلاقات المعلنة تمنع ترتيبًا كاملًا، لكنه لا يقرر أي علاقة ينبغي تغييرها في مشروع لم نعرف بياناته.

المحجوب ليس دائمًا جزءًا من الدورة
في الرسم المعدل،A و B و C أعضاء الدورة المباشرة التي اخترناها. أما D فلا يوجد مسار يعيد منها إلى نفسها؛ هي تعتمد على A المحجوبة. والمهمة E تنتظر C و D، فتظل محجوبة كذلك. لذلك تضم قائمة المتبقي خمسة أسماء مع أن دورتنا المعلنة من ثلاثة أسماء فقط. عدد العناصر الباقية لا يقيس طول الدورة.
هذا الفرق يساعد عند قراءة تشخيص. إذا أعطى برنامج قائمة أسماء لم يستطع وضعها في الترتيب، فلا نعرضها تلقائيًا على أنها دورة واحدة متصلة. نحتاج أن نحدد هل حسب البرنامج رؤوس دورة أم جميع ما بقي ينتظرها. وإذا عاد مسار يغلق على نفسه، نراجع كل سهم في ذلك المسار بدل الاعتماد على الأسماء وحدها.
وتوثق CycleError في Python مثالًا لدورة مكتشفة، وقد لا يمثل كل الدورات إذا وجدت أكثر من واحدة. لا نوسع تشخيصًا واحدًا إلى حصر كامل لمشكلة أكبر. نموذجنا يذكر دورة بعينها ويفصل عنها ذيلين محجوبين، ويختبر ذلك على الرسم المحدد. الرسم العام الذي يحوي دورات متعددة أو اعتمادًا عابرًا يحتاج إلى تحليل يعلن نطاقه ونتيجته بدقة.
بعد خطأ الدورة قد توجد مهام متاحة
في تجربة مكتبة graphlib على الرسم المعدل، prepare يكشف دورة ويرفع CycleError، لكن يمكن طلب المهام المتاحة التي لا تسدها الدورة. في مثالنا تبقى F بلا متطلبات، فتعود من get_ready. إذا أبلغنا done عن F، لا تظهر مهام جديدة، لأن A و B و C في انتظار دائري، و D و E تنتظران أجزاء ذلك الاعتماد.
عندئذ يتوقف التقدم في المنظم، مع أن خمسة أسماء لم تعالج. لهذا لا نفسر False من is_active بعد حالة دورة بوصفه إثباتًا أن كل الرسم اكتمل. نفرق بين لا مزيد من تقدم ممكن في الحالة المعطاة وبين انتهت جميع المهام المقصودة. المقارنة تحتاج أيضًا قائمة الأسماء الكاملة وما أبلغناه منتهيًا، لا قيمة منطقية وحيدة منفصلة عن السياق.
لا نستخدم هذه الخاصية لتجاوز CycleError ثم إعلان نجاح تشغيل كامل. يمكن وصف الجزء الذي أمكن تقدمه، وتسجيل ما بقي محجوبًا وسبب ذلك وفق المثال. يحدد التطبيق هل إنجاز جزء مستقل مفيد أم يحتاج إلى إيقاف العملية كلها، لكن هذا قرار لا يحسمه ترتيب الرؤوس وحده. هنا نراجع سلوكًا محليًا مؤلفًا ونبقي حالة الرسم غير المكتمل واضحة.
الرأس المعزول والمتطلب الذي يظهر ضمن قيمة
تظهر F صراحةً في قاموسنا مع مجموعة فارغة، لذلك لا تختفي رغم عدم ظهورها في أي سهم. إذا حذفت مفتاح F من القاموس ولم تذكرها ضمن متطلب آخر، فلن يعرف النموذج أنك تقصد مهمة بهذا الاسم. ليس من الممكن استنتاج جميع المهام المقصودة من العلاقات وحدها إذا كانت بعض المهام مستقلة ولا تحمل أي علاقة.
وفي مثال آخر صغير، نكتب B تحتاج A ونترك A غير مذكورة كمفتاح. توثق الواجهة أن اسمًا ظهر كمتطلب يضاف تلقائيًا دون متطلبات خاصة به. الكود التعليمي يفعل ذلك أيضًا عند جمع الأسماء من القيم. النتيجة ترتب A قبل B، لكنها لا تثبت أن متطلبات A في ملف واقعي كانت فارغة؛ قد يكون سجلها ناقصًا في المدخلات.
إذا كان عقد البيانات لديك يشترط سجلًا صريحًا لكل مهمة، فتحقق من هذا الشرط قبل بناء الرسم بدل اعتماد الإضافة الضمنية كشفًا لصحة الملف. في أمثلتنا نعلن الأسماء والعلاقات كاملة، ونميز تجربة اسم ضمن قيمة عن تجربة رأس معزول مجهول للنموذج. اسم ظهر في تعريف شيء آخر ليس شهادة بأن كل معلوماته أدرجت.
التكرار والحافة الزائدة: حدد أثر كل منهما
نكتب E تحتاج C و D، ثم نكرر C مرة أخرى في قائمة المتطلبات. عند تحويل المتطلبات إلى مجموعة تبقى العلاقتان نفسهما، ولا نحتاج إنهاء C مرتين كي تتحرر E. توضح وثائق add أن جمع الاعتمادات المتكررة يأخذ اتحادها. النموذج يمثل شرط سبق لكل اسم، لا عددًا من تذاكر المعالجة التي تحمل الاسم نفسه.
أما إضافة سهم جديد من B إلى D فتغير الرسم. صار D ينتظر B بدل أن يكون مستقلًا عنه بعد A. قد يقل عدد الترتيبات الصالحة، وقد تتغير جولات الجاهزية، لكن النتيجة تحتاج فحصًا للعلاقات الجديدة. لا نسمي كل إضافة تغييرًا شكليًا مثل تكرار السهم نفسه. الفرق بين نسختين من علاقة موجودة وعلاقة جديدة جوهري في معنى القاموس.
ويمكن أن يكون سهم مباشر زائدًا من جهة ما يفرضه المسار، مثل A إلى C في الرسم الأصلي، لأن A قبل B قبل C يطلب A قبل C أصلًا. إضافة هذا السهم لا تغير مجموعة الترتيبات الصالحة في مثالنا. نراجع ذلك محليًا، ولا نحذف أي سهم في بيانات تطبيق بناءً على شكله دون فهم معناه. ما يبدو زائدًا في شرط الترتيب قد يحمل تفسيرًا آخر خارج نموذجنا البسيط.
تحقق من النتيجة على الرؤوس والحواف
نراجع الترتيب المقترح بثلاث خطوات: أولًا نتحقق أن عدد الأسماء يساوي عدد الرؤوس، ثم أن كل اسم يظهر مرة واحدة وينتمي إلى المجموعة، ثم أن موضع كل متطلب أصغر من موضع المهمة التابعة له. في نموذجنا يمكن فحص الحواف الخمس صراحةً. قائمة ناقصة F قد تحقق الحواف كلها، لكنها تفشل في شرط احتواء كل الرؤوس.
نقارن كذلك الكود التعليمي بنتيجة static_order على بيانات المثال، مع السماح بترتيب مختلف إذا حقق الشروط. لا نقارن قائمتين بالمساواة الحرفية ثم نعلن فشل إحداهما، لأن الترتيب ليس وحيدًا. يمكن تعداد كل التباديل الستية لتأكيد عدد 18، وفحص رسوم صغيرة أخرى باختبار مباشر لحوافها. هذه مراجعات محددة لا ادعاء بفحص كل رسم ممكن.
وفي حالات الدورة، نحتفظ بالتوقف والمتبقي ونقارن بحقيقة وجود ترتيب كامل من عدمه. الرسم الفارغ يملك قائمة ترتيب فارغة، والرأس المعزول الواحد يعود وحده، والاعتماد الذاتي A على A دورة تمنع معالجته في هذا النموذج. الحالات الصغيرة تكشف ما إذا كنا حفظنا الأسماء وشروطها، بينما تفسير سبب كل نتيجة يظل مهمًا إلى جانب رقم أو قائمة نجحت في تجربة.
الترتيب لا يحدد زمنًا أو أولوية تشغيل
التقدير الزمني يحتاج مدد المهام والموارد وشروط التنفيذ، وهي غير موجودة في رسمنا. يمكن أن تكون B قصيرة و D طويلة، أو العكس، دون أن يتغير أي سهم. لذلك لا نعلن أن إحدى القوائم الثماني عشرة أسرع من الأخرى من معلومات السبق وحدها. كما أن وجود مهمة معزولة F لا يعني أنها بلا عمل أو أن زمنها صفر.
وإذا كانت لديك سياسة تختار الأسماء أبجديًا أو حسب أولوية معلنة عند تعادل الجاهزية، فاكتبها بوصفها سياسة إضافية. الكود التعليمي رتب أسماء الطبقة لكي يعيد العرض نفسه، لكنه لم يستنتج أولوية من الاعتمادات. وثائق static_order تذكر إمكان تأثر ترتيب المجموعات المستقلة بترتيب إضافتها، لذلك نراجع صحة الشروط بدل توقع قائمة حرفية واحدة دون عقد يضمنها.
هذا يفصل خطة صالحة عن تنفيذ مكتمل وعن اختيار خطة أفضل لغرض معين. تستطيع استعمال نتيجة الفرز مدخلًا لخطوة أخرى، لكن عليك إضافة البيانات التي تحتاجها تلك الخطوة. نحتفظ بمعنى الرؤوس والأسهم ومجال النتيجة قبل ربطها بقرار يتعلق بموارد أو أوقات لم نحسبها. المثال يشرح الاعتماد المنطقي، ولا يوصي بإدارة مشروع حقيقي من رسم ناقص.
قائمة مراجعة قبل استعمال ترتيب المهام
اجمع أسماء المهام كلها، بما فيها المعزولة، وحدد اتجاه السهم: من المتطلب السابق إلى المهمة التابعة. إذا استعملت قاموس TopologicalSorter، اكتب الأسلاف في قيمة كل مفتاح. افحص التكرارات والسجلات الناقصة وفق عقد بياناتك، ثم حدد هل المطلوب ترتيب كامل أم طبقات جاهزية أم وصف جزء أمكن تقدمه بعد تعارض.
راجع كل رأس وكل حافة في الترتيب، واسمح ببدائل صحيحة إذا لم تفرض أولوية إضافية. ميز وصول اسم من get_ready عن انتهاء عمله، وسجل ما عولج قبل done. وفي حالة الدورة، لا تحول قائمة المتبقي إلى قائمة أعضاء دورة دون تحليل، ولا تحول توقف التقدم إلى إنجاز كامل. اذكر كل فرض عن ثبات الرسم ومعالجة الجولات.
وأخيرًا، احتفظ بالنموذج والأرقام والنتائج معًا. رسومنا وكودنا بيانات مؤلفة نفذت محليًا للمراجعة، وليست سجل أعمال حقيقية. يمكن إعادة تتبع الجولات الأربع للرسم الأول، ثم مقارنة F المتاحة بالرؤوس الخمسة المحجوبة في الرسم الثاني. هكذا يرتبط تعريف الفرز وسلوك الواجهة بمخرجات واضحة، وتبقى المعلومات التي لا يحددها الرسم ظاهرة للقارئ.
ولمعنى الإجراء مقارنةً بمخرج تعلم، اقرأ الخوارزمية والنموذج في تعلم الآلة.
المصادر ومتابعة القراءة
- Python3.14: عقدTopologicalSorter والمتطلبات والجاهزية والدورات (يفتح في نافذة جديدة)docs.python.org
- NIST: تعريف الفرز الطوبولوجي والترتيب الجزئي (يفتح في نافذة جديدة)xlinux.nist.gov
أُعدّ هذا المقال بصياغة عربية أصلية بالاستناد إلى المصادر أعلاه، وهو مدخل تمهيدي إلى الموضوع. اقرأ منهجية المحتوى وحدوده.
