เหตุใดวิธี Arrays.sort ของ Java จึงใช้อัลกอริธึมการเรียงลำดับที่แตกต่างกันสองแบบสำหรับประเภทต่างๆ


121

Arrays.sortวิธีการของ Java 6 ใช้ Quicksort สำหรับอาร์เรย์ของ primitives และผสานการเรียงลำดับสำหรับอาร์เรย์ของวัตถุ ฉันเชื่อว่า Quicksort ส่วนใหญ่เร็วกว่าการจัดเรียงแบบผสานและใช้หน่วยความจำน้อยกว่า การทดลองของฉันสนับสนุนแม้ว่าอัลกอริทึมทั้งสองจะเป็น O (n log (n)) เหตุใดจึงใช้อัลกอริทึมที่แตกต่างกันสำหรับประเภทต่างๆ


14
Quicksort กรณีที่เลวร้ายที่สุดคือ N ^ 2 ไม่ใช่ NlogN
codaddict

เดี๋ยวก่อนจะเกิดอะไรขึ้นถ้าคุณมีอาร์เรย์ของIntegers หรืออะไร?
Tikhon Jelvis

1
สิ่งนี้ไม่ได้อธิบายไว้ในแหล่งที่มาที่คุณอ่าน?
Humphrey Bogart

5
ข้อมูลนี้ไม่เป็นปัจจุบันอีกต่อไป เริ่มต้นใน Java SE 7 mergesort ได้ถูกแทนที่ด้วยTimSortและ QuickSort ได้ถูกแทนที่ด้วยDual-Pivot QuickSort ดูคำตอบของฉันด้านล่างสำหรับลิงก์ไปยังเอกสาร Java API
Will Byrne

คำตอบ:


200

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

เนื่องจากประเภทดั้งเดิมไม่มีตัวตน (ไม่มีวิธีแยกแยะสอง ints ที่มีค่าเท่ากัน) สิ่งนี้จึงไม่สำคัญสำหรับพวกเขา แต่สำหรับประเภทการอ้างอิงอาจทำให้เกิดปัญหากับบางแอปพลิเคชัน ดังนั้นจึงใช้การเรียงลำดับการผสานที่เสถียรสำหรับสิ่งเหล่านั้น

OTOH เหตุผลที่ไม่ใช้การเรียงลำดับการผสานที่เสถียร (รับประกัน n * log (n)) สำหรับประเภทดั้งเดิมอาจเป็นเพราะต้องสร้างโคลนของอาร์เรย์ สำหรับประเภทการอ้างอิงโดยที่วัตถุที่อ้างถึงมักใช้หน่วยความจำมากกว่าอาร์เรย์ของการอ้างอิงโดยทั่วไปไม่สำคัญ แต่สำหรับประเภทดั้งเดิมการโคลนอาร์เรย์ทันทีจะเพิ่มการใช้หน่วยความจำเป็นสองเท่า


1
อีกเหตุผลหนึ่งในการใช้ Quicksort คือโดยทั่วไป Quicksort จะเร็วกว่าการผสาน แม้ว่า Quicksort จะเปรียบเทียบได้มากกว่าการผสาน แต่ก็เข้าถึงอาร์เรย์น้อยกว่ามาก Quicksort 3 ทางยังสามารถบรรลุเวลาเชิงเส้นได้หากอินพุตมีรายการที่ซ้ำกันจำนวนมากซึ่งไม่ผิดปกติในการใช้งานจริง (ฉันเดาว่าการเรียงลำดับอย่างรวดเร็วของเดือยคู่ก็มีคุณสมบัตินี้เช่นกัน)
Jingguo Yao

สำหรับประเภทดั้งเดิมมันไม่ได้โคลนอาร์เรย์มันสามารถเรียงลำดับได้ดังนั้นฉันคิดว่าเหตุผลเดียวคือสัญญาเสถียรภาพโดยทั่วไป ...
rogerdpack

27

ตาม Java 7 เอกสาร API ที่อ้างถึงในคำตอบนี้ , Arrays#Sort()สำหรับอาร์เรย์วัตถุตอนนี้ใช้TimSortซึ่งเป็นไฮบริดของ mergesort และการเรียงลำดับแบบแทรก บนมืออื่น ๆ , Arrays#sort()สำหรับอาร์เรย์ดั้งเดิมตอนนี้ใช้Dual-Pivot QuickSort การเปลี่ยนแปลงเหล่านี้เริ่มใช้งานใน Java SE 7


