ขั้นตอนวิธีการเรียงลำดับแต่ละครั้งจะถูกใช้เมื่อใด [ปิด]


170

กรณีการใช้งานอะไรบ้างเมื่ออัลกอริทึมการเรียงลำดับเฉพาะเจาะจงเหนือสิ่งอื่น - ผสานการเรียงลำดับกับ QuickSort เทียบกับ heapsort เทียบกับ 'การเรียงลำดับบทนำ' ฯลฯ

มีคำแนะนำในการใช้งานหรือไม่ขึ้นอยู่กับขนาดชนิดของโครงสร้างข้อมูลหน่วยความจำและแคชที่มีอยู่และประสิทธิภาพของ CPU


ชุดของภาพเคลื่อนไหวสำหรับข้อมูลและอัลกอริธึมชนิดต่าง ๆ สามารถดูได้ที่ <a href=" sorting-algorithms.com/"> sorting-algorithms.com </ a >
Chip Uni

2
คู่มือเช่นbigocheatsheet.comสำหรับสิ่งนี้จะเป็น greaaaat
K - ความเป็นพิษใน SO กำลังเพิ่มขึ้น

@ ชิพยูนี่นี่คือลิงค์คงที่: toptal.com/developers/sorting-algorithms
eric

2
ทำไมคำถามนี้ถึงปิด!
Arvand

คำตอบ:


316

ก่อนอื่นคำจำกัดความเนื่องจากมันค่อนข้างสำคัญ: การเรียงที่เสถียรนั้นเป็นสิ่งที่รับประกันได้ว่าจะไม่เรียงลำดับองค์ประกอบด้วยปุ่มเหมือนกัน

คำแนะนำ:

การจัดเรียงอย่างรวดเร็ว: เมื่อคุณไม่ต้องการการเรียงลำดับที่เสถียรและประสิทธิภาพตัวพิมพ์เล็กโดยทั่วไปนั้นสำคัญกว่าประสิทธิภาพของตัวพิมพ์เล็กที่สุด การเรียงลำดับแบบด่วนคือ O (N log N) โดยเฉลี่ย O (N ^ 2) ในกรณีที่เลวร้ายที่สุด การใช้งานที่ดีใช้หน่วยเก็บข้อมูลสำรอง O (log N) ในรูปแบบของพื้นที่สแต็กสำหรับการเรียกซ้ำ

ผสานการเรียงลำดับ: เมื่อคุณต้องการความเสถียรการเรียงลำดับ O (N log N) นี่เป็นเพียงตัวเลือกเดียวของคุณ ข้อเสียเพียงอย่างเดียวคือมันใช้พื้นที่เสริม O (N) และมีค่าคงที่ที่ใหญ่กว่าการจัดเรียงอย่างรวดเร็วเล็กน้อย มีบางอย่างในสถานที่ผสาน แต่ AFAIK ทั้งหมดไม่เสถียรหรือแย่กว่า O (N log N) แม้แต่ O (N log N) ในสถานที่ต่าง ๆ ก็มีค่าคงที่มากกว่าการรวมแบบเก่าแบบธรรมดามากจนพวกมันน่าสนใจทางทฤษฎีมากกว่าอัลกอริธึมที่มีประโยชน์

การเรียงลำดับฮีป: เมื่อคุณไม่ต้องการการจัดเรียงที่เสถียรและคุณให้ความสำคัญกับประสิทธิภาพของเคสที่แย่ที่สุดกว่าประสิทธิภาพเคสโดยเฉลี่ย มันรับประกันว่าจะเป็น O (N log N) และใช้พื้นที่เสริม O (1) ซึ่งหมายความว่าคุณจะไม่ใช้พื้นที่ฮีปหรือสแต็กโดยไม่คาดคิดในอินพุตที่มีขนาดใหญ่มาก

Introsort: นี่คือการเรียงลำดับอย่างรวดเร็วที่สลับไปยังการเรียงลำดับฮีปหลังจากความลึกการวนซ้ำที่แน่นอนเพื่อหลีกเลี่ยงกรณีที่เลวร้ายที่สุดของ O (N ^ 2) มันเกือบจะดีกว่าการจัดเรียงแบบเร็วแบบเก่า ๆ เกือบทุกครั้งเนื่องจากคุณได้รับตัวพิมพ์เร็วโดยเฉลี่ยด้วยประสิทธิภาพ O (N log N) อาจเป็นเหตุผลเดียวที่จะใช้การเรียงลำดับฮีพแทนสิ่งนี้คือในระบบที่ จำกัด หน่วยความจำอย่างรุนแรงซึ่งพื้นที่สแต็ก O (log N) มีความสำคัญในทางปฏิบัติ

