ทำให้กรณีที่ไม่ดีสำหรับการจัดเรียงอย่างรวดเร็วคืออะไร?


10

ฉันกำลังเรียนรู้เกี่ยวกับ quicksort และต้องการแสดงอาร์เรย์ที่แตกต่างกันซึ่ง quicksort จะมีช่วงเวลาที่ยากลำบาก Quicksort ที่ฉันมีอยู่ในใจไม่มีการสับสุ่มเริ่มต้นทำพาร์ติชัน 2 และไม่คำนวณค่ามัธยฐาน

ฉันคิดถึงตัวอย่างสามตัวอย่าง:

[1,2,3,4,5,6,7,8,9,10] - when the array is sorted
[10,9,8,7,6,5,4,3,2,1] - when the array is reversed
[1,1,1,1,1,1,1,1,1,1] - when the array is the same values
[1,1,1,2,2,2,3,3,3,3] - when there are few and unique keys

ตัวอย่างเช่นฉันไม่แน่ใจเกี่ยวกับสิ่งนี้:

[1,3,5,7,9,10,8,6,4,2]

ดังนั้นอะไรที่ทำให้อาร์เรย์ที่ quicksort มีความยากลำบากเมื่อเทียบกับที่มันเหมาะ (เกือบ)?


2
เดือยถูกเลือกอย่างไร? คุณระบุสองวิธีที่ไม่ได้เลือก แต่ไม่ใช่วิธีที่เลือกไว้
Winston Ewert

โปรดให้กรณีที่แย่ที่สุดสำหรับ QuickSort - มันจะเกิดขึ้นได้เมื่อไหร่? บน StackOverflow การอ่าน ฉันยังค้นหาsorting.atเพื่อให้เห็นภาพขั้นตอนวิธีการเรียงลำดับที่ดี

@WinstonEwert Pivot ถูกเลือกโดยองค์ประกอบแรก
mrQWERTY

@ Renren29 ผมได้แก้ไขคำถามนิดพยายามที่จะย้ายไปยังมุ่งเน้นไปที่เหตุผลว่าทำไม quicksort จะมีความยากลำบากกับอาร์เรย์ให้มากกว่าการแสวงหาอาร์เรย์ตัวอย่าง (ที่ฉันทำไม่ได้คนที่จะให้คุณตอบของ[2,1,2,1,2,1,2,1]และที่เป็นทั้ง ตอบ). เป้าหมายของคำถามจะเป็นการดีที่คนอื่นสามารถมาหาข้อมูลเพิ่มเติมเกี่ยวกับสาเหตุ (ซึ่งมีคำตอบ) มากกว่าตัวอย่าง (ซึ่งมีอยู่นับไม่ถ้วน)

คุณกำลังลดระดับลงอย่างรวดเร็วเป็นชิ้น ๆ จาก 2 องค์ประกอบหรือไม่ เพราะการใช้งานในโลกแห่งความเป็นจริงมักจะใช้การเรียงลำดับที่ง่ายกว่าสำหรับชิ้นเล็ก ๆ เช่นการเปรียบเทียบและการสลับเป็นเรื่องง่ายกว่า quicksort มากสำหรับ N = 2
MSalters

คำตอบ:


9

อัลกอริธึมการเรียงลำดับทุกกรณีมีกรณีที่เลวร้ายที่สุดและในหลายกรณีกรณีที่เลวร้ายที่สุดนั้นแย่มากดังนั้นจึงคุ้มค่าที่จะทำการทดสอบ ปัญหาคือไม่มีกรณีที่เลวร้ายที่สุดเพียงเพราะคุณรู้ว่าอัลกอริทึมพื้นฐาน

กรณีที่เลวร้ายที่พบบ่อย ได้แก่ : เรียงลำดับแล้ว; เรียงกลับกัน เรียงเกือบหนึ่งองค์ประกอบออกคำสั่ง; ค่าทั้งหมดเหมือนกัน; ทั้งหมดเดียวกันยกเว้นก่อน (หรือสุดท้าย) สูงกว่า (หรือต่ำกว่า) เราเคยมีประเภทที่กรณีที่เลวร้ายที่สุดคือรูปแบบฟันเลื่อยโดยเฉพาะซึ่งยากที่จะคาดเดา แต่ในทางปฏิบัติค่อนข้างบ่อย

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


สำหรับ quicksort ความซับซ้อนโดยเฉลี่ยคือ nlogn และกรณีที่แย่ที่สุดคือ n ^ 2 เหตุผลที่คุ้มค่าที่กระตุ้นให้เกิดพฤติกรรมของกรณีที่เลวร้ายที่สุดก็คือเพราะนี่เป็นกรณีที่ทำให้เกิดการเรียกซ้ำที่ลึกที่สุด สำหรับการปฏิบัติที่ไร้เดียงสาความลึกของการเรียกซ้ำอาจเป็น n ซึ่งอาจทำให้เกิดการล้นสแต็ก การทดสอบสถานการณ์ที่รุนแรงอื่น ๆ (รวมถึงกรณีที่ดีที่สุด) อาจคุ้มค่าด้วยเหตุผลที่คล้ายกัน


