فرز سريع
خوارزمية الفرز السريع (Quicksort) هي خوارزمية فرز فعّالة وعامة الأغراض . طوّرها عالم الحاسوب البريطاني توني هوار عام 1959 [ 1 ] [ 2 ] ونُشرت عام 1961. [ 3 ] ولا تزال تُستخدم على نطاق واسع في عمليات الفرز. وبشكل عام، تُعدّ أسرع قليلاً من خوارزميتي الفرز بالدمج والفرز بالكومة (Heapsort) للبيانات العشوائية، وخاصةً مع التوزيعات الكبيرة. [ 4 ]
خوارزمية الفرز السريع هي خوارزمية فرق تسد . تعمل هذه الخوارزمية عن طريق اختيار عنصر "محوري" من المصفوفة وتقسيم العناصر الأخرى إلى مصفوفتين فرعيتين، بناءً على ما إذا كانت أصغر من العنصر المحوري أو أكبر منه. ولهذا السبب، تُسمى أحيانًا فرز التبادل التقسيمي . [ 5 ] ثم تُفرز المصفوفات الفرعية بشكل متكرر . يمكن إجراء هذه العملية في مكانها ، مما يتطلب مقدارًا إضافيًا بسيطًا من الذاكرة لتنفيذ الفرز.
خوارزمية الفرز السريع هي خوارزمية فرز مقارنة ، أي أنها تستطيع فرز عناصر من أي نوع مُعرَّف لها علاقة "أصغر من" (أو ترتيب كلي ). وهي خوارزمية فرز قائمة على المقارنة، حيث يتم تبديل العنصرين a و b فقط في حال تم الحصول على ترتيبهما النسبي في الإغلاق المتعدي لنتائج المقارنة السابقة. معظم تطبيقات خوارزمية الفرز السريع غير مستقرة ، أي أن الترتيب النسبي للعناصر المتساوية في الترتيب لا يُحفظ.
يُظهر التحليل الرياضي لخوارزمية الفرز السريع أن الخوارزمية تستغرق في المتوسط ...مقارنات لفرز n عنصرًا. في أسوأ الأحوال ، فإنه يجعلالمقارنات.
تاريخ
طُوِّرت خوارزمية الفرز السريع عام 1959 على يد توني هوار أثناء دراسته كطالب زائر في جامعة موسكو الحكومية . في ذلك الوقت، كان هوار يعمل على مشروع ترجمة آلية لصالح المختبر الفيزيائي الوطني . وكجزء من عملية الترجمة، كان عليه فرز الكلمات في الجمل الروسية قبل البحث عنها في قاموس روسي-إنجليزي، مُرتب أبجديًا على شريط مغناطيسي . [ 6 ] بعد أن أدرك أن فكرته الأولى، فرز الإدراج ، ستكون بطيئة، توصل إلى فكرة جديدة. كتب جزء التقسيم بلغة ميركوري أوتوكود ، لكنه واجه صعوبة في التعامل مع قائمة المقاطع غير المُفرزة. عند عودته إلى إنجلترا، طُلب منه كتابة كود لخوارزمية فرز شيل . ذكر هوار لرئيسه أنه يعرف خوارزمية أسرع، فراهنه رئيسه بستة بنسات على أنه لا يعرفها. في النهاية، اعترف رئيسه بخسارته الرهان. نشر هوار ورقة بحثية حول خوارزميته، تتضمن تحليلًا نظريًا، في مجلة الكمبيوتر، المجلد 5، العدد 1، عام 1962، الصفحات 10-16 . لاحقًا، تعرّف هوار على لغة ALGOL وقدرتها على الاستدعاء الذاتي، مما مكّنه من نشر نسخة محسّنة من الخوارزمية بلغة ALGOL في مجلة Communications of the Association for Computing Machinery ، وهي المجلة الرائدة في علوم الحاسوب آنذاك. [ 3 ] [ 7 ] نُشر كود ALGOL في مجلة Communications of the ACM (CACM)، المجلد 4، العدد 7، يوليو 1961، صفحة 321، الخوارزمية 63: التقسيم والخوارزمية 64: الفرز السريع .
حظيت خوارزمية الفرز السريع بانتشار واسع، حيث ظهرت، على سبيل المثال، في نظام يونكس كدالة فرز افتراضية في المكتبة. ومن ثم، فقد أُطلق اسمها على الدالة الفرعية qsort في مكتبة لغة C القياسية [ 8 ] ، وعلى التنفيذ المرجعي للغة جافا .
تُعتبر أطروحة الدكتوراه التي قدمها روبرت سيدجويك عام 1975 علامة فارقة في دراسة خوارزمية الفرز السريع، حيث حلّ فيها العديد من المشكلات العالقة المتعلقة بتحليل مخططات اختيار المحور المختلفة، بما في ذلك فرز العينات ، والتقسيم التكيفي لفان إمدن [ 9 ] ، بالإضافة إلى اشتقاق العدد المتوقع للمقارنات والتبديلات. [ 8 ] وفي عام 1993، أدخل جون بنتلي ودوغ ماكلروي تحسينات متنوعة لاستخدامها في مكتبات البرمجة، بما في ذلك تقنية للتعامل مع العناصر المتساوية، ومخطط محور يُعرف باسم الوسيط الزائف للتسعة، حيث تُقسّم عينة من تسعة عناصر إلى مجموعات من ثلاثة، ثم يُختار وسيط الوسائط الثلاثة من المجموعات الثلاث. [ 8 ] وصف بنتلي مخطط تقسيم آخر أبسط وأكثر إيجازًا في كتابه "لآلئ البرمجة" ، ونسبه إلى نيكو لوموتو . لاحقًا، كتب بنتلي أنه استخدم نسخة هوار لسنوات، لكنه لم يفهمها تمامًا، بينما كانت نسخة لوموتو بسيطة بما يكفي لإثبات صحتها. [ 10 ] وصف بنتلي خوارزمية الفرز السريع بأنها "أجمل كود كتبته على الإطلاق" في المقال نفسه. كما شاع استخدام مخطط تقسيم لوموتو بفضل كتاب " مقدمة في الخوارزميات" ، على الرغم من أنه أقل كفاءة من مخطط هوار لأنه يُجري عمليات تبديل أكثر بثلاث مرات في المتوسط، ويتدهور وقت تشغيله إلى O ( n² ) عندما تكون جميع العناصر متساوية. [ 11 ] وفي عام 1998، أنتج ماكلروي دالة مضادة للفرز السريع ( aqsort )، والتي تدفع حتى نسخته المعدلة من الفرز السريع لعام 1993 إلى سلوك تربيعي باستمرار من خلال إنتاج بيانات معادية أثناء التشغيل. [ 12 ]
الخوارزمية

خوارزمية الفرز السريع هي نوع من خوارزميات فرق تسد لفرز المصفوفات، وتعتمد على عملية تقسيم. قد تختلف تفاصيل هذا التقسيم بعض الشيء، لذا فإن الفرز السريع في الواقع عبارة عن مجموعة من الخوارزميات المترابطة. عند تطبيق التقسيم على نطاق يحتوي على عنصرين على الأقل، ينتج عنه تقسيم إلى نطاقين فرعيين متتاليين غير فارغين، بحيث لا يكون أي عنصر في النطاق الفرعي الأول أكبر من أي عنصر في النطاق الفرعي الثاني. بعد تطبيق هذا التقسيم، تقوم خوارزمية الفرز السريع بفرز النطاقين الفرعيين بشكل متكرر، ربما بعد استبعاد عنصر عند نقطة التقسيم معروف أنه موجود بالفعل في موقعه النهائي. نظرًا لطبيعتها المتكررة، يجب صياغة خوارزمية الفرز السريع (مثل عملية التقسيم) بحيث يمكن استدعاؤها لنطاق داخل مصفوفة أكبر، حتى لو كان الهدف النهائي هو فرز مصفوفة كاملة. خطوات الفرز السريع الموضعي هي:
- إذا كان النطاق يحتوي على أقل من عنصرين، فقم بالعودة فورًا لأنه لا يوجد ما يجب فعله.
- (اختياري) إذا كان النطاق قصيرًا جدًا، فاستخدم طريقة فرز مخصصة، ثم أعد النتيجة. على سبيل المثال، يمكن فرز نطاقات مكونة من عنصرين بمقارنة واحدة.
- وإلا، فاختر قيمة، تُسمى نقطة ارتكاز ، تقع ضمن النطاق. (تؤثر طريقة اختيار نقطة الارتكاز بشكل كبير على الأداء، ولكن ليس على صحة النتائج).
- قسّم النطاق: أعد ترتيب عناصره إلى نطاقات فرعية، بحيث تكون جميع العناصر ذات القيم الأقل من العنصر المحوري في النطاق الفرعي الأول، بينما تكون جميع العناصر ذات القيم الأكبر من العنصر المحوري في النطاق الفرعي الثاني. يمكن وضع العناصر ذات القيم المساوية للعنصر المحوري في أي من النطاقين الفرعيين، أو في نطاق فرعي ثالث بينهما. هذا النطاق الفرعي الأوسط اختياري، لكن خوارزمية الفرز السريع تتطلب أن يكون كل من النطاقين الفرعيين الأولين أصغر من النطاق الأصلي، وهو ما يمكن تحقيقه بسهولة أكبر بوضع عنصر محوري واحد على الأقل في المنتصف.
- قم بتطبيق خوارزمية الفرز السريع بشكل متكرر على النطاقين الفرعيين، باستثناء النطاق الفرعي الأوسط الموجود بالفعل في موضعه النهائي.
هذه هي المتطلبات الأساسية للتشغيل الصحيح. ويمكن أن تؤثر التفاصيل غير المذكورة أعلاه، بما في ذلك خوارزمية التقسيم، وخاصةً اختيار العنصر المحوري، بشكل كبير على أداء الخوارزمية لبعض مصفوفات الإدخال. لذا، لمناقشة كفاءة خوارزمية الفرز السريع، من الضروري تحديد هذه الخيارات أولاً. فيما يلي، نذكر طريقتين محددتين للتقسيم.
مخطط تقسيم لوموتو
يُنسب هذا المخطط إلى نيكو لوموتو، وقد شاع استخدامه بفضل بنتلي في كتابه "لآلئ البرمجة" [ 13 ] وكورمن وآخرون في كتابهم " مقدمة في الخوارزميات" [ 14 ] . في معظم الصيغ، يختار هذا المخطط العنصر الأخير في المصفوفة كعنصر محوري. وتحافظ الخوارزمية على الفهرس i أثناء مسحها للمصفوفة باستخدام فهرس آخر j، بحيث تكون العناصر من i₀ إلى i₋₁ ( شاملة ) أصغر من العنصر المحوري، والعناصر من i إلى j (شاملة) مساوية أو أكبر من العنصر المحوري. ولأن هذا المخطط أكثر إيجازًا وأسهل فهمًا، فإنه يُستخدم بكثرة في المواد التمهيدية، على الرغم من أنه أقل كفاءة من مخطط هوار الأصلي، على سبيل المثال، عندما تكون جميع العناصر متساوية [ 15 ] . ينخفض تعقيد خوارزمية الفرز السريع مع هذا المخطط إلى O ( n² ) عندما تكون المصفوفة مرتبة بالفعل، نظرًا لأن التقسيم هو أسوأ تقسيم ممكن . [ 11 ] تم اقتراح العديد من المتغيرات لتحسين الأداء، بما في ذلك طرق مختلفة لاختيار العنصر المحوري، والتعامل مع العناصر المتساوية، واستخدام خوارزميات فرز أخرى مثل فرز الإدراج للمصفوفات الصغيرة، وما إلى ذلك. في الشفرة الزائفة ، يمكن التعبير عن خوارزمية الفرز السريع التي ترتب العناصر من lo إلى hi (شاملة) في المصفوفة A على النحو التالي: [ 14 ]
// يقوم بفرز (جزء من) مصفوفة، ويقسمها إلى أقسام، ثم يفرز تلك الأقسام . خوارزمية الفرز السريع (A، lo، hi) هي // التأكد من أن الفهارس مرتبة بشكل صحيح إذا كان lo >= hi || lo < 0 ثم يعود // تقسيم المصفوفة والحصول على فهرس المحور p := partition(A, lo, hi) // فرز القسمين quicksort(A, lo, p - 1) // الجانب الأيسر من المحور quicksort(A, p + 1, hi) // الجانب الأيمن من المحور// تقسم الخوارزمية المصفوفة إلى قسمين : partition(A, lo, hi) is pivot := A[hi] // اختر العنصر الأخير كعنصر محوري// فهرس محوري مؤقت i := lo for j := lo to hi - 1 do // إذا كان العنصر الحالي أصغر من أو يساوي العنصر المحوري if A[j] <= pivot then // بدّل العنصر الحالي مع العنصر الموجود عند فهرس العنصر المحوري المؤقت swap A[i] with A[j] // حرك فهرس العنصر المحوري المؤقت للأمام i := i + 1 // تبديل العنصر المحوري مع العنصر الأخير تبديل A[i] مع A[hi] إرجاع i // فهرس العنصر المحوري
يتم فرز المصفوفة بأكملها بواسطة quicksort(A, 0, length(A) - 1) .
مخطط تقسيم هوار

