إنتروسورت

يُعدّ فرز Introsort، أو الفرز الاستبطاني، خوارزمية فرز هجينة تجمع بين الأداء المتوسط ​​السريع والأداء الأمثل (تقاربًا) في أسوأ الحالات. تبدأ هذه الخوارزمية بفرز Quicksort ، ثم تنتقل إلى فرز Heapsort عندما يتجاوز عمق الاستدعاء مستوىً مُحددًا بناءً على ( لوغاريتم ) عدد العناصر المراد فرزها، وأخيرًا تنتقل إلى فرز الإدراج عندما يقل عدد العناصر عن حدٍّ معين. يجمع هذا الأسلوب بين مزايا الخوارزميات الثلاث، مع أداء عملي يُضاهي Quicksort على مجموعات البيانات النموذجية، ووقت تشغيل في أسوأ الحالات O ( n log n ) بفضل فرز Heapsort. وبما أن الخوارزميات الثلاث المستخدمة هي خوارزميات فرز مقارنة ، فإن Introsort تُصنّف أيضًا ضمن خوارزميات فرز المقارنة.

ابتكر ديفيد موسر خوارزمية Introsort في بحثه المنشور عام 1997 ، حيث قدم أيضًا خوارزمية introselect ، وهي خوارزمية اختيار هجينة تعتمد على خوارزمية quickselect (وهي نسخة معدلة من quicksort)، وتعتمد في حال عدم تحقق الشرط على وسيط الوسائط ، مما يوفر تعقيدًا خطيًا في أسوأ الحالات، وهو الأمثل. وقد طُرحت كلتا الخوارزميتين بهدف توفير خوارزميات عامة لمكتبة C++ القياسية ، تتميز بأداء متوسط ​​سريع وأداء مثالي في أسوأ الحالات، مما يسمح بتقليل متطلبات الأداء. [ 1 ] تُعدّ خوارزمية Introsort خوارزميةً تُنفّذ في مكانها ، وهي غير مستقرة .

الشفرة الزائفة

إذا توفر تطبيق لخوارزمية فرز الكومة ووظائف تقسيم من النوع الذي نوقش في مقالة الفرز السريع ، فيمكن وصف الفرز الداخلي بإيجاز كما يلي:

إجراء الفرز (A: مصفوفة): أقصى عمق ← ⌊log 2 (طول(A))⌋ × 2 introsort(A, maxdepth) الإجراء introsort(A, maxdepth): n ← طول(A) إذا كان n < 16: فرز الإدراج (A) وإلا إذا كانت قيمة maxdepth تساوي 0: heapsort(A) آخر : p ← partition(A) // بافتراض أن هذه الدالة تقوم بتحديد المحور، فإن p هو الموضع النهائي للمحور introsort(A[1:p-1], maxdepth - 1) introsort(A[p+1:n], maxdepth - 1)

العامل 2 في العمق الأقصى اختياري، ويمكن ضبطه لتحقيق الأداء الأمثل. يرمز A [ i : j ] إلى شريحة المصفوفة التي تضم العناصر من i إلى بما في ذلك A [ i ] و A [ j ] . ويُفترض أن تبدأ الفهارس من 1 (العنصر الأول في المصفوفة A هو A[1] ).

تحليل

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

أفاد موسر أن زمن تشغيل خوارزمية الفرز الداخلي (introsort) على تسلسل قاتل متوسط ​​من 100,000 عنصر كان 1/200 من زمن تشغيل خوارزمية الفرز السريع المتوسط ​​من 3. كما درس موسر تأثير فرز سيدجويك الصغير المؤجل على ذاكرة التخزين المؤقت ، حيث يتم فرز النطاقات الصغيرة في النهاية في تمريرة واحدة من فرز الإدراج . وذكر أن ذلك قد يضاعف عدد حالات عدم العثور على البيانات في ذاكرة التخزين المؤقت، لكن أداءها مع قوائم الانتظار ذات النهايتين كان أفضل بكثير، ويجب الاحتفاظ بها في مكتبات القوالب، ويعود ذلك جزئيًا إلى أن الفائدة المرجوة من إجراء الفرز فورًا في الحالات الأخرى لم تكن كبيرة.

التطبيقات

يتم استخدام Introsort أو أحد المتغيرات في عدد من وظائف الفرز في المكتبة القياسية ، بما في ذلك بعض تطبيقات الفرز في لغة C++ .

يستخدم تطبيق stl_algo.h الخاص بمكتبة القوالب القياسية SGI C++ لشهر يونيو 2000 لفرز غير مستقر نهج Musser introsort مع عمق التكرار للتبديل إلى فرز الكومة الذي يتم تمريره كمعامل، واختيار محور الوسيط 3، وتمرير فرز الإدخال النهائي Knuth للأقسام الأصغر من 16.

مكتبة GNU Standard C++ مشابهة: تستخدم introsort بعمق أقصى يبلغ 2×log 2 n ، متبوعًا بفرز الإدراج على الأقسام الأصغر من 16. [ 2 ]

