อัลกอริธึมการเรียงลำดับที่เร็วที่สุดสำหรับอาเรย์ของจำนวนเต็มคืออะไร?


55

ฉันเจออัลกอริธึมการเรียงลำดับจำนวนมากในระหว่างที่เรียนอยู่มัธยม อย่างไรก็ตามฉันไม่เคยรู้ว่าอันไหนเร็วที่สุด (สำหรับอาร์เรย์จำนวนเต็มแบบสุ่ม) ดังนั้นคำถามของฉันคือ:

  • อัลกอริทึมการเรียงลำดับที่รู้จักกันเร็วที่สุดในขณะนี้คืออะไร
  • ในทางทฤษฎีมันเป็นไปได้ไหมที่จะมีคนที่เร็วขึ้น? ดังนั้นการเรียงลำดับที่ซับซ้อนน้อยที่สุดคืออะไร?

6
คุณหมายถึงอะไรโดย "เร็ว" คุณต้องการวัดอะไร
กราฟิลส์

2
"อาร์เรย์จำนวนเต็มแบบสุ่ม" หมายความว่าอะไร สุ่มกับการแจกแจงแบบไหน? กระจายสม่ำเสมอ? เกาส์? ขึ้นอยู่กับการแจกแจงอาจจะดีกว่าอัลกอริทึมเวลาทำงานที่คาดไว้ O(nเข้าสู่ระบบn)
Bakuriu

@ Gen ลองดูที่การจัดเรียง Radix การใช้งานที่ถูกต้องมีความซับซ้อน O (n) สำหรับ Int32 เช่น
นี้


1
@ Gen: ในแง่ของ asymptotics? จากนั้นง่าย: เลือกอัลกอริทึมΘ ( n log n )ใด ๆ โปรดทราบว่าสิ่งนี้อาจไม่มีส่วนเกี่ยวข้องกับประสิทธิภาพการทำงานจริง (โดยเฉลี่ย) นี่อาจเป็นการอ่านที่คุ้มค่าในเรื่องนี้ ΘΘ(nlogn)
กราฟิลส์

คำตอบ:


42

โดยทั่วไปมีอัลกอริทึมการเรียงลำดับ n 2 )เช่นการจัดเรียงการแทรกการเรียงฟองและการเรียงลำดับการเลือกซึ่งโดยทั่วไปคุณควรใช้เฉพาะในกรณีพิเศษเท่านั้น Quicksort ซึ่งเป็นกรณีที่เลวร้ายที่สุด O ( n 2 )แต่ค่อนข้างบ่อย O ( n log n ) ที่มีค่าคงที่และคุณสมบัติที่ดีและสามารถใช้เป็นขั้นตอนการจัดเรียงทั่วไปได้ O ( n log n )ขั้นตอนวิธีการเช่นเดียวกับการผสานเรียงลำดับและกองเรียงลำดับซึ่งนอกจากนี้ยังมีวัตถุประสงค์ทั่วไปเรียงลำดับขั้นตอนวิธีการที่ดี และ O ( nO(n2)O(n2)O(nเข้าสู่ระบบn)O(nเข้าสู่ระบบn)หรืออัลกอริทึมการเรียงลำดับอัลกอริธึมสำหรับรายการจำนวนเต็มเช่น Radix ที่ฝากข้อมูลและการนับประเภทซึ่งอาจเหมาะสมขึ้นอยู่กับลักษณะของจำนวนเต็มในรายการของคุณO(n)

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

โดยทั่วไปแล้วการเพิ่มประสิทธิภาพของอัลกอริธึมการเรียงลำดับขึ้นอยู่กับสมมติฐานที่คุณสามารถทำกับรายการที่คุณกำลังจะเรียงลำดับ (เช่นเดียวกับโมเดลเครื่องที่อัลกอริทึมจะทำงานซึ่งอาจทำให้การเรียงลำดับไม่ดี อัลกอริธึมเป็นตัวเลือกที่ดีที่สุดพิจารณาการจัดเรียงฟองสบู่ด้วยเครื่องสำหรับเก็บข้อมูล) ยิ่งสมมติฐานของคุณแข็งแกร่งขึ้นเท่าไหร่มุมของอัลกอริทึมของคุณก็ยิ่งมากขึ้นเท่านั้น ภายใต้สมมติฐานที่อ่อนแอมากเกี่ยวกับวิธีการได้อย่างมีประสิทธิภาพคุณสามารถกำหนด "sortedness" ของรายการความซับซ้อนที่ดีที่สุดเลวร้ายที่สุดกรณียังสามารถเป็น )Ω(n!)