ฉันเห็นดังนั้นค่าเบี่ยงเบนมาตรฐานจากค่าเฉลี่ยจริง ๆ กำหนดผลการแบ่ง
mrQWERTY

"... และในเกือบทุกกรณีกรณีที่เลวร้ายที่สุดนั้นแย่มากดังนั้นจึงควรลองทดสอบดู" . นั่นเป็นที่ถกเถียงกัน เมื่อฉันดูที่ตารางนี้: en.wikipedia.org/wiki/…ฉันสรุปว่าสำหรับอัลกอริทึมการเรียงลำดับ "ดี" ส่วนใหญ่ (เช่นมีO(NlogN)ประสิทธิภาพโดยเฉลี่ยหรือดีกว่า) กรณีที่แย่ที่สุดและปานกลางมีความซับซ้อนเหมือนกัน นั่นแสดงให้เห็นว่าโดยปกติแล้วจะไม่คุ้มค่าการทดสอบสำหรับกรณีที่เลวร้ายที่สุด (ระบุว่าการทดสอบน่าจะO(N)... หรือแย่กว่านั้น)
สตีเฟนซี

@ Renren29: ค่ามัธยฐานของ 3 เดือยจะเป็นครั้งแรกหรือครั้งสุดท้ายเฉพาะในกรณีที่ 2 หรือ 3 ของค่าเดียวกัน SD ไม่เข้ามา
david.pfx

@StephenC: อัลกอริธึม 'ดี' หลายอย่างรวมถึง quicksort มีความซับซ้อนของกรณีที่เลวร้ายที่สุด n ^ 2 แต่ดูแก้ไข
david.pfx

@ david.pfx - "บางคน" ... ใช่ "เกือบทุกคน" ... ไม่
Stephen C

0

อัลกอริทึมหนีจากกรณีที่ไม่ดีส่วนใหญ่โดยใช้เดือยที่สุ่มการยกเว้นองค์ประกอบต่อเนื่องเท่ากับ pivot จากการแบ่งพาร์ติชันและการค้นหาแบบไม่สมมาตร มันค้นหาไปข้างหน้าองค์ประกอบที่มากกว่าหรือเท่ากับเดือยและค้นหาย้อนหลังองค์ประกอบน้อยกว่าเดือย
ฉันขอบคุณ MichaelT การคิดค้นการค้นหาแบบไม่สมมาตรเพื่อแก้ไข [2,1,2,1,2,1,2,1]

ผลลัพธ์ต่อไปนี้สร้างโดยฟังก์ชันของฉัน qsort_random () N = 100,000

usec    call   compare   copy    pattern
80132   62946  1971278   877143  random
47326   57578  1606067   215155  sorted : 0,1,2,3,...,n-1
49927   63578  1628883   338715  sorted in reverse : n-1,n-2,...,2,1,0
55619   63781  1596934   377330  nearly reverse : n-2,n-1,n-4,n-3,...,2,3,0,1
54714   66667  1611454   290392  median-3-killer : n-1,0,1,2,...,n-2
1491    1      99999     4       all values the same : n,n,n,...
1577    1      99999     4       first is higher : n,1,1,1,...
2778    2      156159    10      last is lower : n,n,n,...,n,1
2994    3      199996    100009  a few data : n,...,n,1,...,1
3196    3      199996    50012   zigzag : n,1,n,1,...,n,1
917796  56284  67721985  673356  valley(sawtooth?) : n-1,n-3,...,0,...,n-4,n-2

กรณีส่วนใหญ่จะเร็วกว่ารูปแบบสุ่ม รูปแบบหุบเขาเป็นกรณีที่ไม่ดีสำหรับการเลือกเดือยส่วนใหญ่

qsort(3)       usec = 14523   call = 0      compare = 884463    copy = 0
qsort_head()   usec = 138609  call = 99999  compare = 8120991   copy = 1214397
qsort_middle() usec = 664325  call = 99999  compare = 52928111  copy = 1036047
qsort_trad()   usec = 118122  call = 99999  compare = 6476025   copy = 1337523
qsort_random() usec = 295699  call = 58806  compare = 19439952  copy = 732962
qsort_log2()   usec = 66411   call = 63987  compare = 1597455   copy = 944821

qsort_log2 () หนีออกมาจากตัวพิมพ์เล็กโดยเลือก pivot ในองค์ประกอบ log2 (N)
qsort (3) ใช้ไลบรารี GNU ซึ่งเป็นการเรียงลำดับแบบผสานของการเรียงลำดับดัชนี
qsort_trad () เลือกเดือยในองค์ประกอบแรกกลางและสุดท้าย
qsort_random () และ qsort_log2 () ไม่ใช้การสลับ
แหล่งที่มาของโปรแกรม C และสคริปต์ที่จะโพสต์ในGitHub

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