iعلى jالتوالي)، بينما تُظهر الخطوط السوداء مواقع العناصر المُفرزة، ويُظهر المربع الأسود الممتلئ القيمة التي تتم مقارنتها ( pivot).تستخدم خوارزمية التقسيم الأصلية التي وصفها توني هوار مؤشرين (فهرسين في النطاق) يبدآن من طرفي المصفوفة المراد تقسيمها، ثم يتحركان باتجاه بعضهما البعض حتى يكتشفا انعكاسًا: زوج من العناصر، أحدهما أكبر من العنصر المحوري عند المؤشر الأول، والآخر أصغر منه عند المؤشر الثاني؛ إذا كان المؤشر الأول لا يزال قبل الثاني عند هذه النقطة، فإن هذين العنصرين يكونان في ترتيب خاطئ بالنسبة لبعضهما البعض، ويتم تبديلهما. [ 16 ] بعد ذلك، يتم تحريك المؤشرين إلى الداخل، وتُكرر عملية البحث عن الانعكاس؛ عندما يتقاطع المؤشران في النهاية (يشير الأول بعد الثاني)، لا يتم إجراء أي تبديل؛ يتم العثور على تقسيم صحيح، مع وجود نقطة التقسيم بين المؤشرين المتقاطعين (أي إدخالات قد تكون محصورة بين المؤشرين المتقاطعين تساوي العنصر المحوري ويمكن استبعادها من كلا النطاقين الفرعيين المُشكَّلين). مع هذه الصيغة، من الممكن أن يكون أحد النطاقين الفرعيين هو النطاق الأصلي بأكمله، مما سيمنع الخوارزمية من التقدم. لذلك ينص هوار على أنه في النهاية، يمكن تقليل حجم النطاق الفرعي الذي يحتوي على عنصر المحور (الذي لا يزال في موضعه الأصلي) عن طريق استبعاد هذا المحور، بعد (إذا لزم الأمر) استبداله بعنصر النطاق الفرعي الأقرب إلى الفصل؛ وبالتالي، يتم ضمان إنهاء الفرز السريع.
فيما يتعلق بهذا الوصف الأصلي، غالبًا ما تُجري التطبيقات تغييرات طفيفة ولكنها مهمة. على وجه الخصوص، يتضمن المخطط الموضح أدناه عناصر مساوية للمحور بين العناصر المرشحة للعكس (لذا تُستخدم اختبارات "أكبر من أو يساوي" و"أصغر من أو يساوي" بدلًا من "أكبر من" و"أصغر من" على التوالي؛ نظرًا لأن الصيغة تستخدم do ... while بدلًا من repeat ... until ، وهو ما ينعكس فعليًا في استخدام عوامل المقارنة الصارمة ). مع أنه لا يوجد سبب لتبديل العناصر المساوية للمحور، فإن هذا التغيير يسمح بحذف الاختبارات على المؤشرات نفسها، والتي تُعد ضرورية لضمان عدم تجاوزها النطاق. في الواقع، نظرًا لوجود نسخة واحدة على الأقل من قيمة المحور في النطاق، لا يمكن لأول تقدم لأي من المؤشرين تجاوز هذه النسخة إذا تم استخدام اختبار شامل؛ بمجرد إجراء التبديل، تصبح هذه العناصر المتبادلة متقدمة تمامًا عن المؤشر الذي وجدها، مما يمنع هذا المؤشر من الخروج عن النطاق. (ينطبق هذا الأخير بغض النظر عن الاختبار المستخدم، لذا يمكن استخدام الاختبار الشامل فقط عند البحث عن أول انعكاس. مع ذلك، يضمن استخدام الاختبار الشامل في جميع المراحل العثور على قسمة قريبة من المنتصف عندما تكون جميع العناصر في النطاق متساوية، مما يُحسّن كفاءة فرز المصفوفات التي تحتوي على العديد من العناصر المتساوية). يتم تجنب خطر حدوث فصل غير متقدم بطريقة مختلفة عن تلك التي وصفها هوار. لا يمكن أن يحدث هذا الفصل إلا عند عدم العثور على أي انعكاسات، حيث يتقدم كلا المؤشرين إلى عنصر المحور في التكرار الأول (ويُعتبر حينها أنهما قد تقاطعا، ولا يحدث أي تبادل).
في الشفرة الزائفة ، [ 14 ]
// تقوم هذه الخوارزمية بفرز (جزء من) مصفوفة، وتقسيمها إلى أقسام، ثم فرز هذه الأقسام. خوارزمية الفرز السريع (A, lo, hi) هي: إذا كان lo >= 0 && hi >= 0 && lo < hi، فإن p := partition(A, lo, hi) quicksort(A, lo, p) // ملاحظة: تم تضمين العنصر المحوري الآن quicksort(A, p + 1, hi) // تقسم الخوارزمية المصفوفة إلى قسمين : partition(A, lo, hi) is // قيمة المحور pivot := A[lo] // اختيار العنصر الأول كعنصر محوري// الفهرس الأيسر i := lo - 1 // الفهرس الأيمن j := hi + 1 حلقة لا نهائية // انقل العنصر ذي الفهرس الأيسر إلى اليمين مرة واحدة على الأقل، وطالما أن العنصر عند // الفهرس الأيسر أقل من العنصر المحوري، نفّذ ما يلي : i := i + 1 while A[i] < pivot // انقل العنصر الموجود في الفهرس الأيمن إلى اليسار مرة واحدة على الأقل، وطالما أن العنصر الموجود في الفهرس الأيمن أكبر من العنصر المحوري، نفّذ ما يلي : j := j - 1 while A[j] > pivot // إذا تقاطعت المؤشرات، فأرجع القيمة إذا كان i >= j ثم أرجع j // تبديل العناصر الموجودة في المؤشرين الأيسر والأيمن تبديل A[i] مع A[j]
يتم فرز المصفوفة بأكملها بواسطة quicksort(A, 0, length(A) - 1) .
تُعدّ خوارزمية هوار أكثر كفاءة من خوارزمية لوموتو للتقسيم، لأنها تُجري عمليات تبديل أقل بثلاث مرات في المتوسط. كما ذُكر سابقًا، تُنشئ هذه الخوارزمية تقسيمًا متوازنًا حتى عندما تكون جميع القيم متساوية [ 11 ] ، وهو ما لا تُنشئه خوارزمية لوموتو. ومثل خوارزمية لوموتو، فإن تقسيم هوار يُؤدي أيضًا إلى انخفاض كفاءة خوارزمية الفرز السريع إلى O(n²) للمدخلات المُرتبة مُسبقًا ، إذا تم اختيار العنصر المحوري كأول أو آخر عنصر. أما عند اختيار العنصر الأوسط كعنصر محوري، فإن البيانات المُرتبة تُنتج نتائج بدون عمليات تبديل تقريبًا في أقسام متساوية الحجم، مما يُؤدي إلى أفضل أداء لخوارزمية الفرز السريع، أي O ( n log( n )) . ومثل غيرها، لا يُنتج تقسيم هوار فرزًا مستقرًا. في هذه الخوارزمية، لا يكون الموقع النهائي للعنصر المحوري بالضرورة عند الفهرس المُعاد، حيث يُمكن أن ينتهي المطاف بالعنصر المحوري والعناصر المُساوية له في أي مكان داخل القسم بعد خطوة التقسيم، وقد لا يتم فرزها حتى يتم الوصول إلى الحالة الأساسية لقسم يحتوي على عنصر واحد عبر الاستدعاء الذاتي. لذلك، فإن الجزأين التاليين اللذين تتكرر عليهما الخوارزمية الرئيسية هما (lo..p) (العناصر ≤ المحور) و (p+1..hi) (العناصر ≥ المحور) على عكس (lo..p−1) و (p+1..hi) كما هو الحال في مخطط لوموتو.
- تكرارات لاحقة (توسيع للفقرة السابقة)
لنُفصّل قليلاً في الجزأين التاليين اللذين تعتمد عليهما الخوارزمية الرئيسية. نظرًا لاستخدامنا مُقارنات صارمة (>، <) في حلقات "do...while" لتجنب تجاوز النطاق، فهناك احتمال أن يتم تبديل العنصر المحوري مع عناصر أخرى في دالة التقسيم. لذلك، فإن الفهرس المُعاد من دالة التقسيم ليس بالضرورة هو موقع العنصر المحوري الفعلي. لنأخذ مثال المصفوفة [5، 2، 3، 1، 0] ، فبعد التقسيم الأول، تصبح المصفوفة [0، 2، 1، 3، 5] ، ويكون "الفهرس" المُعاد هو 2، وهو الرقم 1، بينما العنصر المحوري الحقيقي، الذي اخترناه لبدء التقسيم، هو الرقم 3. من خلال هذا المثال، نرى كيف أنه من الضروري تضمين الفهرس المُعاد من دالة التقسيم في عمليات التكرار اللاحقة. ونتيجةً لذلك، لدينا خياران: إما التكرار على (lo..p) و (p+1..hi) ، أو (lo..p−1) و (p..hi) . يعتمد اختيارنا لأحد هذين الخيارين على الفهرس ( i أو j ) الذي نعيده في دالة التقسيم عند تقاطع الفهارس، وكيفية اختيارنا للمحور في دالة التقسيم ( الحد الأدنى مقابل الحد الأعلى ).
أولًا، لنفحص اختيار التكرار على (lo..p) و (p+1..hi) ، مع مثال فرز مصفوفة تحتوي على عناصر متطابقة متعددة [0, 0] . إذا تم إرجاع الفهرس i (الفهرس "الأخير") بعد تقاطع الفهارس في دالة التقسيم، فسيتم إرجاع الفهرس 1 بعد التقسيم الأول. سيكون التكرار اللاحق على (lo..p) على (0, 1)، والذي يُقابل المصفوفة نفسها [0, 0] . ينتج عن ذلك فصل غير متقدم يؤدي إلى تكرار لا نهائي. لذلك، من الواضح أنه عند التكرار على (lo..p) و (p+1..hi) ، ولأن النصف الأيسر من التكرار يتضمن الفهرس المُعاد، فإن مهمة دالة التقسيم هي استبعاد "الذيل" في حالات الفصل غير المتقدم. أي أنه يجب إرجاع الفهرس j (الفهرس "الأول" عند تقاطع الفهارس) بدلًا من i. وبناءً على منطق مماثل، عند النظر إلى مثال المصفوفة المرتبة [0، 1] ، يجب اختيار العنصر المحوري "floor" لضمان توقف المؤشرات على العنصر "الأول" بدلاً من العنصر "الثاني" (مع اختيار "ceiling" كعنصر محوري، سيتم إرجاع الفهرس 1 وإدراجه في (lo..p) مما يؤدي إلى تكرار لا نهائي). وللسبب نفسه، يجب تجنب اختيار العنصر الأخير كعنصر محوري.
يتبع اختيار التكرار على (lo..p−1) و (p..hi) نفس المنطق المذكور أعلاه. ولأن النصف الأيمن من التكرار يتضمن الفهرس المُعاد، فإن مهمة دالة التقسيم هي استبعاد "الرأس" في حالات عدم التقدم. يجب إعادة الفهرس i (الفهرس "الأخير" بعد تقاطع الفهارس) في دالة التقسيم، ويجب اختيار "السقف" كنقطة ارتكاز. يتضح هذان الفرقان، مرة أخرى، عند النظر في أمثلة فرز مصفوفة تحتوي على عناصر متطابقة متعددة ( [0, 0] )، ومصفوفة مُرتبة مسبقًا [0, 1] على التوالي. ومن الجدير بالذكر أنه مع هذا الإصدار من التكرار، وللسبب نفسه، يجب تجنب اختيار العنصر الأول كنقطة ارتكاز.
مشاكل التنفيذ
اختيار المحور
في الإصدارات الأولى من خوارزمية الفرز السريع، كان يُختار العنصر الأيسر من القسم غالبًا كعنصر محوري. لسوء الحظ، يُؤدي هذا إلى أسوأ أداء في المصفوفات المرتبة مسبقًا، وهو استخدام شائع. [ 17 ] وقد حُلّت هذه المشكلة بسهولة باختيار فهرس عشوائي للعنصر المحوري، أو اختيار الفهرس الأوسط للقسم، أو (خاصةً للأقسام الطويلة) اختيار الوسيط للعناصر الأول والأوسط والأخير من القسم كعنصر محوري (كما أوصى سيدجويك ). [ 18 ] تُعالج قاعدة "وسيط الثلاثة" هذه حالة المدخلات المرتبة (أو المعكوسة الترتيب)، وتُعطي تقديرًا أفضل للعنصر المحوري الأمثل (الوسيط الحقيقي) من اختيار أي عنصر منفرد، عندما لا تتوفر معلومات عن ترتيب المدخلات.
مقتطف من التعليمات البرمجية لحساب متوسط ثلاثة عناصر لتقسيم لوموتو:
mid := ⌊(lo + hi) / 2⌋ إذا كان A[mid] < A[lo] استبدل A[lo] بـ A[mid] إذا كانت A[hi] < A[lo] استبدل A[lo] بـ A[hi] إذا كانت A[mid] < A[hi] استبدل A[mid] بـ A[hi] pivot := A[hi]
يضع الوسيط في A[hi]البداية، ثم يتم استخدام تلك القيمة الجديدة A[hi]للمحور، كما هو الحال في الخوارزمية الأساسية المعروضة أعلاه.
على وجه التحديد، يبلغ العدد المتوقع للمقارنات اللازمة لفرز n عنصرًا (انظر § تحليل الحالة المتوسطة ) مع اختيار محور عشوائي 1.386 n log n . يُقلل استخدام محور الوسيط الثلاثي هذا العدد إلى C n , 2 ≈ 1.188 n log n ، على حساب زيادة بنسبة 3% في العدد المتوقع لعمليات التبديل. [ 8 ] وهناك قاعدة محور أقوى، للمصفوفات الأكبر حجمًا، وهي اختيار العنصر التاسع ، وهو وسيط ثلاثي متكرر (Mo3)، مُعرّف على النحو التالي [ 8 ].
- ninether( a ) = median(Mo3(first 1 / 3 of a ), Mo3(middle 1 / 3 of a ), Mo3(final 1 / 3 of a ))
يُعدّ اختيار عنصر محوري عملية معقدة أيضًا بسبب وجود تجاوز سعة الأعداد الصحيحة . فإذا كانت مؤشرات حدود المصفوفة الفرعية المراد فرزها كبيرة بما يكفي، فإنّ التعبير البسيط للمؤشر الأوسط، ( lo + hi )/2 ، سيؤدي إلى تجاوز السعة، وبالتالي الحصول على مؤشر محوري غير صالح. يمكن التغلب على هذه المشكلة باستخدام، على سبيل المثال، lo + ( hi − lo )/2 لفهرسة العنصر الأوسط، ولكن ذلك يتطلب عمليات حسابية أكثر تعقيدًا. وتظهر مشكلات مماثلة في بعض الطرق الأخرى لاختيار العنصر المحوري.
العناصر المتكررة
مع خوارزمية تقسيم مثل خوارزمية لوموتو المذكورة أعلاه (حتى تلك التي تختار قيمًا محورية جيدة)، يُظهر الفرز السريع أداءً ضعيفًا للمدخلات التي تحتوي على العديد من العناصر المتكررة. تتضح المشكلة جليًا عندما تكون جميع عناصر الإدخال متساوية: ففي كل استدعاء، يكون القسم الأيسر فارغًا (لا توجد قيم إدخال أقل من القيمة المحورية)، بينما ينقص القسم الأيمن عنصرًا واحدًا فقط (حيث تُزال القيمة المحورية). ونتيجةً لذلك، تستغرق خوارزمية لوموتو وقتًا تربيعيًا لفرز مصفوفة من القيم المتساوية. مع ذلك، باستخدام خوارزمية تقسيم مثل خوارزمية هوار، تُؤدي العناصر المتكررة عمومًا إلى تقسيم أفضل، وعلى الرغم من إمكانية حدوث تبديلات غير ضرورية للعناصر المساوية للقيمة المحورية، إلا أن وقت التشغيل ينخفض عمومًا مع ازدياد عدد العناصر المتكررة (حيث تُقلل ذاكرة التخزين المؤقت من عبء التبديل). في حالة تساوي جميع العناصر، تُبدّل خوارزمية هوار العناصر دون داعٍ، لكن التقسيم نفسه يكون في أفضل حالاته، كما ذُكر في قسم خوارزمية هوار أعلاه.
لحل مشكلة مخطط تقسيم لوموتو (المعروفة أحيانًا باسم مشكلة العلم الوطني الهولندي [ 8 ] )، يمكن استخدام روتين تقسيم خطي بديل يفصل القيم إلى ثلاث مجموعات: قيم أقل من العنصر المحوري، وقيم تساوي العنصر المحوري، وقيم أكبر من العنصر المحوري. (يُطلق بنتلي وماكلروي على هذا اسم "التقسيم السمين"، وقد تم تنفيذه بالفعل في خوارزمية الفرز السريع (qsort ) في الإصدار 7 من نظام يونكس [ 8 ] ) . القيم التي تساوي العنصر المحوري مُرتبة بالفعل، لذا لا يلزم سوى فرز مجموعتي "أقل من" و"أكبر من" بشكل متكرر. في الشفرة الزائفة، تصبح خوارزمية الفرز السريع كما يلي:
// تقوم هذه الدالة بفرز (جزء من) مصفوفة، ثم تقسمها إلى أقسام، ثم ترتب هذه الأقسام . خوارزمية الفرز السريع (A, lo, hi) هي: إذا كان lo >= 0 && lo < hi، فإن lt, gt := partition(A, lo, hi) // قيم إرجاع متعددة quicksort(A, lo, lt - 1) quicksort(A, gt + 1, hi) // تقسم الخوارزمية المصفوفة إلى ثلاثة أقسام: partition (A, lo, hi) is // قيمة المحور pivot := A[(lo + hi) / 2] // اختيار العنصر الأوسط كعنصر محور (قسمة عددية صحيحة)// فهرس أصغر، يساوي، وأكبر lt := lo eq := lo gt := hi // تكرار ومقارنة جميع العناصر مع العنصر المحوري بينما يكون eq <= gt do if A[eq] < pivot then // تبديل العناصر عند الفهرسين المتساوي والأصغر swap A[eq] with A[lt] // زيادة الفهرس الأصغر lt := lt + 1 // زيادة مؤشر التساوي المعادلة := المعادلة + 1 وإلا إذا كان A[eq] > pivot ، فقم بما يلي: // تبديل العناصر عند الفهرسين المتساوي والأكبر // تقليل الفهرس الأكبر gt := gt - 1 وإلا // إذا كانت A[eq] = pivot ، فقم بزيادة فهرس التساوي // المعادلة := المعادلة + 1 // إرجاع الفهرسين الأصغر والأكبر return lt, gt
تُعيد الخوارزمية partitionمؤشرات العنصر الأول (الأيسر) والعنصر الأخير (الأيمن) من القسم الأوسط. كل عنصر آخر في القسم يساوي العنصر المحوري، وبالتالي فهو مُرتب. ونتيجةً لذلك، لا يلزم تضمين عناصر القسم في الاستدعاءات المتكررة للدالة quicksort.
تتحقق أفضل حالة للخوارزمية عندما تكون جميع العناصر متساوية (أو مختارة من مجموعة صغيرة من k ≪ n عنصرًا). في حالة تساوي جميع العناصر، ستُجري خوارزمية الفرز السريع المُعدّلة استدعاءين متكررين فقط على المصفوفات الفرعية الفارغة، وبالتالي ستنتهي في وقت خطي (بافتراض أن الروتين partitionالفرعي لا يستغرق وقتًا أطول من الوقت الخطي).
التحسينات
ومن التحسينات المهمة الأخرى، التي اقترحها سيدجويك وتستخدم على نطاق واسع في الممارسة العملية، ما يلي: [ 19 ] [ 20 ]
- للتأكد من استخدام مساحة لا تتجاوز O (log n ) ، قم بالتكرار أولاً في الجانب الأصغر من القسم، ثم استخدم استدعاء الذيل للتكرار في الجانب الآخر، أو قم بتحديث المعلمات بحيث لا تشمل الجانب الأصغر الذي تم فرزه الآن، وكرر لفرز الجانب الأكبر.
- عندما يقل عدد العناصر عن حد معين (ربما عشرة عناصر)، يُنصح بالتحول إلى خوارزمية فرز غير تكرارية، مثل فرز الإدراج ، التي تُجري عمليات تبديل ومقارنات وعمليات أخرى أقل على هذه المصفوفات الصغيرة. ويختلف هذا الحد الأمثل بناءً على تفاصيل التنفيذ المحدد.
- يُعدّ هذا أحد أشكال التحسين القديمة: عندما يقلّ عدد العناصر عن العتبة k ، يتوقف البرنامج ببساطة؛ ثم بعد معالجة المصفوفة بأكملها، يُجرى عليها فرز الإدراج. يؤدي إيقاف الاستدعاء الذاتي مبكرًا إلى جعل المصفوفة مُرتبة k- مرتبة، أي أن كل عنصر يبعد k خانة على الأكثر عن موقعه النهائي المُرتب. في هذه الحالة، يستغرق فرز الإدراج زمنًا قدره O ( kn ) لإنهاء الفرز، وهو زمن خطي إذا كان k ثابتًا. [ 21 ] [ 13 ] : 117 بالمقارنة مع تحسين "العديد من عمليات الفرز الصغيرة"، قد يُنفّذ هذا الإصدار عددًا أقل من التعليمات، ولكنه لا يُحسن استخدام ذاكرة التخزين المؤقت في الحواسيب الحديثة. [ 22 ]
التوازي
بفضل صياغتها القائمة على فرق تسد، تُصبح خوارزمية الفرز السريع قابلةً للتوازي باستخدام توازي المهام . تتم خطوة التقسيم باستخدام خوارزمية مجموع البادئات المتوازية لحساب فهرس لكل عنصر من عناصر المصفوفة في قسمه من المصفوفة المُقسّمة. [ 23 ] [ 24 ] بافتراض مصفوفة بحجم n ، تُنجز خطوة التقسيم عملاً مقداره O( n ) في زمن قدره O (log n ) وتتطلب مساحة تخزين مؤقتة إضافية مقدارها O( n ) . بعد تقسيم المصفوفة، يُمكن فرز القسمين بشكل متكرر ومتوازٍ. بافتراض اختيار مثالي للعناصر المحورية، تُفرز خوارزمية الفرز السريع المتوازية مصفوفة بحجم n في عمل مقداره O( n log n ) في زمن قدره O(log 2 n ) باستخدام مساحة تخزين إضافية مقدارها O( n ) .
يُعاني فرز Quicksort من بعض العيوب مقارنةً بخوارزميات الفرز البديلة، مثل فرز الدمج ، مما يُعقّد عملية التوازي الفعّالة له. يؤثر عمق شجرة فرق تسد في Quicksort بشكل مباشر على قابلية توسع الخوارزمية، ويعتمد هذا العمق بشكل كبير على اختيار الخوارزمية للمحور. إضافةً إلى ذلك، يصعب موازاة خطوة التقسيم بكفاءة في مكانها. يُبسّط استخدام مساحة التخزين المؤقتة خطوة التقسيم، ولكنه يزيد من حجم الذاكرة المستخدمة في الخوارزمية والتكاليف الثابتة.
يمكن لخوارزميات الفرز المتوازي الأخرى الأكثر تطوراً تحقيق حدود زمنية أفضل. [ 25 ] على سبيل المثال، في عام 1991، وصف ديفيد إم دبليو باورز خوارزمية فرز سريع متوازية ( وخوارزمية فرز جذرية ذات صلة ) يمكنها العمل في زمن O (log n ) على جهاز CRCW (القراءة والكتابة المتزامنة) PRAM ( آلة الوصول العشوائي المتوازية ) مع n معالجًا عن طريق إجراء التقسيم ضمنيًا. [ 26 ]
التحليل الرسمي
تحليل أسوأ الحالات
يحدث التقسيم الأكثر عدم توازنًا عندما يكون حجم إحدى القوائم الفرعية التي تُرجعها روتينية التقسيم n − 1. [ 27 ] قد يحدث هذا إذا كان العنصر المحوري هو أصغر عنصر أو أكبر عنصر في القائمة، أو في بعض التطبيقات (مثل مخطط تقسيم لوموتو كما هو موضح أعلاه) عندما تكون جميع العناصر متساوية.
إذا تكرر هذا الأمر في كل قسم، فإن كل استدعاء متكرر يعالج قائمةً يقل حجمها بواحد عن القائمة السابقة. وبالتالي، يتطلب الأمر n − 1 استدعاءً متداخلًا قبل الوصول إلى قائمة بحجم 1. هذا يعني أن شجرة الاستدعاءات عبارة عن سلسلة خطية من n − 1 استدعاءً متداخلًا. يقوم الاستدعاء رقم i بعمل مقداره O ( n − i ) لإجراء القسم، ولذلك في هذه الحالة، تستغرق عملية الفرز السريع O ( n 2 ) من الوقت.
تحليل أفضل الحالات
في الحالة الأكثر توازنًا، يقسم كل قسم القائمة إلى جزأين متساويين تقريبًا. هذا يعني أن كل استدعاء متكرر يعالج قائمة بحجم نصف القائمة الأصلية. وبالتالي، لا يمكن إجراء سوى log₂n من الاستدعاءات المتداخلة قبل الوصول إلى قائمة بحجم 1. وهذا يعني أن عمق شجرة الاستدعاءات هو log₂n . ولكن لا يوجد استدعاءان في نفس مستوى شجرة الاستدعاءات يعالجان نفس الجزء من القائمة الأصلية؛ لذا، يحتاج كل مستوى من الاستدعاءات إلى O ( n ) من الوقت إجمالًا (لكل استدعاء تكلفة إضافية ثابتة، ولكن نظرًا لوجود O ( n ) فقط من الاستدعاءات في كل مستوى، فإن هذه التكلفة مضمنة في عامل O ( n ) ). والنتيجة هي أن الخوارزمية تستخدم O ( n log n ) من الوقت فقط.
تحليل الحالة المتوسطة
لترتيب مصفوفة من n عنصرًا مختلفًا، يستغرق فرز سريع O ( n log n ) من الوقت في المتوسط، محسوبًا على جميع التباديل n ! لـ n عنصرًا باحتمالية متساوية . بدلاً من ذلك، إذا اختارت الخوارزمية العنصر المحوري عشوائيًا بشكل منتظم من مصفوفة الإدخال، فيمكن استخدام التحليل نفسه لتقييد وقت التشغيل المتوقع لأي تسلسل إدخال؛ ثم يُحسب التوقع على الاختيارات العشوائية التي أجرتها الخوارزمية (Cormen et al. ، مقدمة في الخوارزميات ، [ 14 ] القسم 7.3).
تستخدم ثلاثة أدلة شائعة على هذا الادعاء النسب المئوية والتكرارات وأشجار البحث الثنائية، حيث يقدم كل منها رؤى مختلفة حول آلية عمل الفرز السريع.
استخدام النسب المئوية
إذا كان ترتيب كل محور يقع في منتصف الخمسين بالمائة، أي بين المئين 25 والمئين 75، فإنه يقسم العناصر بحيث لا يقل ترتيبها عن 25% ولا يزيد عن 75% على كل جانب. إن اختيار محاور كهذه باستمرار سيؤدي فقط إلى تقسيم القائمة على الأكثرمرات قبل الوصول إلى قوائم بحجم 1، مما ينتج عنه خوارزمية O ( n log n ) .
عندما يكون المدخل عبارة عن تبديل عشوائي ، يكون للعنصر المحوري رتبة عشوائية، وبالتالي لا يُضمن وجوده ضمن النصف الأوسط. مع ذلك، عند البدء بتبديل عشوائي، يكون للعنصر المحوري في كل استدعاء تكراري رتبة عشوائية في قائمته، وبالتالي يكون ضمن النصف الأوسط لنصف الوقت تقريبًا. تخيل أننا قلبنا قطعة نقدية: ظهور الصورة يعني أن رتبة العنصر المحوري تقع ضمن النصف الأوسط، وظهور الكتابة يعني عكس ذلك. الآن تخيل أننا قلبنا القطعة النقدية مرارًا وتكرارًا حتى نحصل على k صورة. على الرغم من أن هذا قد يستغرق وقتًا طويلًا، إلا أننا نحتاج في المتوسط إلى 2k قلبة فقط ، وفرصة عدم حصول القطعة النقدية على k صورة بعد 100k قلبة ضئيلة للغاية (يمكن التحقق من ذلك بدقة باستخدام حدود تشيرنوف ). وبناءً على الحجة نفسها، سينتهي التكرار في خوارزمية الفرز السريع في المتوسط عند عمق استدعاء يبلغ 10 ...لكن إذا كان متوسط عمق الاستدعاءات O (log n ) ، وكان كل مستوى من مستويات شجرة الاستدعاءات يعالج n عنصرًا على الأكثر، فإن إجمالي العمل المنجز في المتوسط هو حاصل ضرب O ( n log n ) . لا يتعين على الخوارزمية التحقق من أن العنصر المحوري يقع في النصف الأوسط طالما أنه يقع فيه عددًا ثابتًا من المرات.
باستخدام حجج أكثر دقة، من الممكن توسيع هذا البرهان ليشمل نسخة من خوارزمية الفرز السريع حيث يتم اختيار العنصر المحوري عشوائيًا، لإظهار حد زمني يتحقق باحتمالية عالية : تحديدًا، لأي قيمة معطاة، يتركإذن باحتمالية لا تقل عنلن يتجاوز عدد المقارنات[ 28 ]
استخدام التكرارات
يتمثل أحد الأساليب البديلة في إنشاء علاقة تكرارية لعامل T ( n ) ، وهو الوقت اللازم لفرز قائمة بحجم n . في الحالة الأكثر اختلالًا، تتضمن عملية فرز سريعة واحدة O ( n ) من العمل بالإضافة إلى عمليتي استدعاء متكررتين على قوائم بحجم 0 و n -1 ، لذا فإن العلاقة التكرارية هي
هذه هي نفس العلاقة كما هو الحال بالنسبة لفرز الإدراج وفرز الاختيار ، ويتم حلها إلى أسوأ حالة T ( n ) = O ( n 2 ) .
في الحالة الأكثر توازناً، تتضمن عملية استدعاء واحدة لخوارزمية الفرز السريع O ( n ) من العمليات بالإضافة إلى استدعاءين متكررين على قوائم بحجم n /2 ، لذا فإن علاقة التكرار هي
تخبرنا النظرية الرئيسية للتكرارات التي تعتمد على فرق تسد أن T ( n ) = O ( n log n ) .
فيما يلي ملخص لإثبات رسمي لتعقيد الوقت المتوقع O ( n log n ) . نفترض عدم وجود عناصر مكررة، إذ يمكن معالجتها مسبقًا وبعديًا بزمن خطي، أو اعتبارها حالات أسهل من الحالة المدروسة. عندما يكون المدخل عبارة عن تبديل عشوائي، تكون رتبة العنصر المحوري عشوائية بشكل منتظم من 0 إلى n -1 . عندئذٍ، يكون حجم الأجزاء الناتجة من التقسيم i و n - i -1 ، و i عشوائية بشكل منتظم من 0 إلى n -1 . لذا، بحساب المتوسط لجميع التقسيمات الممكنة، مع ملاحظة أن عدد المقارنات للتقسيم هو n -1 ، يمكن تقدير متوسط عدد المقارنات لجميع تباديل تسلسل المدخل بدقة عن طريق حل العلاقة التكرارية التالية:
حل التكرار يعطي C ( n ) = 2 n ln n ≈ 1.39 n log 2 n .
هذا يعني أن أداء خوارزمية الفرز السريع، في المتوسط، أسوأ بنسبة 39% فقط من أفضل حالاتها. وبهذا المعنى، فهي أقرب إلى أفضل الحالات منها إلى أسوأها. لا يمكن لخوارزمية الفرز المقارن استخدام أقل من log₂ ( n !) مقارنة في المتوسط لفرز n عنصرًا (كما هو موضح في مقالة الفرز المقارن ) ، وفي حالة n الكبيرة ، يُعطي تقريب ستيرلينغ log₂ ( n !) ≈ n (log₂n - log₂e ) ، لذا فإن أداء الفرز السريع ليس أسوأ بكثير من الفرز المقارن المثالي. يُعد متوسط وقت التشغيل السريع هذا سببًا آخر لتفوق الفرز السريع عمليًا على خوارزميات الفرز الأخرى.
استخدام شجرة بحث ثنائية
تُقابل كل عملية تنفيذ لخوارزمية الفرز السريع شجرة بحث ثنائية (BST) كما يلي : العقدة المحورية الأولية هي العقدة الجذرية؛ وعقدة النصف الأيسر هي جذر الشجرة الفرعية اليسرى، وعقدة النصف الأيمن هي جذر الشجرة الفرعية اليمنى، وهكذا. عدد المقارنات في عملية تنفيذ الفرز السريع يساوي عدد المقارنات أثناء بناء شجرة البحث الثنائية من خلال سلسلة من عمليات الإدخال. لذا، فإن متوسط عدد المقارنات في الفرز السريع العشوائي يساوي متوسط تكلفة بناء شجرة البحث الثنائية عند إدخال القيم.قم بتشكيل تبديل عشوائي.
لنفترض وجود شجرة بحث ثنائية تم إنشاؤها عن طريق إدخال تسلسلمن القيم التي تشكل تبديلاً عشوائياً. لنفترض أن C ترمز إلى تكلفة إنشاء شجرة البحث الثنائية. لدينا، أينهو متغير عشوائي ثنائي يعبر عما إذا كان أثناء إدخالكانت هناك مقارنة بـ.
بحسب خاصية الخطية للتوقع ، فإن القيمة المتوقعةمن C هو.
ثبّت i و j < i . القيمبعد فرزها، حدد فترات j + 1. الملاحظة الهيكلية الأساسية هي أنمقارنة بـفي الخوارزمية إذا وفقط إذايقع ضمن إحدى الفترتين المجاورتين لـ.
لاحظ ذلك منذهو تبديل عشوائي،وهي أيضًا تبديل عشوائي، لذا فإن احتمال أنيقع بجوارهو بالضبط.
مبسطة كعملية حسابية مختصرة:
تعقيد المساحة
تعتمد المساحة التي يستخدمها الفرز السريع على الإصدار المستخدم.
تتمتع النسخة الموضعية من خوارزمية الفرز السريع بتعقيد مكاني قدره O (log n ) ، حتى في أسوأ الحالات، عندما يتم تنفيذها بعناية باستخدام الاستراتيجيات التالية.
- يتم استخدام التقسيم الموضعي. يتطلب هذا التقسيم غير المستقر مساحة O (1) .
- بعد التقسيم، يُرتب القسم ذو أقل عدد من العناصر أولاً (بشكل متكرر)، مما يتطلب مساحة لا تتجاوز O (log n ) . ثم يُرتب القسم الآخر باستخدام التكرار الذيل أو التكرار، وهو ما لا يزيد من حجم مكدس الاستدعاءات. هذه الفكرة، كما ذُكر أعلاه، وصفها ر. سيدجويك ، وتحافظ على عمق المكدس ضمن حدود O (log n ) . [ 18 ] [ 21 ]
Quicksort with in-place and unstable partitioning uses only constant additional space before making any recursive call. Quicksort must store a constant amount of information for each nested recursive call. Since the best case makes at most O(log n) nested recursive calls, it uses O(log n) space. However, without Sedgewick's trick to limit the recursive calls, in the worst case, quicksort could make O(n) nested recursive calls and need O(n) auxiliary space.
From a bit complexity viewpoint, variables such as lo and hi do not use constant space; it takes O(log n) bits to index into a list of n items. Because there are such variables in every stack frame, quicksort using Sedgewick's trick requires O((log n)2) bits of space. This space requirement isn't too terrible, though, since if the list contained distinct elements, it would need at least O(n log n) bits of space.
Stack-free versions of Quicksort have been proposed. These use additional space (more precisely, one cell of the type of the sorted records, in order to exchange records, and a constant number of integer variables used as indices).[29]
Another, less common, not-in-place version of quicksort uses O(n) space for working storage and can implement a stable sort. The working storage allows the input array to be easily partitioned in a stable way and then copied back to the input array for successive recursive calls. Sedgewick's optimization is still appropriate.
Relation to other algorithms
خوارزمية الفرز السريع هي نسخة مُحسّنة من حيث المساحة لخوارزمية فرز الشجرة الثنائية . فبدلاً من إدراج العناصر بالتسلسل في شجرة مُحددة، تُنظمها خوارزمية الفرز السريع بشكل متزامن في شجرة مُستنتجة من الاستدعاءات التكرارية. تُجري الخوارزميتان نفس المقارنات تمامًا، ولكن بترتيب مختلف. من الخصائص المرغوبة في خوارزمية الفرز الاستقرار، أي عدم تغيير ترتيب العناصر المتساوية، مما يسمح بالتحكم في ترتيب الجداول متعددة المفاتيح (مثل قوائم الدلائل أو المجلدات) بطريقة طبيعية. يصعب الحفاظ على هذه الخاصية في خوارزمية الفرز السريع الموضعي (التي تستخدم مساحة إضافية ثابتة فقط للمؤشرات والمخازن المؤقتة، ومساحة إضافية من رتبة O (log n ) لإدارة الاستدعاءات التكرارية الصريحة أو الضمنية). أما في خوارزميات الفرز السريع المُتغيرة التي تتضمن ذاكرة إضافية بسبب استخدام المؤشرات (مثل القوائم أو الأشجار) أو الملفات (التي تُعتبر قوائم فعليًا)، فيسهل الحفاظ على الاستقرار. بشكل عام، تميل هياكل البيانات الأكثر تعقيدًا، أو تلك المُقيدة بالقرص، إلى زيادة الوقت المُستغرق، مما يزيد من استخدام الذاكرة الافتراضية أو القرص.
المنافس المباشر لخوارزمية الفرز السريع هو فرز الكومة . يتميز فرز الكومة بالبساطة ووقت تشغيل في أسوأ الحالات يبلغ O ( n log n ) ، إلا أن متوسط وقت تشغيله يُعتبر عادةً أبطأ من فرز السريع الموضعي، ويعود ذلك أساسًا إلى ضعف خاصية المرجعية المحلية فيه . [ 30 ] هذه النتيجة محل نقاش؛ إذ تشير بعض الدراسات إلى عكس ذلك. [ 31 ] [ 32 ] أما العيب الرئيسي لفرز السريع فهو تعقيد التنفيذ المطلوب لتجنب اختيارات المحور السيئة، وما ينتج عنه من أداء O ( n² ) . يُعد فرز الإدخال (Introsort) أحد أنواع فرز السريع، ويحل هذه المشكلة بالتحول إلى فرز الكومة عند اكتشاف حالة غير مناسبة. تستخدم لغات البرمجة الرئيسية، مثل C++ (في تطبيقات GNU وLLVM)، فرز الإدخال. [ 33 ]
تتنافس خوارزمية الفرز السريع أيضًا مع خوارزمية الفرز بالدمج ، وهي خوارزمية فرز أخرى من رتبة O ( n log n ) . تتمثل المزايا الرئيسية للفرز بالدمج في استقراره وأدائه الممتاز في أسوأ الحالات. أما عيبه الرئيسي فهو أنه خوارزمية فرز خارج المكان، لذا عند تطبيقه على المصفوفات، تتطلب التطبيقات الفعالة مساحة إضافية من رتبة O ( n ) (مقارنةً بـ O (log n ) للفرز السريع مع التقسيم الموضعي والتكرار الذيل، أو O (1) لفرز الكومة).
يعمل فرز الدمج بكفاءة عالية مع القوائم المتصلة ، إذ لا يتطلب سوى مساحة تخزين إضافية صغيرة وثابتة. ورغم إمكانية تطبيق الفرز السريع كخوارزمية فرز مستقرة باستخدام القوائم المتصلة، إلا أنه لا داعي لذلك؛ إذ غالبًا ما يعاني من اختيار غير مناسب للعناصر المحورية في غياب الوصول العشوائي، وهو في جوهره أقل كفاءة من فرز الدمج. كما يُعد فرز الدمج الخوارزمية المُفضلة لفرز مجموعات البيانات الضخمة المخزنة على وسائط تخزين بطيئة الوصول، مثل الأقراص الصلبة أو وحدات التخزين المتصلة بالشبكة .
إن فرز الدلو باستخدام دلوين يشبه إلى حد كبير فرز السرعة؛ فالمحور في هذه الحالة هو القيمة الموجودة في منتصف نطاق القيمة، وهو ما يحقق أداءً جيدًا في المتوسط للمدخلات الموزعة بشكل منتظم.
التمحور القائم على الاختيار
تختار خوارزمية الاختيار أصغر عنصر في قائمة من الأرقام؛ وهذه مشكلة أسهل عمومًا من الفرز. تعمل إحدى خوارزميات الاختيار البسيطة والفعّالة بطريقة مشابهة لخوارزمية الفرز السريع، ولذلك تُعرف باسم " الاختيار السريع" . يكمن الاختلاف في أنها بدلًا من إجراء استدعاءات متكررة على كلتا القائمتين الفرعيتين، فإنها تُجري استدعاءً واحدًا فقط متكررًا على القائمة الفرعية التي تحتوي على العنصر المطلوب. يُقلل هذا التغيير متوسط التعقيد إلى خطي أو O ( n ) ، وهو الأمثل للاختيار، لكن خوارزمية الاختيار تظل O ( n² ) في أسوأ الحالات.
يُعدّ خوارزمية وسيط الوسائط أحد أنواع خوارزمية الاختيار السريع، حيث تختار نقاط الارتكاز بعناية أكبر، مما يضمن قربها من منتصف البيانات (بين المئين 30 والمئين 70)، وبالتالي تضمن زمنًا خطيًا قدره O ( n ) . ويمكن استخدام استراتيجية نقاط الارتكاز نفسها لإنشاء نوع آخر من خوارزمية الفرز السريع (فرز وسيط الوسائط السريع) بزمن قدره O ( n log n ) . مع ذلك، فإنّ عبء اختيار نقطة الارتكاز كبير، لذا لا يُستخدم هذا النوع عمليًا في الغالب.
بصورة أكثر تجريدًا، إذا توفرت خوارزمية اختيار ذات زمن تشغيل O ( n ) ، فيمكن استخدامها لإيجاد العنصر المحوري الأمثل (الوسيط) في كل خطوة من خطوات الفرز السريع، وبالتالي إنتاج خوارزمية فرز بزمن تشغيل O ( n log n ) . تُعدّ التطبيقات العملية لهذا النوع أبطأ بكثير في المتوسط، لكنها ذات أهمية نظرية لأنها تُظهر أن خوارزمية الاختيار الأمثل يمكن أن تُنتج خوارزمية فرز مثلى.
المتغيرات
فرز سريع متعدد المحاور
بدلاً من تقسيم البيانات إلى مصفوفتين فرعيتين باستخدام محور واحد، يقوم فرز البيانات السريع متعدد المحاور (أو فرز البيانات السريع المتعدد [ 22 ] ) بتقسيم المدخلات إلى عدد s من المصفوفات الفرعية باستخدام s − 1 محور. وبينما درس سيدجويك وآخرون حالة المحورين ( s = 3 ) في منتصف سبعينيات القرن الماضي، لم تكن الخوارزميات الناتجة أسرع عمليًا من فرز البيانات السريع "الكلاسيكي". [ 34 ] وفي تقييم أُجري عام 1999 لفرز البيانات السريع المتعدد ذي عدد متغير من المحاور، والمُحسَّن للاستخدام الأمثل لذاكرة التخزين المؤقت للمعالج، وُجد أنه يزيد عدد التعليمات بنحو 20%، لكن نتائج المحاكاة أشارت إلى أنه سيكون أكثر كفاءة مع المدخلات الكبيرة جدًا. [ 22 ] تبين أن نسخة من خوارزمية الفرز السريع ثنائية المحور، التي طورها ياروسلافسكي عام 2009 [ 35 ] ، سريعة بما يكفي [ 36 ] لتبرير تطبيقها في جافا 7 ، كخوارزمية قياسية لفرز مصفوفات العناصر الأولية ( يتم فرز مصفوفات الكائنات باستخدام خوارزمية Timsort ). [ 37 ] وقد تبين لاحقًا أن تحسن أداء هذه الخوارزمية مرتبط في الغالب بأداء الذاكرة المؤقتة، [ 38 ] وتشير النتائج التجريبية إلى أن النسخة ثلاثية المحور قد يكون أداؤها أفضل على الأجهزة الحديثة. [ 39 ] [ 40 ]
فرز سريع خارجي
بالنسبة لملفات القرص، يُمكن استخدام فرز خارجي قائم على التقسيم، على غرار الفرز السريع. وهو أبطأ من فرز الدمج الخارجي، ولكنه لا يتطلب مساحة إضافية على القرص. يتم استخدام 4 مخازن مؤقتة، اثنان للإدخال واثنان للإخراج.عدد السجلات في الملف،عدد السجلات لكل مخزن مؤقت، وعدد أجزاء المخزن المؤقت في الملف. تُقرأ البيانات (وتُكتب) من طرفي الملف باتجاه الداخل. ليكنتمثل هذه المقاطع الأجزاء التي تبدأ من بداية الملف، وتمثل هذه المقاطع أجزاءً تبدأ من نهاية الملف. تُقرأ البيانات فيوقراءة المخازن المؤقتة. يتم اختيار سجل محوري والسجلات الموجودة فيهويتم نسخ المخازن المؤقتة الأخرى غير سجل المحور إلىاكتب البيانات المخزنة مؤقتًا بترتيب تصاعدي ويتم كتابة البيانات المخزنة مؤقتًا بترتيب تنازلي بناءً على المقارنة مع سجل المحور. بمجرد حدوث أي مما يليأويتم ملء المخزن المؤقت، ثم تتم كتابته في الملف، ثم التاليأوتُقرأ البيانات من الملف. وتستمر العملية حتى تُقرأ جميع الأجزاء ويبقى مخزن كتابة واحد. إذا كان هذا المخزن عبارة عنيتم إلحاق سجل المحور بذاكرة التخزين المؤقت للكتابة، ويتم كتابة البيانات في المخزن المؤقت. إذا كان هذا المخزن المؤقت عبارة عنفي مخزن الكتابة، يتم إلحاق سجل المحور بـالمخزن المؤقت وتمت كتابة المخزن المؤقت. يُمثل هذا خطوة تقسيم واحدة للملف، ويتكون الملف الآن من ملفين فرعيين. يتم دفع/سحب موضعَي البداية والنهاية لكل ملف فرعي إلى مكدس مستقل أو المكدس الرئيسي عبر التكرار. لتقييد مساحة المكدس إلىفي حالة المعالجة المتكررة، تتم معالجة الملف الفرعي الأصغر أولاً. بالنسبة للمكدس المستقل، تُضاف معلمات الملف الفرعي الأكبر إلى المكدس، ثم تُكرر العملية على الملف الفرعي الأصغر. أما في حالة المعالجة المتكررة، فتُكرر العملية على الملف الفرعي الأصغر أولاً، ثم تُكرر لمعالجة الملف الفرعي الأكبر. بمجرد أن يصبح حجم الملف الفرعي أقل من أو يساوي 4 بايتات من السجلات، يُرتب الملف الفرعي في مكانه باستخدام خوارزمية الفرز السريع ويُكتب. يصبح هذا الملف الفرعي الآن مُرتبًا وموجودًا في مكانه في الملف. تستمر هذه العملية حتى يتم ترتيب جميع الملفات الفرعية وإضافتها إلى مكانها. يبلغ متوسط عدد مرات المرور على الملف حواليلكن أسوأ سيناريو هوالنجاحات (ما يعادل(للحالات الأسوأ، الفرز الداخلي). [ 41 ]
فرز سريع ثلاثي الاتجاهات
تجمع هذه الخوارزمية بين فرز الجذر والفرز السريع. اختر عنصرًا من المصفوفة (العنصر المحوري) وحدد الحرف الأول (المفتاح) من السلسلة (مفتاح متعدد). قسّم العناصر المتبقية إلى ثلاث مجموعات: تلك التي يكون الحرف المقابل لها أصغر من، أو يساوي، أو أكبر من حرف العنصر المحوري. رتّب مجموعتي "أصغر من" و"أكبر من" بشكل متكرر بناءً على الحرف نفسه. رتّب مجموعة "يساوي" بشكل متكرر بناءً على الحرف التالي (المفتاح). بما أننا نستخدم بايتات أو كلمات بطول W بت للفرز، فإن أفضل حالة هي O ( KN ) وأسوأ حالة هي O (2KN ) أو على الأقل O ( N² ) كما هو الحال في الفرز السريع القياسي، وذلك للمفاتيح الفريدة N < 2K ، حيث K ثابت ضمني في جميع خوارزميات فرز المقارنة القياسية ، بما في ذلك الفرز السريع. هذا نوع من الفرز السريع ثلاثي الاتجاهات ، حيث يمثل القسم الأوسط مصفوفة فرعية مرتبة (بشكل بديهي) من العناصر التي تساوي العنصر المحوري تمامًا .
فرز جذري سريع
طُوِّرت هذه الخوارزمية أيضًا بواسطة باورز كخوارزمية PRAM متوازية من رتبة O ( K ) . وهي بدورها مزيج من فرز الجذر والفرز السريع، ولكن قرار تقسيم المفتاح إلى يمين أو يسار في الفرز السريع يعتمد على البتات المتتالية للمفتاح، وبالتالي يكون زمنها O ( KN ) لمفاتيح N ذات K بت. تفترض جميع خوارزميات فرز المقارنة ضمنيًا نموذجًا ثنائيًا متقاطعًا حيث K في Θ (log N ) ، فإذا كانت K أصغر، يمكننا الفرز في زمن O ( N ) باستخدام جدول تجزئة أو فرز الأعداد الصحيحة . أما إذا كانت K أكبر بكثير من log N ، ولكن العناصر فريدة ضمن O (log N ) بت، فلن يتم فحص البتات المتبقية بواسطة الفرز السريع أو فرز الجذر السريع. وإلا، فإن جميع خوارزميات فرز المقارنة ستتحمل نفس العبء الإضافي المتمثل في البحث في O ( K ) من البتات غير المفيدة نسبيًا، لكن فرز الجذر السريع سيتجنب أسوأ حالات O ( N² ) لسلوكيات الفرز السريع القياسي وفرز الجذر السريع، وسيكون أسرع حتى في أفضل حالات خوارزميات المقارنة هذه في ظل هذه الشروط: uniqueprefix( K ) ≫ log N. انظر Powers [ 42 ] لمزيد من المناقشة حول الأعباء الإضافية الخفية في فرز المقارنة، وفرز الجذر، والفرز المتوازي.
فرز الكتل السريع
في أي خوارزمية فرز تعتمد على المقارنة، يتطلب تقليل عدد المقارنات زيادة كمية المعلومات المُستقاة من كل مقارنة، مما يعني أن نتائج المقارنة غير قابلة للتنبؤ. وهذا يُسبب أخطاءً متكررة في التنبؤ بالفروع ، مما يُحد من الأداء. [ 43 ] تُعيد خوارزمية BlockQuicksort [ 44 ] ترتيب حسابات الفرز السريع لتحويل الفروع غير القابلة للتنبؤ إلى تبعيات بيانات . عند التقسيم، يُقسّم المُدخل إلى كتل متوسطة الحجم (تتناسب بسهولة مع ذاكرة التخزين المؤقت للبيانات )، ويتم ملء مصفوفتين بمواقع العناصر المراد تبديلها. (لتجنب الفروع الشرطية، يتم تخزين الموقع بشكل غير مشروط في نهاية المصفوفة، ويتم زيادة فهرس النهاية إذا لزم التبديل). في دورة ثانية، يتم تبديل العناصر في المواقع المُشار إليها في المصفوفات. تحتوي كلتا الحلقتين على فرع شرطي واحد فقط، وهو اختبار للإنهاء، والذي يتم تنفيذه عادةً.
The BlockQuicksort technique is incorporated into LLVM's C++ STL implementation, libcxx, providing a 50% improvement on random integer sequences. Pattern-defeating quicksort (pdqsort), a version of introsort, also incorporates this technique.[33]
Partial and incremental quicksort
Several variants of quicksort exist that separate the k smallest or largest elements from the rest of the input.
Generalization
Richard Cole and David C. Kandathil, in 2004, discovered a one-parameter family of sorting algorithms, called partition sorts, which on average (with all input orderings equally likely) perform at most comparisons (close to the information theoretic lower bound) and operations; at worst they perform comparisons (and also operations); these are in-place, requiring only additional space. Practical efficiency and smaller variance in performance were demonstrated against optimized quicksorts (of Sedgewick and Bentley-McIlroy).[45]
See also
- Introsort – Hybrid sorting algorithm
Notes
- ↑"Sir Antony Hoare". Computer History Museum. Archived from the original on 3 April 2015. Retrieved 22 April 2015.
- ↑Wilson, John (3 April 2026). "Robert Fox, Mary Rand MBE, Sir Tony Hoare, Biruté Galdikas". Last Word, Radio 4. UK: BBC. Retrieved 4 April 2026. (14 minutes 50 seconds into the programme, interview with Bill Roscoe.)
- 12Hoare, C. A. R. (1961). "Algorithm 64: Quicksort". Comm. ACM. 4 (7): 321. doi:10.1145/366622.366644.
- ↑Skiena, Steven S. (2008). The Algorithm Design Manual. Springer. p. 129. ISBN 978-1-84800-069-8.
- ↑C.L. Foster, Algorithms, Abstraction and Implementation, 1992, ISBN 0122626605, p. 98
- ↑Shustek, L. (2009). "Interview: An interview with C.A.R. Hoare". Comm. ACM. 52 (3): 38–41. doi:10.1145/1467247.1467261. S2CID 1868477.
- ↑"My Quickshort interview with Sir Tony Hoare, the inventor of Quicksort". Marcelo M De Barros. 15 March 2015.
- 1 2 3 4 5 6 7 بنتلي، جون ل.؛ ماكلروي، م. دوغلاس (1993). "هندسة دالة فرز" . البرمجيات: الممارسة والخبرة . 23 (11): 1249-1265 . CiteSeerX 10.1.1.14.8162 . doi : 10.1002/spe.4380231105 . S2CID 8822797 .
- ↑ فان إمدن، إم إتش (1 نوفمبر 1970). "الخوارزميات 402: زيادة كفاءة الفرز السريع" . مجلة الاتصالات ACM . 13 (11): 693-694 . doi : 10.1145/362790.362803 . ISSN 0001-0782 . S2CID 4774719 .
- ↑ بنتلي، جون (2007). "أجمل كود لم أكتبه قط". في: أورام، آندي؛ ويلسون، جريج (محرران). الكود الجميل: مبرمجون بارزون يشرحون طريقة تفكيرهم . دار نشر أورايلي. ص 30. ISBN 978-0-596-51004-6.
- 1 2 3 "تقسيم الفرز السريع: مقارنة بين هوار ولوموتو" . cs.stackexchange.com . تم الاطلاع عليه بتاريخ 3 أغسطس 2015 .
- ↑ ماكيلروي، دكتور في الطب (10 أبريل 1999). "خصمٌ قاتلٌ لخوارزمية الفرز السريع" (ملف PDF) . البرمجيات: الممارسة والخبرة . 29 (4): 341-344 . doi : 10.1002/(SICI)1097-024X(19990410)29:4 < 341::AID-SPE237 > 3.0.CO ; 2-R . S2CID 35935409 .
- 1 2 جون بنتلي (1999). لآلئ البرمجة . أديسون-ويسلي بروفيشنال.
- 1 2 3 4 كورمين، توماس هـ . ليسرسون، تشارلز إي . ريفست، رونالد ل . شتاين، كليفورد (2009) [1990]. "الفرز السريع". مقدمة للخوارزميات ( الطبعة الثالثة). مطبعة معهد ماساتشوستس للتكنولوجيا وماكجرو هيل. ص 170 – 190. ISBN 0-262-03384-4.
- ^ وايلد ، سيباستيان (2012). Java 7's Dual Pivot Quicksort (أطروحة). الجامعة التقنية كايزرسلاوترن.
- ↑ هوار، سي. أ. ر. (1 يناير 1962). "الفرز السريع" . مجلة الحاسوب . 5 (1): 10-16 . doi : 10.1093/comjnl/5.1.10 . ISSN 0010-4620 .
- ↑ تشاندرا مولي، بادريش؛ غولدشتاين، جوناثان (18 يونيو 2014). "الصبر فضيلة" . وقائع مؤتمر ACM SIGMOD الدولي لإدارة البيانات لعام 2014. Sigmod '14. سنو بيرد، يوتا، الولايات المتحدة الأمريكية: ACM. الصفحات 731-742 . doi : 10.1145/2588555.2593662 . ISBN 978-1-4503-2376-5. S2CID 7830071 .
- 1 2 سيدجويك، روبرت (1 سبتمبر 1998). الخوارزميات في لغة سي: الأساسيات، هياكل البيانات، الفرز، البحث، الأجزاء 1-4 ( الطبعة الثالثة). بيرسون للتعليم. ISBN 978-81-317-1291-7.
- ↑ qsort.c في مكتبة GNU libc :،
- ↑ http://www.ugrad.cs.ubc.ca/~cs260/chnotes/ch6/Ch6CovCompiled.html
- 1 2 سيدجويك، ر. (1978). "تنفيذ برامج الفرز السريع". مجلة الاتصالات ACM . 21 (10): 847-857 . doi : 10.1145/359619.359631 . S2CID 10020756 .
- 1 2 3 لاماركا، أنتوني؛ لادنر، ريتشارد إي. (1999). "تأثير الذاكرة المؤقتة على أداء الفرز". مجلة الخوارزميات . 31 (1): 66-104 . CiteSeerX 10.1.1.27.1788 . doi : 10.1006/jagm.1998.0985 . S2CID 206567217.
على الرغم من أن حفظ المصفوفات الفرعية الصغيرة حتى النهاية يبدو منطقيًا من منظور عدد التعليمات، إلا أنه خطأ فادح من منظور أداء الذاكرة المؤقتة.
- ↑ أوموت أ. أكار، جاي إي بليلوش، مارغريت ريد ميلر، وكانات تانغوونغسان، الفرز السريع والحدود الدنيا للفرز ، هياكل البيانات المتوازية والمتسلسلة والخوارزميات . 2013.
- ↑ بريشيرز، كلاي (2012). "تقسيم الفرز السريع عبر مسح البادئة" . دكتور دوبز .
- ↑ ميلر، روس؛ بوكسر، لورانس (2000). الخوارزميات المتسلسلة والمتوازية: منهج موحد . برنتيس هول. ISBN 978-0-13-086373-7.
- ↑ باورز، ديفيد إم دبليو (1991). فرز سريع وفرز جذري متوازيان مع تسريع مثالي . وقائع المؤتمر الدولي لتقنيات الحوسبة المتوازية. CiteSeerX 10.1.1.57.9071 .
- ↑ قد يحتوي الآخر إما على عنصر واحد أو يكون فارغًا (يحتوي على 0 عناصر)، اعتمادًا على ما إذا كان المحور مدرجًا في أحد الأقسام الفرعية، كما هو الحال في روتين تقسيم هوار، أو مستبعدًا من كليهما، كما هو الحال في روتين لوموتو.
- ↑ موتاني، راجيف؛ راغافان، برابهاكار (25 أغسطس 1995). الخوارزميات العشوائية . مطبعة جامعة كامبريدج. ISBN 9780521474658.
- ↑ دوريان، برانيسلاف. "الفرز السريع بدون مكدس". الأسس الرياضية لعلوم الحاسوب 1986: وقائع الندوة الثانية عشرة . MFCS 1986. براتيسلافا، تشيكوسلوفاكيا: سبرينغر برلين هايدلبرغ.
- ↑ إيدلكامب، ستيفان؛ فايس، أرمين (7-8 يناير 2019). فرز فعال في أسوأ الحالات باستخدام QuickMergesort . ALENEX 2019: ورشة العمل الحادية والعشرون حول هندسة الخوارزميات والتجارب. سان دييغو. arXiv : 1811.99833 . doi : 10.1137/1.9781611975499.1 . ISBN 978-1-61197-549-9.
في الحالات الصغيرة، يكون Heapsort أبطأ بكثير من Quicksort (في تجاربنا أكثر من 30٪ لـ n = 2 10 ) وفي الحالات الأكبر يعاني من سلوك ذاكرة التخزين المؤقت الضعيف (في تجاربنا أبطأ بأكثر من ثماني مرات من Quicksort لفرز 2 28 عنصرًا).
- ↑ هسيه، بول (2004). "إعادة النظر في الفرز" . azillionmonkeys.com.
- ↑ ماكاي، ديفيد (ديسمبر 2005). "الفرز الهرمي، والفرز السريع، والإنتروبيا" . مؤرشف من الأصل في 1 أبريل 2009.
- 1 2 كوتينين، دانيلا (20 أبريل 2022). "تغيير std::sort على نطاق جوجل وما بعده" . Experimental chill .
- ↑ وايلد، سيباستيان؛ نيبيل، ماركوس إي. (2012). تحليل الحالة المتوسطة لخوارزمية الفرز السريع ثنائي المحور في جافا 7. الندوة الأوروبية حول الخوارزميات. arXiv : 1310.7409 . Bibcode : 2013arXiv1310.7409W .
- ↑ ياروسلافسكي، فلاديمير (2009). "الفرز السريع ثنائي المحور" (ملف PDF) . مؤرشف من الأصل (ملف PDF) في 2 أكتوبر 2015.
- ↑ وايلد، س.؛ نيبيل، م.؛ ريتزيغ، ر.؛ لاوب، يو. (7 يناير 2013). هندسة خوارزمية الفرز السريع ثنائي المحور في جافا 7 باستخدام MaLiJAn . وقائع الجمعية للرياضيات الصناعية والتطبيقية. ص 55-69 . doi : 10.1137/1.9781611972931.5 . ISBN 978-1-61197-253-5.
- ↑ "المصفوفات" . منصة جافا SE 7. أوراكل . تم الاطلاع عليه في 4 سبتمبر 2014 .
- ↑ وايلد، سيباستيان (3 نوفمبر 2015). "لماذا يعتبر فرز المحور المزدوج سريعًا؟". arXiv : 1511.01138 [ cs.DS ].
- ↑ كوشاغرا، شرينو؛ لوبيز-أورتيز، أليخاندرو؛ كياو، أوريك؛ مونرو، ج. إيان (2014). فرز سريع متعدد المحاور: النظرية والتجارب . وقائع ورشة عمل هندسة الخوارزميات والتجارب (ALENEX). doi : 10.1137/1.9781611973198.6 .
- ↑ كوشاغرا، شرينو؛ لوبيز أورتيز، أليخاندرو؛ مونرو، ج. إيان؛ تشياو ، أوريك (7 فبراير 2014). الفرز السريع متعدد المحاور: النظرية والتجارب (PDF) (عرض ندوة). واترلو، أونتاريو .
- ↑ موتزكين، د.؛ هانسن، سي إل (1982)، "فرز خارجي فعال بأقل متطلبات للمساحة"، المجلة الدولية لعلوم الحاسوب والمعلومات ، 11 (6): 381-396 ، doi : 10.1007/BF00996816 ، S2CID 6829805
- ↑ ديفيد إم دبليو باورز، التوحيد المتوازي: التعقيد العملي ، ورشة عمل هندسة الحاسوب الأسترالية، جامعة فليندرز، يناير 1995
- ↑ كاليغوسي، كانيلا؛ ساندرز، بيتر (11-13 سبتمبر 2006). كيف تؤثر التنبؤات الخاطئة للفروع على خوارزمية الفرز السريع (ملف PDF) . ESA 2006: الندوة الأوروبية السنوية الرابعة عشرة حول الخوارزميات. زيورخ . doi : 10.1007/11841036_69 .
- ^ اديلكامب ، ستيفان. فايس، أرمين (22 أبريل 2016). “BlockQuicksort: كيف لا تؤثر التوقعات الخاطئة للفرع على Quicksort”. أرخايف : 1604.06697 [ cs.DS ].
- ↑ ريتشارد كول، ديفيد سي. كانداثيل: "تحليل الحالة المتوسطة لفرز التقسيم" ، الندوة الأوروبية حول الخوارزميات، 14-17 سبتمبر 2004، بيرغن، النرويج. نُشر في: سلسلة محاضرات في علوم الحاسوب 3221، دار نشر سبرينغر، الصفحات 240-251.
مراجع
- سيدجويك، ر. (1978). "تنفيذ برامج الفرز السريع". مجلة الاتصالات ACM . 21 (10): 847-857 . doi : 10.1145/359619.359631 . S2CID 10020756 .
- دين، بي سي (2006). "تحليل بسيط لوقت التشغيل المتوقع لخوارزميات "فرق تسد" العشوائية" . الرياضيات التطبيقية المنفصلة . 154 : 1-5 . doi : 10.1016/j.dam.2005.07.005 .
- هوار، سي. إيه. آر. (1961). "الخوارزمية 63: التقسيم". مجلة الاتصالات التابعة لجمعية آلات الحوسبة . 4 (7): 321. doi : 10.1145/366622.366642 . S2CID 52800011 .
- هوار، سي. إيه. آر. (1961). "الخوارزمية 65: البحث". مجلة الاتصالات التابعة لجمعية آلات الحوسبة . 4 (7): 321-322 . doi : 10.1145/366622.366647 .
- هور، جمهورية أفريقيا الوسطى (1962). "الفرز السريع" . حساب. ج .5 (1): 10– 16. دوى : 10.1093/comjnl/5.1.10 .(أعيد طبعه في كتاب هوار وجونز: مقالات في علوم الحاسوب ، 1989.)
- موسر، ديفيد ر. (1997). "خوارزميات الفرز والاختيار الاستبطانية" . البرمجيات: الممارسة والخبرة . 27 (8): 983-993 . doi : 10.1002/(SICI)1097-024X(199708)27:8 < 983::AID-SPE117 > 3.0.CO ; 2-# .
- دونالد كنوث . فن برمجة الحاسوب ، المجلد 3: الفرز والبحث ، الطبعة الثالثة. أديسون-ويسلي، 1997. ISBN 0-201-89685-0الصفحات 113-122 من القسم 5.2.2: الفرز عن طريق التبادل.
- توماس هـ. كورمن ، تشارلز إي. ليسرسون ، رونالد ل. ريفست ، وكليفورد شتاين . مقدمة في الخوارزميات ، الطبعة الثانية. مطبعة معهد ماساتشوستس للتكنولوجيا وماكجرو هيل ، 2001. ISBN 0-262-03293-7الفصل 7: الفرز السريع، الصفحات 145-164.
- مولر، فارون . "تحليل خوارزمية الفرز السريع" (ملف PDF) . مؤرشف من الأصل (ملف PDF) بتاريخ 7 يوليو 2022. تم الاطلاع عليه بتاريخ 3 ديسمبر 2024 .(CS 332: تصميم الخوارزميات. قسم علوم الحاسوب، جامعة سوانسي .)
- مارتينيز، سي.؛ رورا، إس. (2001). "استراتيجيات أخذ العينات المثلى في الفرز السريع والاختيار السريع". مجلة SIAM للحوسبة 31 (3): 683-705 . CiteSeerX 10.1.1.17.4954 . doi : 10.1137/S0097539700382108 .
- بنتلي، جيه إل؛ ماكيلروي، إم دي (1993). "هندسة دالة فرز". البرمجيات: الممارسة والخبرة . 23 (11): 1249-1265 . CiteSeerX 10.1.1.14.8162 . doi : 10.1002/spe.4380231105 . S2CID 8822797 .
روابط خارجية
- "خوارزميات الفرز المتحركة: الفرز السريع" . مؤرشف من الأصل في 2 مارس 2015. تم الاطلاع عليه في 25 نوفمبر 2008 .– عرض توضيحي بياني
- "خوارزميات الفرز المتحركة: الفرز السريع (التقسيم ثلاثي الاتجاهات)" . مؤرشف من الأصل في 6 مارس 2015. تم الاطلاع عليه في 25 نوفمبر 2008 .
- هياكل البيانات المفتوحة - القسم 11.1.2 - الفرز السريع ، بات مورين
- رسم توضيحي تفاعلي لخوارزمية الفرز السريع ، مع شرح تفصيلي للبرنامج.
- الفرز السريع باستخدام خوارزمية الفرز السريع ، شرح متعمق مناسب للمبتدئين
- 1961 في مجال الحوسبة
- أنواع المقارنة
- خوارزميات فرق تسد
- توني هوار