تستخدم مكتبة libc++ في LLVM أيضًا خوارزمية الفرز الداخلي (introsort) بعمق أقصى يبلغ 2×log₂n ، إلا أن حد حجم الفرز بالإدراج يختلف باختلاف أنواع البيانات (30 إذا كانت عمليات التبديل بسيطة، و6 في غير ذلك). كما تُعالج المصفوفات التي يصل حجمها إلى 5 عناصر بشكل منفصل. [ 3 ] يقدم كوتينين (2022) نظرة عامة على بعض التغييرات التي أجرتها LLVM، مع التركيز على إصلاح مشكلة التربيعية في عام 2022. [ 4 ]

تستخدم مكتبة فئات إطار عمل Microsoft .NET ، بدءًا من الإصدار 4.5 (2012)، خوارزمية الفرز الداخلي بدلاً من خوارزمية الفرز السريع البسيطة. [ 5 ]

تستخدم لغة Go تعديلًا لخوارزمية فرز الإدخال: فبالنسبة للشرائح التي تحتوي على 12 عنصرًا أو أقل، تستخدم فرز الإدراج ، أما بالنسبة للشرائح الأكبر حجمًا، فتستخدم فرزًا سريعًا يتغلب على الأنماط، بالإضافة إلى وسيطة الوسائط الثلاثة الأكثر تطورًا لاختيار المحور. [ 6 ] قبل الإصدار 1.19، كانت تستخدم فرز شل للشرائح الصغيرة.

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

المتغيرات

فرز pdqsort

خوارزمية الفرز السريع التي تهزم النمط (pdqsort) هي نوع من أنواع خوارزمية الفرز الداخلي التي طورها أورسون بيترز، وتتضمن التحسينات التالية: [ 8 ]

  • التمحور باستخدام الوسيط الثلاثي،
  • تقنية التقسيم "BlockQuicksort" للتخفيف من عقوبات التنبؤ الخاطئ للفروع،
  • أداء زمني خطي لأنماط إدخال معينة ( فرز تكيفي
  • استخدم خلط العناصر في الحالات السيئة قبل تجربة فرز الكومة الأبطأ.
  • تحسين القدرة على التكيف مع المدخلات ذات العدد القليل من العناصر

يتم استخدام Pdqsort بواسطة Boost ، [ 9 ] و GAP ، و Rust ، [ 10 ] و Zig . [ 11 ]

فرز التدفق

fluxsort هو نسخة مستقرة من introsort تتضمن التحسينات التالية: [ 12 ]

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

تم اعتماد التحسينات التي أدخلها كل من خوارزمية fluxsort ونسختها غير المستقرة crumsort في خوارزميات crumsort-rs وglidesort وipnsort وdriftsort. وقد بلغ التحسن الإجمالي في الأداء على المدخلات العشوائية مقارنةً بخوارزمية pdqsort حوالي 50%. [ 13 ] [ 14 ] [ 15 ] [ 16 ] [ 17 ]

مراجع

  1. " الخوارزميات العامة ديفيد موسر
  2. توثيق مكتبة libstdc++: خوارزميات الفرز
  3. شفرة مصدر libc++: فرز
  4. كوتينين، دانيلا (20 أبريل 2022). "تغيير std::sort على نطاق جوجل وما بعده" . Experimental chill .
  5. دالة فرز المصفوفة (المصفوفة)
  6. شفرة المصدر لـ Go 1.20.3
  7. شفرة مصدر Java 14
  8. بيترز، أورسون آر إل (2021). "orlp/pdqsort: خوارزمية فرز سريع تتغلب على الأنماط" . GitHub . arXiv : 2106.05123 .
  9. لاميتش، بيتر (2020). تنفيذ فعال ومُتحقق منه لخوارزميتي Introsort وPdqsort . المؤتمر الدولي المشترك للاستدلال الآلي 2020: الاستدلال الآلي. المجلد 12167. الصفحات 307-323 . doi : 10.1007/978-3-030-51054-1_18 .  
  10. "slice.sort_unstable(&mut self)" . Rust . تعتمد الخوارزمية الحالية على خوارزمية الفرز السريع التي تتغلب على الأنماط، والتي طورها أورسون بيترز، حيث تجمع بين سرعة الحالة المتوسطة لخوارزمية الفرز السريع العشوائي وسرعة أسوأ حالة لخوارزمية فرز الكومة، مع تحقيق زمن خطي على الشرائح ذات أنماط معينة. تستخدم الخوارزمية بعض العشوائية لتجنب الحالات الشاذة، ولكن مع قيمة ابتدائية ثابتة لضمان سلوك حتمي دائمًا.
  11. "pdq.zig" . GitHub . عدد الأقسام غير المتوازنة المسموح بها قبل التحويل إلى فرز الكومة.
  12. ^ فان دن هوفن، إيجور (2021). "فرز التدفق" . جيثب .
  13. ^ فان دن هوفن ، إيجور (2022). "كرمسورت" . جيثب .
  14. ^ تيسيليس ، دراجوش (2022). "crumsort-rs" . جيثب .
  15. بيترز، أورسون (2023). "Glidesort: فرز مستقر تكيفي فعال في الذاكرة على الأجهزة الحديثة" .
  16. بيرغدول، لوكاس (2024). "ipnsort: تنفيذ فرز غير مستقر فعال وعام وقوي" .
  17. بيرغدول، لوكاس (2024). "driftsort: تنفيذ فرز مستقر فعال وعام وقوي" .

عام