คำตอบนี้เกี่ยวข้องกับความซับซ้อนเท่านั้น เวลาทำงานจริงของการปรับใช้อัลกอริทึมจะขึ้นอยู่กับปัจจัยจำนวนมากซึ่งยากที่จะอธิบายในคำตอบเดียว


ฉันเดาว่าเหล่านั้นควรเป็นΩ ? OΩ
Raphael

1
@ ราฟาเอลเมห์ ฉันคิดว่าพวกเขาส่วนใหญ่เป็นอย่างไรก็ตาม ฉันคิดว่าขอบเขตที่ต่ำอาจจะมีการแสดงที่ดีกว่าΩ ฉันจะเปลี่ยนคู่ของพวกเขาที่เหมาะสมที่สุด ΘΩ
Patrick87

7
ผมลงคะแนน @Raphael ได้รับตำรวจหมวก : PΩ
Realz Slaw

2
@ RealzSlaw: ฉันใส่มันอย่างภาคภูมิใจ :]
Raphael

1
@gen ดูstackoverflow.com/a/3274203สำหรับการสนทนา โดยทั่วไปถ้าแต่ละเรคคอร์ดมีขนาดใหญ่และมันไม่ได้ถูกเก็บไว้ในวิธีการเข้าถึงแบบสุ่มและปริมาณของข้อมูลที่จะต้องทำในสถานที่แล้วการเรียงลำดับของฟองเป็นวิธีที่จะไป สถานการณ์เหล่านี้มักจะไม่ค่อยเกิดขึ้นในปัจจุบัน แต่คุณยังอาจพบเจอ
Patrick87

16

คำตอบที่มักจะเป็นสำหรับคำถามเช่นนี้คือ "มันขึ้นอยู่กับ" มันขึ้นอยู่กับสิ่งต่าง ๆ เช่น (a) จำนวนเต็มมีขนาดใหญ่แค่ไหน (b) ไม่ว่าอาร์เรย์อินพุทจะมีจำนวนเต็มตามลำดับแบบสุ่มหรือเรียงตามลำดับเกือบ (c) ไม่ว่าคุณต้องการอัลกอริทึมการเรียงลำดับที่เสถียรหรือไม่ เช่นเดียวกับปัจจัยอื่น ๆ (d) รายการทั้งหมดของตัวเลขเหมาะกับหน่วยความจำ (การเรียงลำดับในหน่วยความจำเทียบกับการเรียงลำดับภายนอก) และ (e) เครื่องที่คุณใช้งาน

ในทางปฏิบัติอัลกอริทึมการเรียงลำดับในไลบรารีมาตรฐานของภาษาของคุณอาจจะค่อนข้างดี (ค่อนข้างใกล้เคียงกับดีที่สุด) หากคุณต้องการการเรียงลำดับในหน่วยความจำ ดังนั้นในทางปฏิบัติเพียงใช้ฟังก์ชั่นการเรียงลำดับใดก็ตามที่มีให้โดยไลบรารีมาตรฐานและวัดเวลาทำงาน เฉพาะในกรณีที่คุณพบว่า (i) การเรียงลำดับเป็นส่วนใหญ่ของเวลาทำงานโดยรวมและ (ii) เวลาทำงานไม่สามารถยอมรับได้คุณควรยุ่งกับระเบียบวิธีอัลกอริธึม ถ้าทั้งสองเงื่อนไขไม่ถือแล้วคุณสามารถดูลักษณะเฉพาะของโดเมนของคุณโดยเฉพาะและการทดสอบกับขั้นตอนวิธีการเรียงลำดับอย่างรวดเร็วอื่น ๆ

