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

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

การเรียงลำดับทำงานอย่างไร?

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

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

ไม่มีความลับว่ามีอัลกอริธึมที่ดีกว่าสำหรับการค้นหาภายในอาร์เรย์ที่เรียงลำดับ ด้วยการใช้อัลกอริธึมง่ายๆ เราสามารถค้นหาองค์ประกอบเฉพาะในอาร์เรย์ที่เรียงลำดับซึ่งมีองค์ประกอบ 1,000,000 รายการโดยใช้การเปรียบเทียบเพียง 20 รายการ! แน่นอนว่าข้อเสียก็คือการเรียงลำดับอาร์เรย์ที่มีองค์ประกอบจำนวนมากนั้นมีราคาค่อนข้างแพง และแน่นอนว่าไม่ได้ทำเพื่อคำค้นหาคำเดียว

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

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

ในการสลับสององค์ประกอบเราสามารถใช้ฟังก์ชันได้ มาตรฐาน::swap()จากไลบรารีมาตรฐาน C++ ซึ่งกำหนดไว้ในอัลกอริทึม ใน C ++ 11 std::swap() ถูกย้ายไปยังไฟล์ส่วนหัวของยูทิลิตี้:

#รวม #รวม int main() ( int a = 3; int b = 5; std::cout<< "Before swap: a = " << a << ", b = " << b << "\n"; std::swap(a, b); // меняем местами значения переменных a и b std::cout << "After swap: a = " << a << ", b = " << b << "\n"; }

#รวม

#รวม // สำหรับ std::swap ใน C ++ 11 ใช้ส่วนหัว

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 ++:

#รวม #รวม // สำหรับ std::swap ใน C ++ 11 ใช้ส่วนหัว int main() ( const int length = 5; int array = ( 30, 50, 20, 10, 40 ); // วนซ้ำแต่ละองค์ประกอบของอาร์เรย์ // (ยกเว้นอันสุดท้ายจะถูกจัดเรียงตามแล้ว ถึงเวลาที่เราไปถึงที่นั่นกันเถอะ) สำหรับ (int startIndex = 0; startIndex< length - 1; ++startIndex) { // В переменной smallestIndex хранится индекс наименьшего значения, которое мы нашли в этой итерации // Начинаем с того, что наименьший элемент в этой итерации - это первый элемент (индекс 0) int smallestIndex = startIndex; // Затем ищем элемент поменьше в остальной части массива for (int currentIndex = startIndex + 1; currentIndex < length; ++currentIndex) { // Если мы нашли элемент, который меньше нашего наименьшего элемента, if (array < array) // то запоминаем его smallestIndex = currentIndex; } // smallestIndex теперь наименьший элемент // Меняем местами наше начальное наименьшее число с тем, которое мы обнаружили std::swap(array, array); } // Теперь, когда весь массив отсортирован - выводим его на экран for (int index = 0; index < length; ++index) std::cout << array << " "; return 0; }

#รวม

#รวม // สำหรับ std::swap ใน C ++ 11 ใช้ส่วนหัว

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++ จึงมีฟังก์ชันการเรียงลำดับในตัว - มาตรฐาน::เรียงลำดับ()- ตั้งอยู่ในไฟล์ส่วนหัวของอัลกอริทึมและเรียกว่าดังนี้:

#รวม #รวม // สำหรับ std::sort int main() ( const int length = 5; int array = ( 30, 50, 20, 10, 40 ); std::sort(array, array+length); for (int i= 0;< length; ++i) std::cout << array[i] << " "; return 0; }

#รวม

#รวม // สำหรับ std::sort

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 ด้วย:

#รวม #รวม // สำหรับ std::swap ใน C ++ 11 ใช้ส่วนหัว int main() ( const int length= 5; int array = ( 30, 50, 20, 10, 40 ); // วนซ้ำแต่ละองค์ประกอบอาร์เรย์ยกเว้นองค์ประกอบสุดท้ายสำหรับ (int startIndex = 0; startIndex< length - 1; ++startIndex) { // largestIndex - это индекс наибольшего элемента, который мы обнаружили до сих пор int largestIndex = startIndex; // Перебираем каждый элемент массива начиная со startIndex + 1 for (int currentIndex = startIndex + 1; currentIndex < length; ++currentIndex) { // Если текущий элемент больше нашего наибольшего элемента, if (array >array) // นี่คือองค์ประกอบที่ใหญ่ที่สุดใหม่ในการวนซ้ำ mostIndex = currentIndex;< length; ++index) std::cout << array << " "; return 0; }

