อัลกอริทึมการเรียงลำดับนี้เป็นอย่างไร³ (n³) และไม่Θ (n²) เป็นกรณีที่เลวร้ายที่สุด?


52

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

void F3() {
    for (int i = 1; i < n; i++) {
        if (A[i-1] > A[i]) {
            swap(i-1, i)
            i = 0
        }
    }
}

อาจไม่ชัดเจน แต่ที่นี่คือขนาดของอาร์เรย์ที่เราพยายามเรียงลำดับnA

ในกรณีใด ๆ ผู้ช่วยสอนอธิบายให้ชั้นเรียนรู้ว่าอัลกอริทึมนี้อยู่ในเวลา (แย่ที่สุดฉันเชื่อ) แต่ไม่ว่าฉันจะผ่านมันไปกี่ครั้งด้วยอาเรย์เรียงกลับด้าน มันดูเหมือนว่าฉันที่มันควรจะเป็นและไม่ได้3)Θ(n3)Θ(n2)Θ(n3)

คนที่จะสามารถอธิบายให้ฉันทำไมนี้เป็นΘ(n3)และไม่Θ(n2) ?


คุณอาจจะสนใจในวิธีการที่มีโครงสร้างการวิเคราะห์ ; พยายามหาหลักฐานด้วยตัวเอง!
กราฟิลส์

เพียงใช้มันและวัดค่าเพื่อโน้มน้าวตัวเอง อาร์เรย์ที่มี 10,000 องค์ประกอบในลำดับที่กลับรายการควรใช้เวลาหลายนาทีและอาร์เรย์ที่มีองค์ประกอบ 20,000 รายการในลำดับที่กลับรายการควรใช้เวลานานกว่าประมาณแปดเท่า
gnasher729

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

1
เนื่องจากi = 0คำแถลง
njzk2

คำตอบ:


61

อัลกอริทึมนี้สามารถเขียนใหม่ได้เช่นนี้

  1. สแกนAจนกว่าคุณจะได้พบกับการผกผัน
  2. หากคุณพบหนึ่งแลกเปลี่ยนและเริ่มต้นใหม่
  3. หากไม่มีให้ยุติ

ขณะนี้มีได้มากที่สุด inversions และคุณต้องการสแกนเชิงเส้นเพื่อค้นหาแต่ละครั้งดังนั้นเวลาที่เลวร้ายที่สุดคือ3) ตัวอย่างการสอนที่สวยงามในขณะที่มันเข้าใกล้การจับคู่รูปแบบที่หลายคนยอมแพ้!(n2)Θ(n2)Θ(n3)

หมายเหตุ:เราต้องระวังนิดหน่อย: ผู้รุกรานบางคนปรากฏขึ้น แต่เช้า, ช้าไปแล้ว, ดังนั้นจึงไม่น่าแปลกใจเลยที่ค่าใช้จ่ายจะเพิ่มขึ้นตามที่กล่าวอ้าง (สำหรับขอบเขตล่าง) นอกจากนี้คุณยังต้องสังเกตว่าสัญญาไม่เคยแนะนำใหม่ inversions การวิเคราะห์รายละเอียดเพิ่มเติมของกรณีที่มีอาร์เรย์ที่เรียงกลับกันจะให้ผลลัพธ์เหมือนกับกรณีกำลังสองของสูตรของเกาส์

ในฐานะที่เป็น @ gnasher729 ความคิดเห็น aptly มันง่ายที่จะเห็นเวลาทำงานที่เลวร้ายที่สุดคือโดยการวิเคราะห์เวลาทำงานเมื่อเรียงลำดับอินพุต (แม้ว่าการป้อนข้อมูลนี้อาจจะไม่กรณีที่เลวร้าย)Ω(n3)[1,2,,n,2n,2n1,,n+1]

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


14
หากคุณใช้อาร์เรย์ที่ครึ่งแรกประกอบด้วยตัวเลข 1 ถึง n / 2 ตามลำดับจากน้อยไปมากและครึ่งหลังคือ n ถึง n / 2 + 1 ในลำดับที่กลับกันดังนั้นจึงเป็นที่ชัดเจนว่าคุณต้องการอย่างน้อย n / 2 ขั้นตอนในการค้นหาการผกผันแต่ละครั้งและจะมีประมาณ (n / 2) ^ 2/2 ของพวกเขา และนั่นก็ไม่ใช่กรณีที่เลวร้ายที่สุด
gnasher729