แต่ในทางปฏิบัติในทางปฏิบัติอัลกอริทึมการเรียงลำดับไม่ค่อยเป็นปัญหาคอขวดที่สำคัญ


9

นอกจากนี้ตอบคำถามที่สองของคุณ

ในทางทฤษฎีมันเป็นไปได้ไหมที่จะมีคนที่เร็วขึ้น?
ดังนั้นการเรียงลำดับที่ซับซ้อนน้อยที่สุดคืออะไร?

สำหรับการเรียงวัตถุประสงค์ทั่วไป เรียงลำดับปัญหาการเปรียบเทียบตามความซับซ้อนเป็น Ω (n log n) มีอัลกอริธึมบางอย่างที่ดำเนินการเรียงลำดับใน O (n) แต่ทั้งหมดนั้นขึ้นอยู่กับการตั้งสมมติฐานเกี่ยวกับอินพุตและไม่ใช่อัลกอริทึมการเรียงลำดับวัตถุประสงค์ทั่วไป

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

คุณสามารถหาหลักฐานที่เป็นทางการสำหรับการเรียงลำดับความซับซ้อนที่ต่ำกว่าที่นี่ :


3
คำตอบนี้ไม่ถูกต้องนัก ไม่ใช่ขอบเขตล่างแบบสากลสำหรับการเรียงลำดับ ขอบเขตล่างนั้นใช้กับการเรียงลำดับแบบอิงการเปรียบเทียบเท่านั้นเช่นอัลกอริทึมการเรียงลำดับที่ใช้การเปรียบเทียบเท่านั้น อัลกอริทึมการเรียงลำดับบางอย่างไม่ได้อิงการเปรียบเทียบ คำสั่ง "มีอัลกอริทึมบางอย่างที่ดำเนินการเรียงลำดับใน O (n) แต่พวกเขาทั้งหมดขึ้นอยู่กับการตั้งสมมติฐานเกี่ยวกับอินพุตและไม่ใช่อัลกอริทึมการเรียงลำดับวัตถุประสงค์ทั่วไป" อาจทำให้เข้าใจผิดเล็กน้อย - ระวัง Radix-sort เป็นอัลกอริทึมการเรียงลำดับวัตถุประสงค์ทั่วไป (สมมติว่าคุณกำลังเรียงลำดับจำนวนเต็มความกว้างคงที่) Ω(nเข้าสู่ระบบn)
DW

ขึ้นอยู่กับสิ่งที่คุณหมายถึงโดยปัญหาการเรียงลำดับ การเรียงลำดับตามวัตถุประสงค์ทั่วไปไม่ใช่ปัญหาการเรียงลำดับที่ผู้คนมี
Patrick87

1
แน่นอนว่าเป็นเรื่องจริง ฉันควรจะเจาะจงมากขึ้นขอบคุณที่ชี้ให้เห็น อย่างไรก็ตามฉันค่อนข้างสงสัยเกี่ยวกับวิธีการเรียงลำดับอื่น ๆ (ไม่ใช่แบบอิงการเปรียบเทียบ) ที่คุณอ้างถึง การจัดเรียง Radix เป็นประเภทของอัลกอริทึม O (n) ที่ฉันพูดถึง - คุณต้อง 'สมมติ' บางสิ่งเกี่ยวกับอินพุต (จำนวนเต็มความกว้างคงที่) ในแง่นี้มันไม่ได้เป็นอัลกอริทึมการเรียงลำดับวัตถุประสงค์ทั่วไปใช่มั้ย
rla4