การเรียงลำดับการแทรก : เมื่อรับประกันว่า N จะมีขนาดเล็กรวมถึงเป็นกรณีพื้นฐานของการจัดเรียงอย่างรวดเร็วหรือการจัดเรียงผสาน แม้ว่านี่จะเป็น O (N ^ 2) แต่ก็มีค่าคงที่ที่เล็กมากและมีความเสถียร

การเรียงลำดับฟองการเรียงลำดับการเลือก : เมื่อคุณทำสิ่งที่รวดเร็วและสกปรกและด้วยเหตุผลบางอย่างคุณไม่สามารถใช้อัลกอริทึมการเรียงลำดับของไลบรารีมาตรฐานได้ ข้อได้เปรียบเพียงอย่างเดียวที่มีมากกว่าการเรียงลำดับการแทรกนั้นง่ายกว่าเล็กน้อยที่จะนำไปใช้


การเรียงลำดับที่ไม่ใช่การเปรียบเทียบ: ภายใต้เงื่อนไขที่ จำกัด บางอย่างเป็นไปได้ที่จะทำลายสิ่งกีดขวาง O (N log N) และเรียงลำดับใน O (N) ต่อไปนี้เป็นกรณีที่ควรลอง:

การเรียงลำดับการนับ: เมื่อคุณเรียงลำดับเลขจำนวนเต็มด้วยช่วง จำกัด

การจัดเรียง Radix: เมื่อ log (N) มีขนาดใหญ่กว่า K อย่างมีนัยสำคัญที่ K คือจำนวนของตัวเลขฐานราก

ถังเรียง: เมื่อคุณสามารถรับประกันได้ว่าการป้อนข้อมูลของคุณมีการกระจายอย่างสม่ำเสมอ


1
ในขณะที่ฉันจำได้ว่า heap sort นั้นมีเวลาทำงานที่สามารถคาดเดาได้มากว่ามีความแตกต่างกันเล็กน้อยในอินพุตที่มีขนาดเท่ากัน แต่ก็มีความสนใจน้อยกว่าพื้นที่คงที่ ฉันยังพบว่าการเรียงลำดับการแทรกนั้นง่ายที่สุดที่จะนำไปใช้กับ n ^ 2 ทุกประเภท ในที่สุดคุณอาจต้องการพูดถึงการเรียงลำดับของเชลล์ซึ่งเกือบจะเป็นเรื่องง่ายที่จะใช้เป็นการเรียงลำดับการแทรก แต่มีประสิทธิภาพที่ดีขึ้นแม้ว่าจะยังไม่ได้เข้าสู่ระบบ n
JaakkoK

29
อย่าลืมBogosort ! ;-)
Alex Brasetvik

2
+1 น่าสนใจมาก คุณสนใจที่จะอธิบายวิธีที่คุณสามารถ "รับประกัน ... กระจายอย่างสม่ำเสมอโดยประมาณ" สำหรับถังเรียง?
Sam Overton

2
ทำไม Introsort ถึงช้ากว่าการจัดเรียงอย่างรวดเร็ว? ค่าใช้จ่ายเพียงอย่างเดียวคือการนับความลึกของการเรียกซ้ำซึ่งควรจะเล็กน้อย มันสลับเฉพาะหลังจากการเรียกซ้ำลึกกว่าที่ควรจะเป็นในกรณีการเรียงลำดับที่ดี
dsimcha

2
คุณไม่ได้พูดถึงกรณีที่ดีที่สุดของการจัดเรียงฟองคือ O (n)!
ธารา

33

Quicksortมักจะเร็วที่สุดโดยเฉลี่ย แต่มันมีพฤติกรรมที่เลวร้ายที่สุดที่น่ารังเกียจ ดังนั้นหากคุณต้องรับประกันว่าจะไม่มีข้อมูลที่ไม่ดีมาให้O(N^2)คุณควรหลีกเลี่ยง

Merge-sortใช้หน่วยความจำเพิ่มเติม แต่เหมาะอย่างยิ่งสำหรับการจัดเรียงภายนอก (เช่นไฟล์ขนาดใหญ่ที่ไม่พอดีกับหน่วยความจำ)

Heap-sortสามารถเรียงลำดับในตำแหน่งและไม่มีพฤติกรรมกำลังสองกรณีที่เลวร้ายที่สุด แต่โดยเฉลี่ยจะช้ากว่า quicksort ในกรณีส่วนใหญ่

ในกรณีที่มีเฉพาะจำนวนเต็มในช่วงที่ จำกัด คุณสามารถใช้การเรียงลำดับแบบ Radix บางประเภทเพื่อทำให้รวดเร็วมาก