#รวม

#รวม // สำหรับ std::swap ใน C ++ 11 ใช้ส่วนหัว

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

#รวม #รวม // สำหรับ std::swap ใน C ++ 11 ใช้ส่วนหัว int main() ( const int length(9); int array = ( 7, 5, 6, 4, 9, 8, 2, 1, 3 ); for (int วนซ้ำ = 0; วนซ้ำ< length-1; ++iteration) { // Перебираем каждый элемент массива до последнего элемента (не включительно) // Последний элемент не имеет пары для сравнения for (int currentIndex = 0; currentIndex < length - 1; ++currentIndex) { // Если текущий элемент больше элемента после него, то меняем их местами if (array >อาร์เรย์) std::swap(อาร์เรย์, อาร์เรย์);< length; ++index) std::cout << array << " "; return 0; }

#รวม

#รวม // สำหรับ std::swap ใน C ++ 11 ใช้ส่วนหัว

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 ข้อมูล[k])( เจ = k; ) ) tmp = ข้อมูล [i];

ข้อมูล [i] = ข้อมูล [j];

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

รหัสซี++

เป็นโมฆะ SortAlgo::bubbleSort (ข้อมูล int, int lenD) ( int tmp = 0; สำหรับ (int i = 0; i =(i+1);j--)( ถ้า (ข้อมูล[j]

การเรียงลำดับการแทรก

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

ในแต่ละรอบ ขนาดของขอบเขตที่เรียงลำดับจะเพิ่มขึ้น 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 =0 && ข้อมูล[i]>คีย์)( data = data[i]; i = i-1; data=key; ) ) )

ผสานการเรียงลำดับ

รหัสซี++

ถือเป็นโมฆะ 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 ทำ

  1. ในขณะที่ (X 0)ทำ

  2. 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 ครั้ง แต่น้อยกว่า เมื่อรู้ว่าอาเรย์นั้น สั่งแล้ว การตรวจสอบนี้อิงตามสิ่งต่อไปนี้: หากไม่มีการเรียงสับเปลี่ยนระหว่างการดำเนินการของลูปด้านใน แสดงว่าอาร์เรย์ได้รับการสั่งซื้อแล้ว และคุณสามารถออกจากลูปด้านนอกได้ ตัวแปรประเภทบูลีนถูกใช้เป็นสัญญาณบ่งชี้ว่ามีการเรียงสับเปลี่ยนหรือไม่: ก่อนที่จะเข้าสู่วงใน ตัวแปรจะได้รับค่าหนึ่งค่า เช่น เท็จ และเมื่อดำเนินการเรียงสับเปลี่ยน จะได้รับค่าอื่น เช่น จริง.

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

แนวคิดเบื้องหลังการเลือกประเภทคืออะไร?

  1. ในอาร์เรย์ย่อยที่ไม่ได้เรียงลำดับ จะมีการค้นหาค่าสูงสุด (ต่ำสุด) ในพื้นที่
  2. การเปลี่ยนแปลงสูงสุด (ขั้นต่ำ) ที่พบจะวางตำแหน่งด้วยองค์ประกอบสุดท้าย (แรก) ในอาร์เรย์ย่อย
  3. หากมีอาร์เรย์ย่อยที่ยังไม่ได้เรียงลำดับเหลืออยู่ในอาร์เรย์ ดูจุดที่ 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): # ผ่านครั้งแรก

max = len(data) - 1 nextValue = data for i ในช่วง (สูงสุด - 1, -1, -1): ถ้า data[i] > nextValue: nextValue = data[i] ในขณะที่ max และ data == nextValue: max -= 1 # ผ่านครั้งต่อไป

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

มันทำงานเช่นนี้ มาดูอาร์เรย์แล้วเรียก 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:=ร;.

วิธีค้นหาดัชนีองค์ประกอบสูงสุด

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