1
@DW: การเรียงลำดับ Radix ไม่ควรพิจารณาอัลกอริทึมการเรียงลำดับ 'วัตถุประสงค์ทั่วไป' เพราะต้องใช้คีย์จำนวนเต็มความยาวคงที่ มันไม่มีประโยชน์อย่างอื่น แต่ฉันได้รับคะแนนของคุณ :) ฉันเดาว่าความผิดพลาดของฉันคือการมุ่งเน้นไปที่การเรียงลำดับสิ่งของที่สามารถเปรียบเทียบได้แทนที่จะเรียงลำดับจำนวนเต็มเป็นพิเศษ พวกเขามีปัญหาที่แตกต่างกันและมีวิธีแก้ปัญหาต่าง ๆ ที่เป็นไปได้ คำถามนี้พูดถึง "อาร์เรย์จำนวนเต็มแบบสุ่ม" แต่ฉันยอมรับว่าฉันเอามันมาเป็นตัวอย่างแทนที่จะเป็นข้อ จำกัด
rla4

2
@DavidRicherby เมื่อมองย้อนกลับไปหลังจากผ่านไปครึ่งปีฉันเห็นด้วยกับคุณ ขอขอบคุณ.
DW

3

อัลกอริทึมการเรียงลำดับจำนวนเต็มเร็วที่สุดในแง่ของกรณีที่แย่ที่สุดที่ฉันเจอคือAndersson et al แต่ก็มีกรณีที่แย่ที่สุดของซึ่งเป็นหลักสูตรที่เร็วกว่าO ( n log n )O(nเข้าสู่ระบบเข้าสู่ระบบn)O(nเข้าสู่ระบบn)


2
น่าสนใจมาก แต่คุณต้องให้ข้อมูลเพิ่มเติม เมื่อคุณพูดถึงผมถือว่าคุณทราบว่าการเรียงลำดับการเปรียบเทียบตามของจำนวนเต็มทั่วไปสรรพสิ่งต้องใช้เวลาΩ ( n log n ) สิ่งใดที่เร็วกว่าที่ต้องทำในเรื่อง asymptotically สมมติฐานเกี่ยวกับข้อมูล: ตัวอย่างเช่นการเรียงลำดับแบบ Radix จะทำงานในเวลาเชิงเส้นสมมติว่าองค์ประกอบทุกส่วนของอาร์เรย์มีค่าคงที่มากที่สุด อัลกอริทึมนี้จัดเรียงตามเงื่อนไขใดในO ( n log log n )และมันทำงานอย่างไรกับอัลกอริทึมอื่น ๆ เช่น quicksort และ radix sort nlognΩ(nlogn)O(nเข้าสู่ระบบเข้าสู่ระบบn)
David Richerby

1

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