ใน 99% ของกรณีคุณจะไม่เป็นไรกับห้องสมุดซึ่งมักจะอิงจากการเรียงลำดับแบบด่วน


6
+1: สำหรับ "ใน 99% ของทุกกรณีคุณจะไม่เป็นไรกับห้องสมุดซึ่งมักจะอ้างอิงจาก quicksort"
Jim G.

การสุ่ม pivoting ให้ Quicksort รันไทม์ของ O (nlogn) สำหรับวัตถุประสงค์ในทางปฏิบัติทั้งหมดโดยไม่จำเป็นต้องมีการรับประกันใด ๆ เกี่ยวกับข้อมูลที่ไม่ดี ฉันไม่คิดว่าใครจะใช้ Quicksort O (n ^ 2) สำหรับรหัสการผลิตใด ๆ
MAK

2
MAK ยกเว้น qsort ไลบรารีมาตรฐาน C หรือไม่ ( google.com/codesearch/… ) - ตามที่ "รหัสการผลิต" ส่วนใหญ่พึ่งพา
Eli Bendersky

การเรียงลำดับไลบรารีไม่ได้ขึ้นอยู่กับ quicksort เนื่องจากมันไม่เสถียร เกือบทุกภาษาที่สูงกว่า (คาดหวังสำหรับ C) ให้เรียงลำดับที่มีเสถียรภาพ ในกรณีส่วนใหญ่ฉันรู้ว่าคุณต้องมีความมั่นคงหรืออย่างน้อยก็กำหนดประเภท
12431234123412341234123


3

สิ่งที่ลิงก์ที่ให้ไว้เพื่อเปรียบเทียบ / แอนิเมชั่นไม่ได้พิจารณาคือเมื่อปริมาณข้อมูลเกินกว่าหน่วยความจำที่มีอยู่ --- ณ จุดที่จำนวนการส่งผ่านข้อมูลเช่น I / O-cost จะควบคุมรันไทม์ หากคุณจำเป็นต้องทำเช่นนั้นอ่านได้ที่ "การเรียงลำดับภายนอก" ซึ่งมักจะครอบคลุมหลากหลายรูปแบบของการผสานและฮีป

http://corte.si/posts/code/visualisingsorting/index.htmlและhttp://corte.si/posts/code/timsort/index.htmlนอกจากนี้ยังมีรูปภาพเจ๋ง ๆ เปรียบเทียบกับอัลกอริทึมการเรียงลำดับต่างๆ


0

@dsimcha wrote: การเรียงลำดับการนับ: เมื่อคุณเรียงลำดับจำนวนเต็มด้วยช่วงที่ จำกัด

ฉันจะเปลี่ยนเป็น:

การเรียงลำดับการนับ: เมื่อคุณเรียงลำดับจำนวนเต็มบวก (0 - Integer.MAX_VALUE-2 เนื่องจากช่องว่าง)

คุณสามารถรับค่าสูงสุดและต่ำสุดเป็นวิธีแก้ปัญหาประสิทธิภาพในเวลาเชิงเส้นเช่นกัน
นอกจากนี้คุณต้องมีพื้นที่พิเศษอย่างน้อย n สำหรับอาร์เรย์กลางและมีความเสถียรอย่างเห็นได้ชัด

/**
* Some VMs reserve some header words in an array.
* Attempts to allocate larger arrays may result in
* OutOfMemoryError: Requested array size exceeds VM limit
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

(แม้ว่าจริง ๆ แล้วจะอนุญาตให้ MAX_VALUE-2) ดู: อาร์เรย์ Java มีขนาดสูงสุดหรือไม่

นอกจากนี้ฉันจะอธิบายว่าความซับซ้อนในการจัดเรียงของ Radix คือ O (wn) สำหรับ n keys ซึ่งเป็นจำนวนเต็มของขนาดคำ w บางครั้ง w ถูกนำเสนอเป็นค่าคงที่ซึ่งจะทำให้การเรียงลำดับแบบ radix ดีขึ้น (สำหรับขนาดใหญ่พอ n) กว่าอัลกอริทึมการเรียงลำดับแบบอิงการเปรียบเทียบที่ดีที่สุดซึ่งทั้งหมดทำการเปรียบเทียบ O (n log n) เพื่อเรียงลำดับปุ่ม n อย่างไรก็ตามโดยทั่วไป w ไม่สามารถพิจารณาค่าคงที่ได้: หากปุ่ม n ทั้งหมดแตกต่างกันดังนั้นอย่างน้อย w จะต้องมี log n อย่างน้อยสำหรับเครื่องที่เข้าถึงแบบสุ่มเพื่อให้สามารถเก็บไว้ในหน่วยความจำได้ (n บันทึก n) (จากวิกิพีเดีย)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.