@AnthonyRossello มันเป็นผลมาตรฐาน (ใน combinatorics ของการเรียงสับเปลี่ยน) กล่าวโดยสรุปให้นับจำนวนผู้รุกรานในอาร์เรย์ที่เรียงลำดับแบบย้อนกลับ (เห็นได้ชัดว่าเป็นกรณีที่แย่ที่สุด?) มันเป็นผลรวมของเกาส์
Raphael

เราต้องจำไว้ว่าไม่ว่าอะไรจะเกิดขึ้นบางส่วนมักจะเป็นมันเป็นเพียงค่าสัมประสิทธิ์ที่ลดลงอย่างรวดเร็ว: (สังเกตค่าสัมประสิทธิ์ค่อนข้างใหญ่ ) ปัญหาคือไม่สนใจค่าสัมประสิทธิ์ Θ(nα)Θ(nα+1)k=0nkα1α+1nα+11α+1Θ
yo

2
@yo 'และสิ่งนี้เกี่ยวข้องกับคำตอบ (หรือคำถาม) ได้อย่างไร
กราฟิลส์

7

อีกทางเลือกหนึ่งในการคิดเกี่ยวกับสิ่งนี้คือสิ่งที่ค่าสูงสุดของiก่อนที่จะถูกรีเซ็ต สิ่งนี้ตามที่ปรากฏทำให้ตรงไปตรงมามากขึ้นเกี่ยวกับเหตุผลว่าลำดับการเรียงลำดับก่อนหน้าของAส่งผลกระทบต่อเวลารันไทม์ของอัลกอริทึมอย่างไร

โดยเฉพาะอย่างยิ่งสังเกตว่าเมื่อiตั้งค่าสูงสุดใหม่แล้วเรียกมันว่า N อาร์เรย์[A[0], ..., A[N-1]]จะเรียงตามลำดับจากน้อยไปมาก

แล้วจะเกิดอะไรขึ้นเมื่อเราเพิ่มองค์ประกอบA[N]ลงในส่วนผสม

คณิตศาสตร์:

ดีช่วยบอกมันเหมาะกับที่ตำแหน่งp_Nแล้วเราต้องการทำซ้ำห่วง (ซึ่งผมจะแสดง ) เพื่อย้ายไปวาง ,การทำซ้ำที่จะย้ายไปยังสถานที่และโดยทั่วไป:pNNstepsN1N+(N1)N2

stepsN(pN)=N+(N1)+(N2)++(pN+1)=12(N(N+1)pN(pN+1))

สำหรับอาร์เรย์ที่เรียงลำดับแบบสุ่มรับการแจกแจงแบบสม่ำเสมอบนสำหรับแต่ละด้วย:pN{0,1,,N}N

E(stepsN(pN))=a=1NP(pN=a)stepsN(a)=a=1N1N12(N(N+1)a(a+1))=12(N(N+1)13(N+1)(N+2))=13(N21)=Θ(N2)

ยอดรวมสามารถแสดงได้โดยใช้สูตรของ Faulhaber หรือลิงก์ Wolfram Alpha ที่ด้านล่าง

สำหรับอาร์เรย์ที่เรียงกลับกันสำหรับทั้งหมดและเราได้รับ:pN=0N

stepsN(pN)=12N(N+1)

ว่าการอย่างเคร่งครัดนานกว่าค่าอื่น ๆ ของp_NpN

สำหรับอาร์เรย์ที่เรียงลำดับแล้วและโดยที่คำที่มีลำดับต่ำกว่ามีความสัมพันธ์กันpN=NstepsN(pN)=0

เวลารวม:

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

และอีกครั้งโดยใช้เส้นตรงของความคาดหวังและสูตรของ Faulhaber:

Expected Total Steps=E(N=1nstepsN(pN))=N=1nE(stepsN(pN))=Θ(n3)