รับอาร์เรย์มีองค์ประกอบจำนวนเต็มn รายการคุณต้องเปรียบเทียบ( n - 1 ) ให้ตรงกันเพื่อตรวจสอบว่าAเรียงลำดับหรือไม่ (เพิ่งเริ่มต้นที่จุดเริ่มต้นของอาร์เรย์และตรวจสอบองค์ประกอบถัดไปกับองค์ประกอบสุดท้าย) ในความเป็นจริงแล้วการเปรียบเทียบ( n - 1 )เป็นกรณีที่ดีที่สุดที่ใช้เวลาในการเรียงลำดับอัลกอริทึม ในคำอื่น ๆ ขอบเขตเวลาการทำงานที่ต่ำกว่าสำหรับขั้นตอนวิธีการเรียงลำดับใด ๆ ที่เป็นΩ ( n ) หากคุณจำการเรียงลำดับ radix หรือ bucket bucket คุณจะสังเกตเห็นว่าเวลาการทำงานของพวกเขาคือO ( nAn(n-1)A(n-1)Ω(n)O(n). เนื่องจากอัลกอริธึมการเรียงลำดับทั้งหมดถูกผูกไว้ด้านล่างด้วยฉันจะยืนยันว่าทั้งการเรียงเรดิสและการจัดเรียงเร็กคอร์ดเป็นอัลกอริธึมที่เร็วที่สุดสำหรับการเรียงอาเรย์ของจำนวนเต็มΩ(n)

นอกจากนี้หากคุณไม่คุ้นเคยกับสิ่งที่หรือO ( n ) : สัญลักษณ์ทั้งสองหมายความว่าอัลกอริทึมใช้เวลาดำเนินการประมาณnการดำเนินการให้เสร็จสมบูรณ์ (อาจเป็น2 nหรือ3 n - 5แต่ไม่ใช่1หรือn 2 ) .Ω(n)O(n)n2n3n-51n2


ใช่ แต่เวลาทำงานก็เกือบจะโกงด้วยเช่นกันเนื่องจากค่าคงที่ที่ด้านหน้าของn จะปรับขนาดได้อย่างมีประสิทธิภาพเช่นlg n (เนื่องจากคุณสมมติว่าเป็นเครื่อง 32 บิตและนั่นก็หมายความว่าn 2 32 ) . ดังนั้นแม้ว่าO ( n ) (สำหรับการจัดเรียง radix) ดูดีกว่าO ( n lg n )O(n)nLGnn232O(n)O(nLGn)(สำหรับ quicksort หรือการรวมกัน) ในทางปฏิบัติการเปรียบเทียบยังไม่ชัดเจนนัก: ค่าคงที่ที่ซ่อนอยู่ในสัญกรณ์ใหญ่ -O กลายเป็นสิ่งสำคัญมากและค่าคงที่สำหรับการเรียงแบบฐานจะสูงกว่าค่าคงที่สำหรับการรวมหรือการรวม
DW

"ค่าคงที่ด้านหน้าของ n มีขนาดได้อย่างมีประสิทธิภาพเช่น " ฉันไม่เข้าใจสิ่งที่คุณหมายถึงโดยวลีนี้ (ฉันเข้าใจว่าสัญกรณ์ Big-Oh ซ่อนค่าคงที่ซึ่งอาจมีความสำคัญสำหรับnขนาดเล็ก) ล.ก.(n)n
bourbaki4481472

Ω(n)

2
O(Wn)WWW{0,...,2W-1}เข้าสู่ระบบnnW=เข้าสู่ระบบnnเข้าสู่ระบบn.
David Richerby

1

O(nล.โอก.ล.โอก.n)
O(nล.โอก.ล.โอก.ยู)ยู

0

เข้าสู่ระบบ(n!)เป็นสิ่งจำเป็นในกรณีที่เลวร้ายที่สุดเพื่อระบุการเปรียบเทียบในมือกับสิ่งที่เป็นไปได้ทั้งหมด นี่คือขอบเขตที่ไม่สามารถแตกได้

Ω(n)


0

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

ในทางทฤษฎีเช่นเป็นquick_sort O(n log n)ด้วยpโปรเซสเซอร์สิ่งนี้น่าจะเกิดขึ้นได้O(n/p log n)หากเราใช้งานแบบขนาน

เพื่ออ้างถึง Wikipedia: ความซับซ้อนของเวลาของ ...

การเรียงลำดับแบบขนานที่เหมาะสมที่สุดคือ O (log n)

ในทางปฏิบัติสำหรับขนาดอินพุตขนาดใหญ่มันเป็นไปไม่ได้ที่จะประสบความสำเร็จO(log n)เนื่องจากปัญหาการขยายขนาด

นี่คือรหัสเทียมสำหรับการจัดเรียงผสานขนาน การใช้งานของmerge()สามารถเหมือนกับในการผสานการเรียงปกติ:

// Sort elements lo through hi (exclusive) of array A.
algorithm mergesort(A, lo, hi) is
    if lo+1 < hi then  // Two or more elements.
        mid = ⌊(lo + hi) / 2⌋
        fork mergesort(A, lo, mid)
        mergesort(A, mid, hi)
        join
        merge(A, lo, mid, hi)

ดูเพิ่มเติมที่:


O(n2)

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