จัดเรียงอาร์เรย์คือกระบวนการกระจายองค์ประกอบทั้งหมดตามลำดับที่แน่นอน บ่อยครั้งสิ่งนี้มีประโยชน์ ตัวอย่างเช่น กล่องขาเข้าของคุณจะแสดงอีเมลตามเวลาที่ได้รับ อีเมลใหม่ถือว่ามีความเกี่ยวข้องมากกว่าอีเมลที่คุณได้รับเมื่อครึ่งชั่วโมง หนึ่งชั่วโมง สองหรือหนึ่งวันก่อน เมื่อคุณไปที่รายชื่อผู้ติดต่อ ชื่อมักจะเรียงตามตัวอักษรเพราะง่ายต่อการค้นหา กรณีทั้งหมดนี้เกี่ยวข้องกับการเรียงลำดับข้อมูลก่อนส่งออกจริง
การเรียงลำดับทำงานอย่างไร?
การเรียงลำดับข้อมูลสามารถทำให้การค้นหาภายในอาเรย์มีประสิทธิภาพมากขึ้น ไม่เพียงแต่สำหรับคนเท่านั้น แต่ยังรวมถึงคอมพิวเตอร์ด้วย ตัวอย่างเช่น พิจารณากรณีที่เราต้องค้นหาว่ามีชื่อใดปรากฏในรายชื่อหรือไม่ หากต้องการทราบ เราจำเป็นต้องตรวจสอบแต่ละองค์ประกอบของอาร์เรย์กับค่าของเรา การค้นหาอาร์เรย์ที่มีองค์ประกอบจำนวนมากอาจไม่มีประสิทธิภาพเกินไป (มีค่าใช้จ่ายสูง)
อย่างไรก็ตาม สมมติว่าอาร์เรย์ชื่อของเราเรียงลำดับตามตัวอักษร จากนั้นการค้นหาของเราเริ่มต้นด้วยอักษรตัวแรกของค่าของเราและลงท้ายด้วยตัวอักษรที่อยู่ถัดไปในตัวอักษร ในกรณีนี้ หากเราได้รับจดหมายฉบับนี้และไม่พบชื่อ เราก็รู้แน่นอนว่าไม่ได้อยู่ในอาร์เรย์ที่เหลือ เนื่องจากเราได้ส่งจดหมายของเราตามลำดับตัวอักษรแล้ว!
ไม่มีความลับว่ามีอัลกอริธึมที่ดีกว่าสำหรับการค้นหาภายในอาร์เรย์ที่เรียงลำดับ ด้วยการใช้อัลกอริธึมง่ายๆ เราสามารถค้นหาองค์ประกอบเฉพาะในอาร์เรย์ที่เรียงลำดับซึ่งมีองค์ประกอบ 1,000,000 รายการโดยใช้การเปรียบเทียบเพียง 20 รายการ! แน่นอนว่าข้อเสียก็คือการเรียงลำดับอาร์เรย์ที่มีองค์ประกอบจำนวนมากนั้นมีราคาค่อนข้างแพง และแน่นอนว่าไม่ได้ทำเพื่อคำค้นหาคำเดียว
ในบางกรณี การเรียงลำดับอาร์เรย์ทำให้การค้นหาไม่จำเป็น ตัวอย่างเช่น เรากำลังมองหาคะแนนที่ดีที่สุดของนักเรียนในการทดสอบ ถ้าอาร์เรย์ไม่ได้เรียงลำดับ เราจะต้องดูแต่ละองค์ประกอบของอาร์เรย์เพื่อหาคะแนนสูงสุด หากเรียงลำดับอาร์เรย์แล้ว คะแนนสูงสุดจะอยู่ในตำแหน่งแรกหรืออันดับสุดท้าย (ขึ้นอยู่กับวิธีการเรียงลำดับอาร์เรย์: จากน้อยไปหามากหรือจากมากไปหาน้อย) ดังนั้นเราจึงไม่จำเป็นต้องค้นหาเลย!
โดยทั่วไปการเรียงลำดับจะทำโดยการเปรียบเทียบคู่ขององค์ประกอบอาเรย์ซ้ำแล้วซ้ำอีกและแทนที่ค่าหากตรงตามเกณฑ์ที่กำหนด ลำดับการเปรียบเทียบองค์ประกอบเหล่านี้ขึ้นอยู่กับอัลกอริทึมการเรียงลำดับที่ใช้ เกณฑ์ประกอบด้วยวิธีการจัดเรียงอาร์เรย์ (เช่น ลำดับจากน้อยไปมากหรือจากมากไปน้อย)
ในการสลับสององค์ประกอบเราสามารถใช้ฟังก์ชันได้ มาตรฐาน::swap()จากไลบรารีมาตรฐาน C++ ซึ่งกำหนดไว้ในอัลกอริทึม ใน C ++ 11 std::swap() ถูกย้ายไปยังไฟล์ส่วนหัวของยูทิลิตี้:
#รวม
#รวม #รวม int หลัก() int = 3 ; อินท์ ข = 5 ; มาตรฐาน::cout<< "Before swap: a = " << a << ", b = " << b << "\n" ; มาตรฐาน::swap(a, b); // สลับค่าของตัวแปร a และ b มาตรฐาน::cout<< "After swap: a = " << a << ", b = " << b << "\n" ; |
ผลลัพธ์ของการรันโปรแกรมด้านบน:
ก่อนสลับ: a = 3, b = 5
หลังจากสลับ: a = 5, b = 3
หลังจากดำเนินการเปลี่ยนแล้ว ค่าของตัวแปร a และ b จะถูกสลับ
การเรียงลำดับอาร์เรย์โดยใช้วิธีการเลือก
มีหลายวิธีในการจัดเรียงอาร์เรย์ การเรียงลำดับอาร์เรย์โดยใช้วิธีการเลือกอาจเป็นวิธีที่เข้าใจง่ายที่สุด แม้ว่าจะเป็นวิธีที่ช้าที่สุดก็ตาม
สำหรับ การเรียงลำดับอาร์เรย์โดยเลือกจากองค์ประกอบที่เล็กที่สุดไปหาใหญ่ที่สุดดำเนินการตามขั้นตอนต่อไปนี้:
เริ่มต้นด้วยองค์ประกอบที่ดัชนี 0 เราจะค้นหาค่าที่น้อยที่สุดในอาร์เรย์
ค่าที่พบจะถูกสลับกับองค์ประกอบศูนย์
เราทำซ้ำขั้นตอนที่ 1 และหมายเลข 2 สำหรับดัชนีถัดไปในอาร์เรย์
กล่าวอีกนัยหนึ่ง เรามองหาองค์ประกอบที่เล็กที่สุดในอาร์เรย์และย้ายไปยังตำแหน่งแรก จากนั้นเรามองหาองค์ประกอบที่เล็กที่สุดเป็นอันดับสองและย้ายไปยังตำแหน่งที่สองรองจากองค์ประกอบที่เล็กที่สุดตัวแรก กระบวนการนี้จะดำเนินต่อไปจนกว่าอาร์เรย์จะหมดองค์ประกอบที่ไม่ได้เรียงลำดับ
นี่คือตัวอย่างการทำงานของอัลกอริทึมนี้ในอาร์เรย์ที่มี 5 องค์ประกอบ:
{ 30, 50, 20, 10, 40 }
ขั้นแรกเรามองหาองค์ประกอบที่เล็กที่สุด เริ่มต้นที่ดัชนี 0:
{ 30, 50, 20, 10 , 40 }
จากนั้นเราสลับองค์ประกอบที่เล็กที่สุดกับองค์ประกอบที่ดัชนี 0:
{ 10 , 50, 20, 30 , 40 }
เมื่อองค์ประกอบแรกของอาร์เรย์ถูกจัดเรียงแล้ว เราก็จะไม่สนใจมัน เรากำลังมองหาองค์ประกอบที่เล็กที่สุดถัดไป แต่เริ่มจากดัชนี 1:
{ 10 , 50, 20 , 30, 40 }
และสลับกับองค์ประกอบที่ดัชนี 1:
{ 10 , 20 , 50 , 30, 40 }
ตอนนี้เราสามารถละเว้นสององค์ประกอบแรกได้แล้ว เรามองหาองค์ประกอบที่เล็กที่สุดถัดไป เริ่มต้นที่ดัชนี 2:
{ 10 , 20 , 50, 30 , 40 }
และสลับกับองค์ประกอบที่ดัชนี 2:
{ 10 , 20 , 30 , 50 , 40 }
เรามองหาองค์ประกอบที่เล็กที่สุดถัดไป เริ่มต้นที่ดัชนี 3:
{ 10 , 20 , 30 , 50, 40 }
และสลับกับองค์ประกอบที่ดัชนี 3:
{ 10 , 20 , 30 , 40 , 50 }
เรามองหาองค์ประกอบที่เล็กที่สุดถัดไป เริ่มต้นที่ดัชนี 4:
{ 10 , 20 , 30 , 40 , 50 }
และเราสลับมันกับองค์ประกอบที่ดัชนี 4 (ดำเนินการเปลี่ยนเองนั่นคือ เราไม่ทำอะไรเลย):
{ 10 , 20 , 30 , 40 50 }
{ 10, 20, 30, 40, 50 }
โปรดทราบว่าการเปรียบเทียบครั้งล่าสุดจะเป็นการเปรียบเทียบครั้งเดียวเสมอ (เช่น การเปลี่ยนตัวเอง) ซึ่งเป็นการดำเนินการที่ไม่จำเป็น ดังนั้นในความเป็นจริงแล้ว เราสามารถหยุดการเรียงลำดับก่อนองค์ประกอบสุดท้ายของอาร์เรย์ได้
การเรียงลำดับอาร์เรย์โดยใช้วิธีการเลือกใน C ++
ต่อไปนี้เป็นวิธีการใช้งานอัลกอริทึมนี้ใน C ++:
#รวม
#รวม #รวม int หลัก() ความยาว int คงที่ = 5 ; // วนซ้ำแต่ละองค์ประกอบของอาร์เรย์ // (ยกเว้นอันสุดท้ายมันจะถูกจัดเรียงตามเวลาที่เราไปถึงแล้ว) < length - 1 ; ++ startIndex ) // ตัวแปร littlestIndex จะเก็บดัชนีของค่าที่น้อยที่สุดที่เราพบในการวนซ้ำนี้ // เริ่มต้นด้วยองค์ประกอบที่เล็กที่สุดในการวนซ้ำนี้ซึ่งเป็นองค์ประกอบแรก (ดัชนี 0) int smallestIndex = startIndex ; // จากนั้นมองหาองค์ประกอบที่มีขนาดเล็กกว่าในส่วนที่เหลือของอาร์เรย์ < length ; ++ currentIndex ) // ถ้าเราพบองค์ประกอบที่เล็กกว่าองค์ประกอบที่เล็กที่สุดของเรา ถ้า (อาร์เรย์ [ currentIndex ]< array [ smallestIndex ] ) //แล้วก็จำไว้. ดัชนีที่เล็กที่สุด = currentIndex ; // smallestIndex ตอนนี้เป็นองค์ประกอบที่เล็กที่สุด // สลับจำนวนที่น้อยที่สุดเริ่มต้นของเรากับจำนวนที่เราค้นพบ มาตรฐาน::swap(อาร์เรย์[startIndex],อาร์เรย์[smallestIndex]); // เมื่อจัดเรียงอาร์เรย์ทั้งหมดแล้ว ให้แสดงบนหน้าจอ สำหรับ (ดัชนี int = 0 ; ดัชนี< length ; ++ index ) มาตรฐาน::cout<< array [ index ] << " " ; กลับ 0 ; |
ส่วนที่สับสนที่สุดของอัลกอริธึมนี้อยู่ในลูปอื่น (เรียกว่าลูปซ้อน) วงรอบนอก (startIndex) วนซ้ำผ่านองค์ประกอบทีละรายการ (ทีละรายการ) ในการวนซ้ำแต่ละครั้งของลูปภายนอก ลูปด้านใน (currentIndex) ถูกใช้เพื่อค้นหาองค์ประกอบที่เล็กที่สุดในบรรดาองค์ประกอบที่ยังคงอยู่ในอาร์เรย์ (เริ่มต้นที่ startIndex + 1) smallestIndex ติดตามดัชนีขององค์ประกอบที่เล็กที่สุดที่พบโดยวงใน จากนั้น SmallestIndex จะเปลี่ยนค่าจาก startIndex สุดท้าย ลูปด้านนอก (startIndex) จะผ่านองค์ประกอบนี้ และกระบวนการจะทำซ้ำ
เบาะแส:หากคุณมีปัญหาในการทำความเข้าใจวิธีการทำงานของโปรแกรมข้างต้น ให้ลองเขียนลงในกระดาษ เขียนองค์ประกอบเริ่มต้น (ไม่เรียงลำดับ) ของอาร์เรย์ในแนวนอนบนบรรทัดที่ด้านบนของแผ่นงาน วาดลูกศรเพื่อระบุว่าองค์ประกอบใดคือ startIndex , currentIndex และ SmallestIndex ในขณะนี้ วนซ้ำโปรแกรมด้วยตนเองแล้ววาดลูกศรใหม่เมื่อดัชนีเปลี่ยนแปลง หลังจากการวนรอบด้านนอกแต่ละครั้ง ให้ลากเส้นใหม่เพื่อแสดงสถานะปัจจุบันของอาร์เรย์ (ตำแหน่งขององค์ประกอบ)
การเรียงลำดับข้อความดำเนินการโดยใช้อัลกอริทึมเดียวกัน เพียงเปลี่ยนประเภทอาร์เรย์จาก -a เป็นและเริ่มต้นด้วยค่าที่เหมาะสม
มาตรฐาน::เรียงลำดับ()
เนื่องจากการทำงานของการเรียงลำดับอาร์เรย์เป็นเรื่องปกติมาก ไลบรารีมาตรฐาน C++ จึงมีฟังก์ชันการเรียงลำดับในตัว - มาตรฐาน::เรียงลำดับ()- ตั้งอยู่ในไฟล์ส่วนหัวของอัลกอริทึมและเรียกว่าดังนี้:
#รวม
#รวม #รวม int หลัก() ความยาว int คงที่ = 5 ; อาร์เรย์ int [ความยาว] = (30, 50, 20, 10, 40); std::sort(อาร์เรย์, อาร์เรย์ + ความยาว); สำหรับ (int i = 0 ; i< length ; ++ i ) มาตรฐาน::cout<< array [ i ] << " " ; กลับ 0 ; |
ทดสอบ
ภารกิจที่ 1
เขียนลงบนกระดาษถึงวิธีการจัดเรียงอาร์เรย์ต่อไปนี้โดยใช้วิธีการเลือก (ดังที่เราทำข้างต้น):
{30, 60, 20, 50, 40, 10}
ตอบ #1
30 60 20 50 40 10
10
60 20 50 40 30
10 20
60
50 40 30
10 20 30
50 40 60
10 20 30 40
50
60
10 20 30 40 50
60 (เปลี่ยนตัวเอง)
10 20 30 40 50 60
(ทดแทนตนเอง)
ภารกิจที่ 2
เขียนโค้ดโปรแกรมใหม่จากคำบรรยาย "Sorting Arrays by Selection in C++" เพื่อให้การเรียงลำดับเสร็จสิ้นจากมากไปน้อย (จำนวนมากที่สุดไปหาน้อยที่สุด) แม้ว่าสิ่งนี้อาจดูซับซ้อนเมื่อมองแวบแรก แต่จริงๆ แล้วง่ายมาก
ตอบ #2
เพียงแค่เปลี่ยน:
ถ้า (อาร์เรย์< array)
ถ้า (อาร์เรย์ [ currentIndex ]< array [ smallestIndex ] ) |
ถ้า (อาร์เรย์ > อาร์เรย์)
ถ้า (อาร์เรย์ [ currentIndex ] > อาร์เรย์ [ smallestIndex ] ) |
SmallestIndex ควรเปลี่ยนชื่อเป็น LargestIndex ด้วย:
#รวม
#รวม #รวม int หลัก() ความยาว int คงที่ = 5 ; อาร์เรย์ int [ความยาว] = (30, 50, 20, 10, 40); ) // สลับหมายเลขเริ่มต้นของเราด้วยองค์ประกอบที่ใหญ่ที่สุดที่พบ std::swap(array, array); ) สำหรับ (ดัชนี int = 0; ดัชนี< length - 1 ; ++ startIndex ) // วนซ้ำทุกองค์ประกอบของอาร์เรย์ ยกเว้นองค์ประกอบสุดท้าย สำหรับ (int startIndex = 0 ; startIndex // largeIndex คือดัชนีขององค์ประกอบที่ใหญ่ที่สุดที่เราพบจนถึงตอนนี้ สำหรับ (int currentIndex = startIndex + 1 ; currentIndex< length ; ++ currentIndex ) // หากองค์ประกอบปัจจุบันมากกว่าองค์ประกอบที่ใหญ่ที่สุดของเรา ถ้า (อาร์เรย์ [ currentIndex ] > อาร์เรย์ [ hugeIndex ] ) // นี่คือองค์ประกอบที่ใหญ่ที่สุดใหม่ในการวนซ้ำนี้ ดัชนีที่ใหญ่ที่สุด = ดัชนีปัจจุบัน ; // สลับหมายเลขเริ่มต้นของเรากับองค์ประกอบที่ใหญ่ที่สุดที่พบ std::swap (อาร์เรย์ [ startIndex ] , อาร์เรย์ [ hugeIndex ] ) ; // แสดงอาร์เรย์ที่เรียงลำดับบนหน้าจอ สำหรับ (ดัชนี int = 0 ; ดัชนี< length ; ++ index ) มาตรฐาน::cout<< array [ index ] << " " ; กลับ 0 ; |
ภารกิจที่ 3
งานนี้ยากขึ้นเล็กน้อย
วิธีการเรียงลำดับองค์ประกอบง่ายๆ อีกวิธีหนึ่งก็คือ "การเรียงลำดับฟอง"(หรืออย่างอื่น "การเรียงลำดับฟอง"- แนวคิดคือการเปรียบเทียบคู่ของค่าที่อยู่ใกล้เคียง และหากตรงตามเกณฑ์ที่กำหนด ค่าจากคู่นี้จะถูกสลับ และด้วยเหตุนี้องค์ประกอบจึงเกิด "ฟองสบู่" ที่ส่วนท้ายของอาร์เรย์ แม้ว่าจะมีหลายวิธีในการเพิ่มประสิทธิภาพการเรียงลำดับแบบบับเบิ้ล แต่สำหรับงานมอบหมายนี้ เราจะยังคงใช้เวอร์ชันที่ยังไม่ได้เพิ่มประสิทธิภาพเนื่องจากง่ายกว่า
สำหรับการเรียงลำดับแบบบับเบิลเวอร์ชันที่ไม่ได้รับการปรับให้เหมาะสม ให้ดำเนินการตามขั้นตอนต่อไปนี้เพื่อ: เรียงลำดับอาร์เรย์จากค่าที่น้อยที่สุดไปมากที่สุด:
องค์ประกอบอาร์เรย์ที่ดัชนี 0 จะถูกเปรียบเทียบกับองค์ประกอบอาร์เรย์ที่ดัชนี 1 หากองค์ประกอบที่ดัชนี 0 มากกว่าองค์ประกอบที่ดัชนี 1 ค่าจะถูกสลับ
จากนั้นเราจะย้ายไปยังคู่ค่าถัดไป: องค์ประกอบที่ดัชนี 1 และองค์ประกอบที่ดัชนี 2 ไปเรื่อยๆ จนกระทั่งเราไปถึงจุดสิ้นสุดของอาร์เรย์
ทำซ้ำขั้นตอน #1 และขั้นตอน #2 จนกว่าอาร์เรย์ทั้งหมดจะถูกจัดเรียง
เขียนโปรแกรมที่จะเรียงลำดับอาร์เรย์ต่อไปนี้โดยใช้การเรียงลำดับแบบฟองตามกฎด้านบน:
ความยาว int คงที่ (9); อาร์เรย์ int = ( 7, 5, 6, 4, 9, 8, 2, 1, 3 );
ความยาว int คงที่ (9); |
ในตอนท้ายของโปรแกรม ให้พิมพ์องค์ประกอบที่เรียงลำดับของอาเรย์
เบาะแส:หากเราสามารถจัดเรียงองค์ประกอบได้เพียงองค์ประกอบเดียวในการวนซ้ำครั้งเดียว นั่นหมายความว่าเราจะต้องวนซ้ำหลาย ๆ ครั้งตามจำนวนตัวเลขในอาร์เรย์ของเรา (ความยาวขององค์ประกอบ) เพื่อให้แน่ใจว่าอาร์เรย์ทั้งหมดจะถูกจัดเรียง
ตอบ #3
#รวม
#รวม #รวม int หลัก() ความยาว int คงที่ (9); ) ) // แสดงอาร์เรย์ที่เรียงลำดับบนหน้าจอสำหรับ (ดัชนี int = 0; ดัชนี อาร์เรย์ int [ความยาว] = (7, 5, 6, 4, 9, 8, 2, 1, 3);< length - 1 ; ++ iteration ) สำหรับ (int iteration = 0 ; iteration // วนซ้ำแต่ละองค์ประกอบอาร์เรย์จนถึงองค์ประกอบสุดท้าย (ไม่รวม) // องค์ประกอบสุดท้ายไม่มีคู่ให้เปรียบเทียบ< length - 1 ; ++ ดัชนีปัจจุบัน) { // หากองค์ประกอบปัจจุบันมีขนาดใหญ่กว่าองค์ประกอบหลังจากนั้น ให้สลับองค์ประกอบเหล่านั้น ถ้า(อาร์เรย์[ ดัชนีปัจจุบัน] > อาร์เรย์[ ดัชนีปัจจุบัน+ 1 ] ) มาตรฐาน:: แลกเปลี่ยน(อาร์เรย์[ ดัชนีปัจจุบัน] , อาร์เรย์[ ดัชนีปัจจุบัน+ 1 ] ) ; } } // แสดงอาร์เรย์ที่เรียงลำดับบนหน้าจอ สำหรับ(ภายในดัชนี= 0 ; ดัชนี< ความยาว; ++ ดัชนี) มาตรฐาน:: ศาล<< อาร์เรย์[ ดัชนี] << " " ; กลับ0 ; } |
ภารกิจที่ 4
ใช้โซลูชันการปรับให้เหมาะสมสองรายการต่อไปนี้สำหรับอัลกอริธึมการเรียงลำดับแบบฟองที่คุณเขียนไว้ในงานก่อนหน้า:
โปรดสังเกตว่าแต่ละครั้งที่ดำเนินการเรียงลำดับแบบบับเบิล ซึ่งเป็นค่าที่ใหญ่ที่สุดในอาร์เรย์ "บับเบิ้ล" จนถึงจุดสิ้นสุด หลังจากการวนซ้ำครั้งแรก องค์ประกอบสุดท้ายของอาร์เรย์จะถูกจัดเรียงแล้ว หลังจากการวนซ้ำครั้งที่สอง องค์ประกอบสุดท้ายของอาร์เรย์จะถูกจัดเรียง และต่อๆ ไป ในการวนซ้ำแต่ละครั้ง เราไม่จำเป็นต้องตรวจสอบองค์ประกอบที่ได้รับการจัดเรียงแล้วซ้ำอีก แก้ไขลูปของคุณเพื่อไม่ให้ตรวจสอบองค์ประกอบที่เรียงลำดับแล้วซ้ำแล้วซ้ำอีก
มีการประเมินกันว่าคอมพิวเตอร์ส่วนกลางจะใช้เวลามากถึงหนึ่งในสี่ในการจัดเรียงข้อมูล เนื่องจากการค้นหาค่าในอาร์เรย์ที่เรียงลำดับไว้ล่วงหน้าจะง่ายกว่ามาก มิฉะนั้น การค้นหาก็เหมือนกับการมองหาเข็มในกองหญ้า
มีโปรแกรมเมอร์จำนวนหนึ่งที่ใช้เวลาทำงานทั้งหมดเพื่อศึกษาและใช้อัลกอริธึมการเรียงลำดับ เนื่องจากซอฟต์แวร์ธุรกิจส่วนใหญ่เกี่ยวข้องกับการจัดการฐานข้อมูล ผู้คนค้นหาข้อมูลในฐานข้อมูลตลอดเวลา ซึ่งหมายความว่าอัลกอริทึมการค้นหาเป็นที่ต้องการสูง
แต่มี "แต่" อย่างหนึ่ง อัลกอริธึมการค้นหาทำงานเร็วขึ้นมากกับฐานข้อมูลที่จัดเรียงไว้แล้ว ในกรณีนี้ ต้องใช้การค้นหาเชิงเส้นเท่านั้น
ในขณะที่คอมพิวเตอร์ไม่มีผู้ใช้ในบางช่วงเวลา อัลกอริธึมการเรียงลำดับยังคงทำงานบนฐานข้อมูลต่อไป ผู้ค้นหากลับมาอีกครั้ง และฐานข้อมูลได้รับการจัดเรียงตามวัตถุประสงค์ในการค้นหาอย่างใดอย่างหนึ่งแล้ว
บทความนี้แสดงตัวอย่างการใช้งานอัลกอริธึมการเรียงลำดับมาตรฐาน
เรียงลำดับการเลือก
ในการจัดเรียงอาร์เรย์จากน้อยไปมาก คุณต้องค้นหาองค์ประกอบที่มีค่ามากที่สุดในแต่ละการวนซ้ำ คุณต้องสลับองค์ประกอบสุดท้ายด้วย องค์ประกอบถัดไปที่มีค่าสูงสุดจะถูกวางไว้ในอันดับที่สองจากตำแหน่งสุดท้าย สิ่งนี้จะเกิดขึ้นจนกว่าองค์ประกอบในตำแหน่งแรกในอาร์เรย์จะอยู่ในลำดับที่ถูกต้อง
รหัสซี++
เป็นโมฆะ SortAlgo::selectionSort(int data, int lenD) ( int j = 0; int tmp = 0; for (int i=0; i
ข้อมูล [i] = ข้อมูล [j];
การเรียงลำดับแบบบับเบิลจะเปรียบเทียบองค์ประกอบที่อยู่ติดกันและสลับตำแหน่งหากองค์ประกอบถัดไปมีขนาดเล็กกว่าองค์ประกอบก่อนหน้า จำเป็นต้องผ่านข้อมูลหลายครั้ง ในระหว่างการส่งผ่านครั้งแรก จะมีการเปรียบเทียบสององค์ประกอบแรกในอาร์เรย์ หากไม่เรียงลำดับจะถูกสลับแล้วเปรียบเทียบองค์ประกอบในคู่ถัดไป ภายใต้เงื่อนไขเดียวกันพวกเขาก็เปลี่ยนสถานที่ด้วย ดังนั้นการเรียงลำดับจะเกิดขึ้นในแต่ละรอบจนกระทั่งถึงจุดสิ้นสุดของอาร์เรย์
รหัสซี++
เป็นโมฆะ SortAlgo::bubbleSort (ข้อมูล int, int lenD) ( int tmp = 0; สำหรับ (int i = 0; i การเรียงลำดับการแทรกจะแยกอาร์เรย์ออกเป็นสองขอบเขต: เรียงลำดับและไม่เรียงลำดับ ในตอนแรก อาเรย์ทั้งหมดจะเป็นขอบเขตที่ไม่เรียงลำดับ ในการผ่านครั้งแรก องค์ประกอบแรกจากขอบเขตที่ไม่ได้เรียงลำดับจะถูกลบออก และวางในตำแหน่งที่ถูกต้องในภูมิภาคที่ได้รับคำสั่ง ในแต่ละรอบ ขนาดของขอบเขตที่เรียงลำดับจะเพิ่มขึ้น 1 และขนาดของขอบเขตที่ไม่เป็นระเบียบจะลดลง 1 วงหลักเริ่มจาก 1 ถึง N-1 ในการวนซ้ำที่ j องค์ประกอบ [i] จะถูกแทรกเข้าไปในตำแหน่งที่ถูกต้องในภูมิภาคที่ได้รับคำสั่ง ทำได้โดยการเลื่อนองค์ประกอบทั้งหมดของขอบเขตการเรียงลำดับที่มากกว่า [i] ไปทางขวาหนึ่งตำแหน่ง [i] ถูกแทรกลงในช่องว่างระหว่างองค์ประกอบที่น้อยกว่า [i] และองค์ประกอบที่มากกว่า [i] รหัสซี++
เป็นโมฆะ SortAlgo :: insertionSort (int data, int lenD) ( int key = 0; int i = 0; for (int j = 1; j รหัสซี++
ถือเป็นโมฆะ SortAlgo::mergeSort (int data, int lenD) ( if (lenD>1)( int middle = lenD/2; int rem = lenD-middle; int * L = int ใหม่; int * R = int ใหม่; สำหรับ ( int i=0;i Quicksort ใช้อัลกอริธึมการแบ่งและพิชิต เริ่มต้นด้วยการแบ่งอาร์เรย์ดั้งเดิมออกเป็นสองส่วน ส่วนเหล่านี้อยู่ทางซ้ายและขวาขององค์ประกอบที่ทำเครื่องหมายไว้ เรียกว่าส่วนรองรับ เมื่อสิ้นสุดกระบวนการ ส่วนหนึ่งจะมีองค์ประกอบที่เล็กกว่าข้อมูลอ้างอิง และอีกส่วนหนึ่งจะมีองค์ประกอบที่มีขนาดใหญ่กว่าข้อมูลอ้างอิง รหัสซี++
ถือเป็นโมฆะ SortAlgo::quickSort(int * data, int const len) ( int const lenD = len; int pivot = 0; int ind = lenD/2; int i,j = 0,k = 0; if (lenD>1) ( int * L = int ใหม่ ; int * R = int ใหม่ ; pivot = data; สำหรับ (i=0;i มีการพัฒนาวิธีการมากมายสำหรับการเรียงลำดับ (เรียงลำดับ) จากน้อยไปหามากหรือจากมากไปน้อยของค่าในอาร์เรย์ [Wirth, Knuth. t 3] ลองพิจารณาสามองค์ประกอบเพื่อความชัดเจนว่า n, n=6 องค์ประกอบแรกของอาร์เรย์ X ในแต่ละขั้นตอนที่ i ต่อไป i=2, 3,…,n-1 ค่าจากเซลล์ที่ (i+1) ของอาร์เรย์จะถูกย้ายไปสู่การลดดัชนีเซลล์โดยการแลกเปลี่ยนตำแหน่งกับตัวเลขจากก่อนหน้า เซลล์จนกระทั่ง ปรากฎว่าเซลล์ก่อนหน้ามีจำนวนน้อยกว่า จากที่กล่าวมาข้างต้นเป็นไปตามว่าเมื่อใช้วิธีการรวมโดยตรงจะต้องดำเนินการวนรอบด้านนอก n-1 ครั้งและจำนวนการดำเนินการสูงสุดของวงในที่เป็นไปได้ในร่างกายซึ่งต้องทำการเปรียบเทียบและการจัดเรียงตัวเลขใหม่ จะเพิ่มขึ้นจาก 1 เป็น n-1 อย่างไรก็ตาม ควรจัดระเบียบลูปด้านในให้สิ้นสุดหรือไม่ดำเนินการเลยเมื่อมีเงื่อนไขเกิดขึ้น: ค่าในเซลล์อาเรย์ก่อนหน้าน้อยกว่าค่าปัจจุบัน ในตัวอย่างของเรา: เมื่อ i=2 หมายเลข 15 จากเซลล์ X 3 จะสลับตำแหน่งตามลำดับกับหมายเลข 34 จากเซลล์ X 2 และจากนั้นกับหมายเลข 21 จากเซลล์ X 1 เมื่อ i=4 จำนวน 25 จากเซลล์ X 5 จะแลกกับหมายเลข 34 จากเซลล์ X 3 ด้านล่างนี้เป็นส่วนของโปรแกรมสำหรับการจัดลำดับองค์ประกอบ n แรกของอาร์เรย์ X จากน้อยไปมาก โดยใช้วิธีการรวมโดยตรง (รวมในขณะที่ยังคงรักษาลำดับ) สำหรับ i:=1 ถึง n-1 ทำ ในขณะที่ (X R:=X[เจ]; เอ็กซ์[เจ]:=X; X:=ร; หากต้องการเรียงลำดับตัวเลขในอาร์เรย์จากมากไปน้อยในแต่ละขั้นตอนก็เพียงพอที่จะเปลี่ยนเงื่อนไขในการเรียงสับเปลี่ยนตัวเลขในเซลล์ข้างเคียงของอาร์เรย์ไปในทางตรงกันข้าม กล่าวคือ การแลกเปลี่ยนค่าของเซลล์ข้างเคียงจะดำเนินการใน กรณีที่อันก่อนหน้าน้อยกว่าอันปัจจุบัน วิธีการนี้เหมือนกับวิธีก่อนหน้านี้ขึ้นอยู่กับการแลกเปลี่ยนค่าของเซลล์ข้างเคียงของอาเรย์ แต่จากขั้นตอนแรกสุดในการวิเคราะห์ตามลำดับเมื่อย้ายจากปลายด้านหนึ่งของอาเรย์ไปยังอีกด้านหนึ่ง ทุกคู่ของ เซลล์ข้างเคียงของอาร์เรย์มีส่วนเกี่ยวข้อง ในขั้นตอนแรกตามลำดับสำหรับ j = n, n-1, ..., 2 จะมีการเปรียบเทียบค่าของเซลล์ข้างเคียงของอาร์เรย์และหากเงื่อนไข X j<Х j-1 выполняется их
перестановка, в результате чего наименьшее
число оказывается в ячейке Х 1 . ในตัวอย่างของเรา หลังจากเสร็จสิ้นขั้นตอนแรกแล้ว ข้อมูลในอาร์เรย์จะอยู่ในลักษณะนี้: ในแต่ละขั้นตอนถัดไป จำนวนคู่ของเซลล์ที่ตรวจสอบจะลดลง 1 โดยทั่วไป ที่ขั้นตอนใดๆ i, i=1, 2, 3, ..., n-1 กระบวนการจะดำเนินการสำหรับ j จาก n ถึง i+1 โดยเฉพาะ สำหรับ i= n-1 – เพียงครั้งเดียวสำหรับเซลล์ที่ n-th และ (n-1)-th จากที่กล่าวมาข้างต้นตามมาว่าเมื่อใช้วิธีการแลกเปลี่ยนโดยตรง จะต้องดำเนินการวนรอบด้านนอก n-1 ครั้ง และจำนวนการประมวลผลของวงในในส่วนเนื้อหาที่ต้องทำการเปรียบเทียบและการจัดเรียงตัวเลขใหม่จะลดลง จาก n-1 ถึง 1 ที่มาของคำว่า "วิธีบับเบิ้ล" ได้รับการอธิบายดังนี้: หากคุณจินตนาการถึงการจัดเรียงเซลล์อาเรย์ในแนวตั้งโดยมีดัชนีเพิ่มขึ้นจากบนลงล่าง จำนวนที่น้อยที่สุดที่พิจารณาจะลอยขึ้นเหมือนฟองในน้ำ ในตัวอย่างของเรา เมื่อ i=3 การเรียงสับเปลี่ยนจะนำไปสู่สถานะของอาร์เรย์ดังต่อไปนี้ เมื่อใช้วิธีการแบบฟอง ไม่สำคัญว่าการวิเคราะห์คู่ของตัวเลขในอาร์เรย์จะเคลื่อนไปสู่ดัชนีที่เพิ่มขึ้นหรือลดลง และประเภทของการเรียงลำดับ (จากน้อยไปหามากหรือจากมากไปน้อย) จะถูกกำหนดโดยเงื่อนไขของการเรียงสับเปลี่ยนของตัวเลขเท่านั้น ( อันที่เล็กกว่าควรอยู่ด้านหลังอันที่ใหญ่กว่าหรือกลับกัน) แก้ไขวิธีการแลกเปลี่ยนโดยตรง (วิธีแก้ไขฟอง) ดังที่เห็นได้จากตัวอย่างเชิงตัวเลขข้างต้น อาเรย์จะถูกเรียงลำดับหลังจากขั้นตอนที่สี่ นั่นคือ มีความเป็นไปได้ที่จะดำเนินการลูปภายนอกไม่ใช่ n-1 ครั้ง แต่น้อยกว่า เมื่อรู้ว่าอาเรย์นั้น สั่งแล้ว การตรวจสอบนี้อิงตามสิ่งต่อไปนี้: หากไม่มีการเรียงสับเปลี่ยนระหว่างการดำเนินการของลูปด้านใน แสดงว่าอาร์เรย์ได้รับการสั่งซื้อแล้ว และคุณสามารถออกจากลูปด้านนอกได้ ตัวแปรประเภทบูลีนถูกใช้เป็นสัญญาณบ่งชี้ว่ามีการเรียงสับเปลี่ยนหรือไม่: ก่อนที่จะเข้าสู่วงใน ตัวแปรจะได้รับค่าหนึ่งค่า เช่น เท็จ และเมื่อดำเนินการเรียงสับเปลี่ยน จะได้รับค่าอื่น เช่น จริง. เห็นได้ชัดว่าผลของการใช้วิธีฟองสบู่ที่ถูกดัดแปลงเมื่อเปรียบเทียบกับวิธีที่ไม่มีการดัดแปลงในการเร่งกระบวนการคัดแยกจะถูกสังเกตหากลำดับตัวเลขเดิมใกล้เคียงกับการเรียงลำดับในทิศทางที่ต้องการ ในกรณีที่ร้ายแรง เมื่ออาร์เรย์ได้รับการสั่งซื้อตามวิธีที่ต้องการแล้ว เนื้อความของลูปด้านนอกจะถูกดำเนินการเพียงครั้งเดียว แนวคิดเบื้องหลังการเลือกประเภทคืออะไร? อย่างไรก็ตาม ความไม่เชิงเส้นในปัจจุบันกำลังเป็นที่นิยม ดังนั้น โดยไม่ต้องเขียนสิ่งพิมพ์ทั้งหมดเกี่ยวกับการเรียงลำดับการแทรก วันนี้ฉันจะเริ่มหัวข้อคู่ขนานเกี่ยวกับการเรียงลำดับการเลือก จากนั้น ฉันจะทำเช่นเดียวกันกับคลาสอัลกอริธึมอื่นๆ เช่น การเรียงลำดับแบบผสาน การเรียงลำดับการกระจาย ฯลฯ โดยทั่วไปสิ่งนี้จะช่วยให้คุณสามารถเขียนสิ่งพิมพ์ในหัวข้อใดหัวข้อหนึ่งได้ ด้วยการสลับธีมแบบนี้ มันจะสนุกมากขึ้น เรียบง่ายและไม่โอ้อวด - เราผ่านอาร์เรย์เพื่อค้นหาองค์ประกอบสูงสุด ค่าสูงสุดที่พบจะถูกสลับกับองค์ประกอบสุดท้าย ส่วนที่ไม่มีการเรียงลำดับของอาร์เรย์ลดลงหนึ่งองค์ประกอบ (ไม่รวมองค์ประกอบสุดท้ายที่เราย้ายค่าสูงสุดที่พบ) เราใช้การกระทำเดียวกันกับส่วนที่ไม่ได้เรียงลำดับนี้ - เราค้นหาค่าสูงสุดและวางไว้ในตำแหน่งสุดท้ายในส่วนที่ไม่มีการเรียงลำดับของอาร์เรย์ และเราทำเช่นนี้ต่อไปจนกว่าส่วนที่ไม่ได้เรียงลำดับของอาร์เรย์จะลดลงเหลือองค์ประกอบเดียว การเลือก Def (ข้อมูล): สำหรับ i, e ในการแจกแจง (ข้อมูล): mn = min (ช่วง (i, len (ข้อมูล)), key=data.__getitem__) data[i], data = data, e return data การเรียงลำดับการเลือกแบบง่ายเป็นการค้นหาซ้ำซ้อนแบบใช้กำลังเดรัจฉาน สามารถปรับปรุงได้หรือไม่? ลองดูการปรับเปลี่ยนเล็กน้อย มีการใช้แนวคิดที่คล้ายกันใน ซึ่งเป็นรูปแบบหนึ่งของ Bubble sort เมื่อพิจารณาส่วนที่ไม่ได้เรียงลำดับของอาร์เรย์ นอกเหนือจากค่าสูงสุดแล้ว เรายังพบค่าต่ำสุดตลอดทางด้วย เราใส่ขั้นต่ำไว้อันดับแรก สูงสุดอยู่อันดับสุดท้าย ดังนั้นส่วนที่ไม่ได้เรียงลำดับจะลดลงสององค์ประกอบในการวนซ้ำแต่ละครั้ง เมื่อมองแวบแรก ดูเหมือนว่าวิธีนี้จะเร่งความเร็วอัลกอริธึม 2 เท่า - หลังจากแต่ละรอบผ่านไป อาร์เรย์ย่อยที่ไม่ได้เรียงลำดับจะไม่ลดลงด้านเดียว แต่ทั้งสองด้านพร้อมกัน แต่ในขณะเดียวกัน จำนวนการเปรียบเทียบก็เพิ่มขึ้นสองเท่า ในขณะที่จำนวนสวอปยังคงไม่เปลี่ยนแปลง การเลือกคู่จะเพิ่มความเร็วของอัลกอริทึมเพียงเล็กน้อยเท่านั้น และในบางภาษา มันยังทำงานช้าลงด้วยเหตุผลบางประการอีกด้วย ข้อแตกต่างที่สำคัญ: ในการเรียงลำดับการแทรกเราจะแยกออกจากส่วนที่ไม่ได้เรียงลำดับของอาร์เรย์ ใดๆองค์ประกอบและแทรกเข้าไปในตำแหน่งในส่วนที่เรียงลำดับ ในการเรียงลำดับการเลือกเราตั้งใจมองหา สูงสุดองค์ประกอบ (หรือน้อยที่สุด) ที่เราเสริมส่วนที่เรียงลำดับของอาร์เรย์ ในการแทรก เรากำลังมองหาตำแหน่งที่จะแทรกองค์ประกอบถัดไป และในการเลือก เรารู้ล่วงหน้าแล้วว่าเราจะใส่ตำแหน่งใด แต่ในขณะเดียวกัน เราก็ต้องหาองค์ประกอบที่สอดคล้องกับสถานที่นี้ สิ่งนี้ทำให้อัลกอริธึมทั้งสองคลาสแตกต่างกันอย่างสิ้นเชิงทั้งในด้านสาระสำคัญและวิธีการที่ใช้ ตัวอย่างเช่น หากอาร์เรย์เกือบจะเรียงลำดับแล้ว ดังที่ทราบกันดีว่าการเรียงลำดับการแทรกจะประมวลผลเร็วกว่ามาก (เร็วกว่าการเรียงลำดับอย่างรวดเร็วด้วยซ้ำ) และอาร์เรย์ที่เรียงลำดับย้อนกลับสำหรับการเรียงลำดับการแทรกจะเป็นกรณีที่เสื่อมลง โดยจะเรียงลำดับให้นานที่สุด และสำหรับการเรียงลำดับการเลือก การเรียงลำดับอาเรย์บางส่วนหรือแบบย้อนกลับนั้นไม่สำคัญ - มันจะประมวลผลด้วยความเร็วประมาณเดียวกับการสุ่มปกติ นอกจากนี้ สำหรับการเรียงลำดับการเลือกแบบคลาสสิก ไม่สำคัญว่าอาเรย์จะประกอบด้วยองค์ประกอบเฉพาะหรือองค์ประกอบที่ซ้ำกัน ซึ่งในทางปฏิบัติแล้วจะไม่ส่งผลต่อความเร็ว แต่โดยหลักการแล้ว คุณสามารถฉลาดขึ้นและปรับเปลี่ยนอัลกอริทึมเพื่อให้ทำงานได้เร็วขึ้นสำหรับชุดข้อมูลบางชุด ตัวอย่างเช่น การเรียงลำดับบิงโกจะพิจารณาว่าอาร์เรย์ประกอบด้วยองค์ประกอบที่ซ้ำกันหรือไม่ เคล็ดลับที่นี่คือในส่วนที่ไม่เรียงลำดับ ไม่เพียงแต่จดจำองค์ประกอบสูงสุดเท่านั้น แต่ยังกำหนดจำนวนสูงสุดสำหรับการวนซ้ำครั้งถัดไปด้วย วิธีนี้ช่วยให้คุณไม่ต้องค้นหาค่าสูงสุดนี้อีกทุกครั้ง แต่สามารถวางค่าเหล่านั้นเข้าที่ทันทีทันทีที่พบค่าสูงสุดนี้อีกครั้งในอาร์เรย์ ความซับซ้อนของอัลกอริทึมยังคงเหมือนเดิม แต่ถ้าอาร์เรย์ประกอบด้วยตัวเลขที่ซ้ำกัน การเรียงลำดับบิงโกจะเร็วกว่าการเรียงลำดับการเลือกปกติหลายสิบเท่า # Bingo sort def bingo(data): # ผ่านครั้งแรก มันทำงานเช่นนี้ มาดูอาร์เรย์แล้วเรียก X เซลล์ถัดไปในวงรอบนอกนี้ และเราดูว่าตำแหน่งใดในอาร์เรย์ที่เราต้องแทรกองค์ประกอบถัดไปจากเซลล์นี้ มีองค์ประกอบอื่นอยู่ตรงจุดที่คุณต้องการวาง เราจะส่งไปยังคลิปบอร์ด สำหรับองค์ประกอบนี้ในบัฟเฟอร์ เรายังค้นหาตำแหน่งในอาร์เรย์ด้วย (และแทรกลงในตำแหน่งนี้ และส่งองค์ประกอบที่สิ้นสุดในตำแหน่งนี้ไปยังบัฟเฟอร์) และสำหรับหมายเลขใหม่ในบัฟเฟอร์ เราก็ดำเนินการแบบเดียวกัน กระบวนการนี้ควรดำเนินต่อไปนานแค่ไหน? จนกว่าองค์ประกอบถัดไปในคลิปบอร์ดจะกลายเป็นองค์ประกอบที่ต้องแทรกลงในเซลล์ X (ตำแหน่งปัจจุบันในอาร์เรย์ในวงหลักของอัลกอริทึม) ไม่ช้าก็เร็วช่วงเวลานี้จะเกิดขึ้นจากนั้นในวงนอกคุณสามารถย้ายไปยังเซลล์ถัดไปและทำซ้ำขั้นตอนเดียวกันได้ ในการเลือกประเภทอื่นๆ เราจะมองหาค่าสูงสุด/ต่ำสุดเพื่อวางไว้ที่สุดท้าย/อันดับแรก ในการเรียงลำดับแบบวงจร ปรากฎว่าค่าต่ำสุดในตำแหน่งแรกในอาร์เรย์ย่อยคือตัวมันเอง เหมือนกับที่เคยเป็นอยู่ในกระบวนการขององค์ประกอบอื่น ๆ หลายอย่างที่ถูกวางไว้ในตำแหน่งที่ถูกต้องของพวกเขาที่ไหนสักแห่งตรงกลางของอาร์เรย์ และที่นี่ความซับซ้อนของอัลกอริทึมยังคงอยู่ภายใน O( หมายเลข 2- ในทางปฏิบัติ การเรียงลำดับแบบวนจะช้ากว่าการเรียงลำดับแบบปกติหลายเท่า เนื่องจากคุณต้องดำเนินการผ่านอาร์เรย์มากขึ้นและเปรียบเทียบบ่อยขึ้น นี่คือราคาสำหรับจำนวนการเขียนซ้ำขั้นต่ำที่เป็นไปได้ # Cyclic sorting def cycle(data): # เราผ่านอาร์เรย์เพื่อค้นหาวงจร cyclic สำหรับ cycleStart ในช่วง (0, len(data) - 1): value = data # เรามองหาตำแหน่งที่จะแทรกองค์ประกอบ pos = cycleStart สำหรับฉันอยู่ในช่วง (cycleStart + 1, len (ข้อมูล)): ถ้าข้อมูล [i]< value:
pos += 1
# Если элемент уже стоит на месте, то сразу
# переходим к следующей итерации цикла
if pos == cycleStart:
continue
# В противном случае, помещаем элемент на своё
# место или сразу после всех его дубликатов
while value == data:
pos += 1
data, value = value, data
# Циклический круговорот продолжается до тех пор,
# пока на текущей позиции не окажется её элемент
while pos != cycleStart:
# Ищем, куда переместить элемент
pos = cycleStart
for i in range(cycleStart + 1, len(data)):
if data[i] < value:
pos += 1
# Помещаем элемент на своё место
# или сразу после его дубликатов
while value == data:
pos += 1
data, value = value, data
return data
ในเวอร์ชันที่ง่ายที่สุด เราจะมองหาองค์ประกอบสูงสุดในส่วนที่ไม่ได้เรียงลำดับของอาร์เรย์ เมื่อพบจุดสูงสุดแล้ว เราจะเลี้ยวหักศอกสองครั้ง ขั้นแรก เราหมุนสายโซ่ขององค์ประกอบต่างๆ เพื่อให้ค่าสูงสุดอยู่ฝั่งตรงข้าม จากนั้นเราจะพลิกอาร์เรย์ย่อยที่ไม่ได้เรียงลำดับทั้งหมด ส่งผลให้ค่าสูงสุดตกเข้าที่ โดยทั่วไปแล้ว คอร์ตบัลเล็ตดังกล่าวนำไปสู่ความซับซ้อนของอัลกอริทึมของ O( หมายเลข 3- เหล่านี้เป็น ciliates ที่ได้รับการฝึกฝนซึ่งจะพังทลายลงในคราวเดียว (ดังนั้นประสิทธิภาพของพวกเขาจึงมีความซับซ้อน O( หมายเลข 2)) และเมื่อเขียนโปรแกรม การกลับส่วนของอาเรย์จะเป็นการวนซ้ำเพิ่มเติม การเรียงลำดับแพนเค้กนั้นน่าสนใจมากจากมุมมองทางคณิตศาสตร์ (ผู้ที่มีความคิดดีที่สุดเกี่ยวกับการประมาณจำนวนรอบขั้นต่ำที่เพียงพอสำหรับการเรียงลำดับ) มีสูตรของปัญหาที่ซับซ้อนมากขึ้น (โดยเรียกว่าด้านที่ถูกไฟไหม้) หัวข้อของแพนเค้กน่าสนใจอย่างยิ่งบางทีฉันจะเขียนเอกสารที่มีรายละเอียดเพิ่มเติมเกี่ยวกับประเด็นเหล่านี้ # Pancake sort def pancake(data): if len(data) > 1: for size in range(len(data), 1, -1): # Position of the maximum in the unsorted part maxindex = max(range(size) , key = data.__getitem__) ถ้า maxindex + 1 != ขนาด: # หากค่าสูงสุดไม่ใช่คำ คุณจะต้องย้อนกลับหาก maxindex != 0: # พลิกกลับเพื่อให้ # ค่าสูงสุดอยู่ที่ข้อมูลด้านซ้าย[: maxindex+1] = ย้อนกลับ (ข้อมูล [: maxindex +1]) # ย้อนกลับส่วนที่ไม่ได้เรียงลำดับของอาร์เรย์ # ค่าสูงสุดตกอยู่ในข้อมูลตำแหน่ง [: ขนาด] = ย้อนกลับ (ข้อมูล [: ขนาด]) ส่งคืนข้อมูล การเรียงลำดับการเลือกจะมีผลเท่ากับการค้นหาองค์ประกอบขั้นต่ำ/สูงสุดในส่วนที่ไม่มีการเรียงลำดับของอาร์เรย์เท่านั้น ในอัลกอริธึมทั้งหมดที่วิเคราะห์ในวันนี้ การค้นหาจะดำเนินการในรูปแบบของการค้นหาสองครั้ง และการค้นหาซ้ำ ไม่ว่าคุณจะมองอย่างไร ก็จะมีความซับซ้อนของอัลกอริทึมเสมอไปไม่ดีกว่า O( หมายเลข 2- นี่หมายความว่าการเลือกทุกประเภทถูกกำหนดให้หมายถึงความซับซ้อนของกำลังสองใช่หรือไม่ ไม่เลยหากกระบวนการค้นหามีการจัดการที่แตกต่างกันโดยพื้นฐาน ตัวอย่างเช่น พิจารณาชุดข้อมูลเป็นฮีปและค้นหาภายในฮีป อย่างไรก็ตาม หัวข้อของฮีปไม่ใช่บทความ แต่เป็นเรื่องราวทั้งหมด เราจะพูดถึงฮีปอย่างแน่นอน แต่เป็นอีกครั้งหนึ่ง วิธีการทั้งหมดที่อธิบายไว้ด้านล่างควรได้รับการพิจารณาว่าเป็นตัวแปรพิเศษของวิธีการที่เรียกว่า วิธีการเลือกโดยตรงหรือ จัดเรียงตามการเลือก- สิ่งที่วิธีการเหล่านี้มีเหมือนกันคือการค้นหา (เลือก) องค์ประกอบสูงสุดหรือต่ำสุดของอาร์เรย์และวางไว้ในเซลล์ที่ต่อเนื่องกันของอาร์เรย์ สาระสำคัญของวิธีนี้ (โดยคำนึงถึงข้อจำกัดที่เลือกไว้สำหรับตัวอย่างเชิงตัวเลขที่เรากำลังพิจารณา) มีดังต่อไปนี้ ในขั้นตอนแรก จำนวนต่ำสุดในบรรดาตัวเลขทั้งหมดในอาร์เรย์และดัชนีจะถูกพบและจัดเก็บไว้ในตัวแปร เช่น Xmin และดัชนีของมันถูกจัดเก็บไว้ในตัวแปรอื่น เช่น Imin จากนั้นตำแหน่งใน อาร์เรย์ของจำนวนขั้นต่ำที่พบจะถูกแลกเปลี่ยนกับองค์ประกอบแรกของอาร์เรย์: X:=X ; X:=Xนาที;. ในตัวอย่างของเรา จำนวนขั้นต่ำ Xmin=15 อยู่ในเซลล์ Imin=3 และการจัดเรียงตัวเลขแรกและตัวเลขต่ำสุดใหม่จะได้ผลลัพธ์ต่อไปนี้ สำหรับ i=3 เราจะได้ Xmin=21 และ Imin=4 และหลังจากการจัดเรียงใหม่ สำหรับ i=5 เราจะได้ Xmin=34 และ Imin=5 และหลังจากการจัดเรียงใหม่ ดังนั้น ลูปด้านนอกควรถูกดำเนินการ n-1 ครั้ง และจำนวนการประมวลผลของลูปด้านในจะลดลงจาก n-1 เป็น 1 หากต้องการเรียงลำดับอาร์เรย์จากมากไปน้อย ควรสลับหมายเลขขั้นต่ำตัวแรกที่พบกับหมายเลขสุดท้าย หนึ่งอันที่สองกับอันสุดท้ายเป็นต้น วิธีการค้นหาองค์ประกอบสูงสุด
วิธีนี้แตกต่างจากวิธีก่อนหน้าเฉพาะในกรณีที่พบองค์ประกอบสูงสุดเท่านั้น ด้วยการจัดระเบียบลูปเดียวกันเมื่อใช้วิธีการเหล่านี้พวกเขาจะให้ผลลัพธ์ที่ตรงกันข้าม: หากมีใครนำไปสู่การเพิ่มจำนวนในอาร์เรย์จากนั้นอีกฝ่ายจะนำไปสู่การลดลงและในทางกลับกัน วิธีการค้นหาดัชนี
องค์ประกอบขั้นต่ำ
วิธีการนี้จะแตกต่างจากวิธีการค้นหาองค์ประกอบขั้นต่ำและดัชนีของมันตรงที่วงในจะใช้เพื่อค้นหาเฉพาะดัชนีขององค์ประกอบขั้นต่ำ ดังนั้นการเรียงสับเปลี่ยนตัวเลขในอาร์เรย์ในแต่ละขั้นตอน i, i=1, 2 , ...,n-1 จะต้องดำเนินการโดยใช้ตัวแปรเพิ่มเติม เช่น R: R:=X[i]; X[i]:=X; X:=ร;. วิธีค้นหาดัชนีองค์ประกอบสูงสุด
วิธีการนี้แตกต่างจากวิธีก่อนหน้าเฉพาะในกรณีที่พบดัชนีขององค์ประกอบสูงสุดเท่านั้น ด้วยการจัดระเบียบลูปเดียวกันเมื่อใช้วิธีการเหล่านี้พวกเขาจะให้ผลลัพธ์ที่ตรงกันข้าม: หากมีใครนำไปสู่การเพิ่มจำนวนในอาร์เรย์จากนั้นอีกฝ่ายจะนำไปสู่การลดลงและในทางกลับกันการเรียงลำดับการแทรก
ผสานการเรียงลำดับ
จัดเรียงอย่างรวดเร็ว
วิธีแลกเปลี่ยนโดยตรง (วิธีฟอง)
การพูดนอกเรื่องโคลงสั้น ๆ ในตอนแรกในชุดบทความของฉัน ฉันวางแผนที่จะนำเสนอเนื้อหาเกี่ยวกับการเรียงลำดับคลาสตามลำดับที่เข้มงวดตามลำดับ หลังจากนั้น บทความต่างๆ ได้ถูกวางแผนเกี่ยวกับอัลกอริธึมการแทรกอื่นๆ: การเรียงลำดับไพ่คนเดียว การเรียงลำดับโต๊ะแบบเด็ก การเรียงลำดับแบบหลีกเลี่ยง ฯลฯ การเรียงลำดับการเลือก:: การเรียงลำดับการเลือก
การเรียงลำดับการเลือกคู่: การเรียงลำดับการเลือกคู่
ความแตกต่างระหว่างการเรียงลำดับการเลือกและการเรียงลำดับการแทรก
อาจดูเหมือนว่าการเรียงลำดับและการเรียงลำดับการเลือกโดยพื้นฐานแล้วเป็นสิ่งเดียวกัน ซึ่งเป็นคลาสอัลกอริธึมทั่วไป หรือการเรียงลำดับการแทรก - ประเภทของการเรียงลำดับการเลือก หรือการเรียงลำดับการเลือก - กรณีพิเศษของการเรียงลำดับการแทรก ในทั้งสองกรณี เราจะผลัดกันแยกองค์ประกอบออกจากส่วนที่ไม่ได้เรียงลำดับของอาร์เรย์ และเปลี่ยนเส้นทางไปยังพื้นที่ที่เรียงลำดับ เรียงลำดับบิงโก:: เรียงลำดับบิงโก
คุณลักษณะที่น่าสนใจของการเรียงลำดับการเลือกคือความเร็วไม่ได้ขึ้นอยู่กับลักษณะของข้อมูลที่กำลังเรียงลำดับ max = len(data) - 1 nextValue = data for i ในช่วง (สูงสุด - 1, -1, -1): ถ้า data[i] > nextValue: nextValue = data[i] ในขณะที่ max และ data == nextValue: max -= 1 # ผ่านครั้งต่อไป
การเรียงลำดับแบบวนเป็นเรื่องที่น่าสนใจ (และมีคุณค่าจากมุมมองเชิงปฏิบัติ) เนื่องจากการเปลี่ยนแปลงระหว่างองค์ประกอบของอาร์เรย์จะเกิดขึ้นก็ต่อเมื่อองค์ประกอบนั้นถูกวางในตำแหน่งสุดท้ายเท่านั้น สิ่งนี้มีประโยชน์หากการเขียนอาร์เรย์ใหม่มีราคาแพงเกินไป และเพื่อให้ระมัดระวังเกี่ยวกับหน่วยความจำกายภาพ คุณต้องลดจำนวนการเปลี่ยนแปลงในองค์ประกอบอาร์เรย์ให้เหลือน้อยที่สุด การเรียงลำดับแพนเค้ก
อัลกอริธึมที่เชี่ยวชาญทุกระดับของชีวิต - จากถึง วิธีการหาองค์ประกอบขั้นต่ำ