แน่นอนถ้าด้วยเหตุผลไม่ใช่ (เช่นการกระจายของอาร์เรย์ที่เรากำลังดูอยู่นั้นใกล้จะเรียงแล้ว) สิ่งนี้ไม่จำเป็นเสมอไป เป็นกรณี แต่ต้องใช้การแจกแจงที่เฉพาะเจาะจงอย่างมากในเพื่อให้ได้สิ่งนี้!stepsN(pN)Θ(N2)pN

การอ่านที่เกี่ยวข้อง:


@ ราฟาเอล - ขอบคุณสำหรับการปรับปรุงที่แนะนำฉันได้เพิ่มรายละเอียดอีกเล็กน้อย ตัวแปรสุ่มคือ (จากชุดของการเรียงลำดับของ) ดังนั้นความคาดหวังจะทำในทางเทคนิคpiΩAΩ
David E

แตกต่างกัน ; ฉันหมายถึงรถม้าหนึ่งคัน Ω
กราฟิลส์

3

Disclaimer:

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

ไม่ว่ากี่ครั้งที่ผมผ่านมันไปกับอาร์เรย์สลับเรียงมันดูเหมือนว่าฉันที่มันควรจะเป็นและไม่3)Θ(n2)Θ(n3)

ด้วยรหัสง่าย ๆ ความแตกต่างระหว่างและไม่ควรมองเห็นได้ยากและในกรณีที่ใช้งานได้หลายกรณีนี่เป็นวิธีที่มีประโยชน์ในการตรวจสอบลางสังหรณ์หรือปรับความคาดหวังΘ(n2)Θ(n3)


@Raphael ตอบคำถามของคุณแล้ว แต่เพียงสำหรับการเตะกระชับของโปรแกรมนี้ส่งออกไปยังใช้สคริปต์ gnuplot นี้รายงานค่าตัวแทนของและและผลิตแปลงดังต่อไปนี้ ( ครั้งแรกคือขนาดปกติและที่สองคือระดับล็อกบันทึก):f(x)=axb+cx2.997961668332222.99223727692339

ปกติ loglog

ฉันหวังว่าสิ่งนี้จะช่วย¨


2
คุณสามารถใส่ฟังก์ชันใด ๆ ดูที่นี่ด้วย
กราฟิลส์

3
@ ราฟาเอลถ้าคุณไม่ต้องการ nitpick ด้วยวิธีนี้แล้วไม่คุณไม่สามารถปรับฟังก์ชั่นใด ๆ ได้ (ตัวอย่างเช่นคุณจะไม่สามารถปรับฟังก์ชั่นคงที่ให้เหมาะสมกับความแม่นยำที่เหมาะสม) นี่ไม่ใช่ข้อพิสูจน์ แต่มีคำตอบที่ให้ภาพร่าง สำหรับประโยชน์ฉันสามารถอ้างอิงโพสต์ของคุณที่คุณเชื่อมโยง: "ฉันต้องยอมรับว่านี่เป็นวิธีที่มีประโยชน์มากซึ่งบางครั้งก็ใช้งานไม่ได้" ยิ่งกว่านั้น OP กล่าวว่าเขาคิดว่ามันควรเป็นมากกว่าดังนั้นทำไมไม่ลองทดสอบดูว่าลางสังหรณ์ของเขาถูกต้องหรือไม่? ต่อเนื่อง Θ(n2)Θ(n3)
dtldarek

2
แห่งนี้มีหลักฐานว่าอัลกอริทึมแต่คำถามจะถามว่าทำไม มันขอคำอธิบายเกี่ยวกับปรากฏการณ์ไม่ใช่การยืนยัน Θ(n3)
David Richerby

2
@DavidRicherby นี่หมายความว่าคำตอบนี้ไม่มีประโยชน์หรือไม่?
dtldarek

3
@Magicsowon เป็นเว็บไซต์คำถามและคำตอบไม่ใช่ฟอรัม เรากำลังมองหาคำตอบสำหรับคำถามไม่ใช่การอภิปรายรอบ ๆ
David Richerby

3

สมมติว่าคุณมีอาร์เรย์