2
ไม่ใช่คำตอบทำไมถึงเลือกอัลกอริทึม 2 แบบที่แตกต่างกัน
Alexandr

12

เหตุผลหนึ่งที่ฉันคิดได้คือ Quicksort มีความซับซ้อนของเวลากรณีที่เลวร้ายที่สุดของ O ( n ^ 2 ) ในขณะที่การผสานยังคงรักษาเวลากรณีที่เลวร้ายที่สุดของ O ( n log n ) สำหรับอาร์เรย์อ็อบเจ็กต์มีความคาดหวังที่ยุติธรรมว่าจะมีการอ้างอิงอ็อบเจ็กต์ที่ซ้ำกันหลายครั้งซึ่งเป็นกรณีหนึ่งที่ Quicksort ทำได้แย่ที่สุด

มีการเปรียบเทียบภาพที่ดีของอัลกอริทึมต่างๆให้ความสนใจเป็นพิเศษกับกราฟด้านขวาสุดสำหรับอัลกอริทึมที่แตกต่างกัน


2
Quicksort ของ java คือ Quicksort ที่ได้รับการแก้ไขซึ่งไม่ลดทอนประสิทธิภาพเป็น O (n ^ 2) จากเอกสาร "อัลกอริทึมนี้มีประสิทธิภาพ n * log (n) ในชุดข้อมูลจำนวนมากที่ทำให้
Quicksort

7

ฉันกำลังเรียน Coursera เกี่ยวกับอัลกอริทึมและในการบรรยายครั้งหนึ่งศาสตราจารย์ Bob Sedgewick กล่าวถึงการประเมินระบบ Java:

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


4
มันไม่ใช่เหตุผลหลัก หลังจากประโยคนั้นมีคำถามฝังอยู่ในวิดีโอเกี่ยวกับ "เหตุใดจึงใช้ประเภทการอ้างอิง MergeSort" (เพราะมันเสถียร). ฉันคิดว่า Sedgewick ไม่ได้พูดถึงเรื่องนั้นในวิดีโอเพื่อทิ้งคำถามไว้
likern

1

java.util.Arraysใช้quicksortชนิดดั้งเดิมเช่น int และmergesortสำหรับวัตถุที่ใช้เทียบเคียงหรือใช้เปรียบเทียบ แนวคิดในการใช้สองวิธีที่แตกต่างกันคือถ้าโปรแกรมเมอร์ใช้วัตถุบางทีพื้นที่ไม่ใช่การพิจารณาที่สำคัญอย่างยิ่งดังนั้นพื้นที่เพิ่มเติมที่ใช้โดยการผสานอาจไม่ใช่ปัญหาและหากโปรแกรมเมอร์ที่ใช้ประเภทดั้งเดิมประสิทธิภาพอาจเป็นสิ่งที่สำคัญที่สุดให้ใช้quicksort

ตัวอย่าง: นี่คือตัวอย่างเมื่อการเรียงลำดับความเสถียรมีความสำคัญ

ใส่คำอธิบายภาพที่นี่

นั่นเป็นเหตุผลว่าทำไมประเภทที่เสถียรจึงมีความหมายสำหรับประเภทอ็อบเจ็กต์โดยเฉพาะประเภทอ็อบเจ็กต์ที่ไม่แน่นอนและประเภทอ็อบเจ็กต์ที่มีข้อมูลมากกว่าคีย์การจัดเรียงและการผสานคือการจัดเรียง แต่สำหรับความเสถียรของประเภทดั้งเดิมนั้นไม่เพียง แต่ไม่เกี่ยวข้อง มันไม่มีความหมาย

ที่มา: INFO


0

Arrays.sortวิธีการของ Java ใช้ Quicksort การเรียงลำดับการแทรกและการผสาน แม้จะมีการใช้งาน Pivot Quicksort แบบเดี่ยวและแบบคู่ในโค้ด OpenJDK อัลกอริธึมการเรียงลำดับที่เร็วที่สุดขึ้นอยู่กับสถานการณ์และผู้ชนะ ได้แก่ : การเรียงลำดับการแทรกสำหรับอาร์เรย์ขนาดเล็ก (47 ที่เลือกในปัจจุบัน) การผสานสำหรับอาร์เรย์ที่เรียงลำดับส่วนใหญ่และ Quicksort สำหรับอาร์เรย์ที่เหลือดังนั้น Array.sort () ของ Java จึงพยายามเลือกอัลกอริทึมที่ดีที่สุดเพื่อ ใช้ตามเกณฑ์เหล่านั้น

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