array a[10] = {10,8,9,6,7,4,5,2,3,0,1}

อัลกอริทึมของคุณทำสิ่งต่อไปนี้

Scan(1) - Swap (10,8) => {8,10,9,6,7,4,5,2,3,0,1}  //keep looking at "10"
Scan(2) - Swap (10,9) => {8,9,10,6,7,4,5,2,3,0,1}
...
Scan(10) - Swap(10,1) => {8,9,6,7,4,5,2,3,0,1,10}

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


4
สิ่งนี้เพิ่มอะไรมากกว่าคำตอบอื่น ๆ คำอธิบายของสิ่งที่อัลกอริทึมได้รับมาแล้วและเหตุผลของคุณสำหรับรันไทม์นั้นดีที่สุด (กรณีที่เลวร้ายที่สุดไม่ทำงานเป็นเส้นตรง!)
ราฟาเอล

2
บางครั้งมีค่าในการอธิบายความคิดเดียวกันในหลาย ๆ วิธี (ด้วยความเป็นทางการ; ด้วยตัวอย่างง่ายๆในการ "ปั๊มสัญชาตญาณ") โดยเฉพาะอย่างยิ่งเมื่อบุคคลที่ถามคำถามนั้นใหม่ ดังนั้นสำหรับฉันสิ่งที่เพิ่มเข้ามาคือการนำเสนอในลักษณะที่อาจช่วยปรีชาญาณ
DW

เนื่องจากฉันได้รับการตอบกลับความคิดเห็นของฉันในธง (อย่าทำอย่างนั้น!): "กรณีที่เลวร้ายที่สุดไม่ทำงานเป็นเส้นตรง!" - ฉันหมายถึงคุณสมบัติเชิงพีชคณิตของตัวดำเนินการตัวพิมพ์เล็กสุด คุณกำลังใช้ WorstCase (1 + ... + n) "=" WorstCase (1) + ... + WorstCase (n) แต่ตัวตนนี้ไม่ได้เก็บไว้
กราฟิลส์

1
ฉันยังใหม่กับสาขานี้และให้คำอธิบายอย่างเป็นรูปธรรมตัวอย่างที่สะกดออกมาอย่างแน่นอนช่วยให้ฉันได้สัญชาตญาณเกี่ยวกับปัญหา ตอนนี้ทางออกที่เป็นที่ยอมรับทำให้ฉันเข้าท่ามากขึ้น
vaer-k

0

ตรรกะดูเหมือนว่าจะเรียงลำดับองค์ประกอบในอาร์เรย์ตามลำดับจากน้อยไปมาก

สมมติว่าจำนวนที่น้อยที่สุดอยู่ที่ท้ายอาร์เรย์ (a [n]) เพื่อให้มันมาถูกที่ - ต้องใช้การดำเนินงาน (n + (n-1) + (n-2) + ... 3 + 2 + 1) = O (n2)

สำหรับองค์ประกอบเดียวในอาร์เรย์ O (n2) จำเป็นต้องมี ดังนั้นสำหรับ n eements มันคือ O (n3)


5
สิ่งนี้เพิ่มอะไรมากกว่าคำตอบอื่น ๆ คำอธิบายของสิ่งที่อัลกอริทึมได้รับมาแล้วและเหตุผลของคุณสำหรับรันไทม์นั้นดีที่สุด (กรณีที่เลวร้ายที่สุดไม่ทำงานเป็นเส้นตรง!)
ราฟาเอล

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

1
@ 2501 ไม่ผิดหรอก ลองใช้ "ปรีชา" นี้กับอัลกอริธึมของ Dijkstra และคุณจะได้รับกำลังสอง (ในจำนวนโหนด) ซึ่งผิด
Raphael

@ ราฟาเอลไม่ถูกต้องตามที่อธิบายไว้ในคำตอบ คำอธิบายนี้ใช้ได้กับอัลกอริทึมนี้ไม่ใช่สำหรับคนอื่น ในขณะที่มันอาจจะผิดสำหรับพวกเขาเรียกร้องนี้ไม่ได้พิสูจน์ว่ามันผิดสำหรับคนนี้
2501

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