แต่ละรอบหา minimum จากส่วนที่ยังไม่เรียง
ใช้ลูปใน (j จาก i+1 ถึง n-1) ไล่เปรียบเทียบ arr[j] กับ arr[minIndex] — ถ้าเจอค่าน้อยกว่า ให้อัปเดต minIndex
Basic Sorting
เรียนรู้ Selection Sort ตั้งแต่แนวคิด วิธีทำงานทีละขั้น พร้อมตัวอย่างโค้ดและแบบฝึกหัด
Selection Sort คืออัลกอริทึมเรียงข้อมูลที่ใช้แนวคิด "เลือกก่อนแล้วค่อยสลับ" — ในแต่ละรอบเราจะค้นหาค่าที่น้อยที่สุด (หรือมากที่สุด) ในช่วงที่ยังไม่เรียง แล้วสลับค่านั้นไปไว้ตำแหน่งหน้าสุดของช่วง
ข้อแตกต่างที่สำคัญจาก Bubble Sort: Bubble Sort จะสลับสมาชิกที่ติดกันบ่อยครั้งในแต่ละ pass แต่ Selection Sort จะหา minimum ให้เจอก่อน แล้วสลับเพียงครั้งเดียวต่อรอบ — ทำให้จำนวนครั้งในการสลับน้อยกว่า Bubble Sort มาก
ในมุมมองของ Selection Sort อาเรย์จะถูกแบ่งเป็น 2 ส่วนเสมอ: ด้านซ้ายคือส่วนที่เรียงแล้ว (sorted partition) และด้านขวาคือส่วนที่ยังไม่เรียง (unsorted partition)
เมื่อเริ่มต้น ส่วนที่เรียงแล้วจะว่างเปล่า ทุกครั้งที่เราหา minimum จากฝั่งขวาแล้วสลับมาไว้หน้าสุด ส่วนที่เรียงแล้วจะขยายออกไป 1 ตำแหน่ง และส่วนที่ยังไม่เรียงจะหดลง 1 ตำแหน่ง — ทำซ้ำจนส่วนที่ยังไม่เรียงว่างเปล่า
ด้านซ้าย (สีเข้ม) = ส่วนที่เรียงแล้ว — ด้านขวา (สีอ่อน) = ส่วนที่ยังไม่เรียง
เราจะสาธิตด้วยอาเรย์ [29, 10, 14, 37, 13] โดยเรียงจากน้อยไปมาก มาดูกันว่า Selection Sort เลือกและสลับอย่างไรในแต่ละรอบ
แต่ละรอบค้นหาค่าน้อยสุดจากส่วนที่ยังไม่เรียง (สีอ่อน) แล้วไฮไลต์ไว้
ค่าน้อยสุดที่ถูกเลือก (สีเขียว) จะถูกสลับมาไว้ตำแหน่งหน้าสุดของช่วงที่ยังไม่เรียง
สังเกตว่า Selection Sort สลับเพียง 3 ครั้งสำหรับอาเรย์ 5 ตัว (สูงสุด n-1 = 4 ครั้ง) — น้อยกว่า Bubble Sort ที่ต้องสลับหลายสิบครั้งในกรณีเดียวกัน
โครงแนวคิดก่อนแปลงเป็นโค้ดจริง — หา minimum ใน loop ใน แล้วสลับทีเดียว
ฟังก์ชัน selectionSort(values):
arr = คัดลอก values
n = จำนวนสมาชิกของ arr
ทำซ้ำ i จาก 0 ถึง n - 2:
minIndex = i
ทำซ้ำ j จาก i + 1 ถึง n - 1:
ถ้า arr[j] < arr[minIndex]:
minIndex = j
ถ้า minIndex ไม่เท่ากับ i:
สลับ arr[i] กับ arr[minIndex]
คืนค่า arrค้นหา minimum ในแต่ละรอบ แล้วสลับเพียงครั้งเดียวต่อรอบ
function selectionSort(values) {
const arr = [...values];
for (let i = 0; i < arr.length - 1; i += 1) {
let minIndex = i;
for (let j = i + 1; j < arr.length; j += 1) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
if (minIndex !== i) {
const temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
return arr;
}
console.log(selectionSort([29, 10, 14, 37, 13]));
// [10, 13, 14, 29, 37]อธิบายทีละส่วน: • `const arr = [...values]` — สร้างสำเนาอาเรย์ • `for (let i = 0; i < arr.length - 1; i += 1)` — ลูปนอก: i คือตำแหน่งที่เรากำลังจะล็อกค่าให้ถูกต้อง (ขยาย sorted partition) • `let minIndex = i` — ตั้งสมมติฐานว่าตำแหน่ง i มีค่าน้อยสุดในส่วนที่ยังไม่เรียง • `for (let j = i + 1; j < arr.length; j += 1)` — ลูปใน: ไล่หาค่าที่น้อยกว่า minIndex จริง • `if (minIndex !== i)` — ถ้าค่าน้อยสุดไม่ได้อยู่ที่ i ตั้งแต่แรก จึงสลับ — ไม่เช่นนั้นไม่ต้องทำอะไร
ได้เวลาลงมือเขียน Selection Sort — เริ่มจากการเขียนฟังก์ชันหา index ของค่าน้อยสุดก่อน แล้วค่อยประกอบเป็น Selection Sort ที่สมบูรณ์
Space Complexity = O(1) — Selection Sort เป็น in-place algorithm ใช้ตัวแปร i, j, minIndex, temp เท่านั้น ไม่ต้องสร้างโครงสร้างข้อมูลใหม่ หมายเหตุ: ต่างจาก Bubble Sort ที่ Best Case อาจเป็น O(n) ได้เมื่อใช้ optimized version — Selection Sort ไม่มี early exit เพราะต้องตรวจข้อมูลทั้งหมดเพื่อหา minimum เสมอ
| n (ขนาดข้อมูล) | จำนวนการเปรียบเทียบ (~n²/2) | จำนวนการสลับ (สูงสุด) | เปรียบเทียบ Bubble Sort Worst |
|---|---|---|---|
| 10 | ~45 | 9 | ~45 (สลับสูงกว่ามาก) |
| 100 | ~4,950 | 99 | ~4,950 |
| 1,000 | ~499,500 | 999 | ~499,500 |
| 10,000 | ~50M | 9,999 | ~50M |
| ข้อดี | ข้อเสีย | กรณีที่เหมาะสม |
|---|---|---|
| จำนวนการสลับน้อยมาก — สูงสุดเพียง n-1 ครั้ง | Best Case ก็ยังเป็น O(n²) — ไม่มี early exit | เมื่อต้นทุนการสลับสูง — เช่น การสลับ record ขนาดใหญ่ในหน่วยความจำ |
| เข้าใจง่าย — แนวคิดเลือกแล้วสลับตรงไปตรงมา | ไม่ใช่ stable sort ในรูปแบบพื้นฐาน (การสลับอาจเปลี่ยนลำดับของค่าที่เท่ากัน) | การเรียนการสอน — แนะนำแนวคิดการหา minimum และ index manipulation |
| ใช้หน่วยความจำ O(1) — in-place | ประสิทธิภาพการเปรียบเทียบแย่กว่า Insertion Sort เมื่อข้อมูลเกือบเรียง | ข้อมูลขนาดเล็ก (n < 100) ที่จำนวนการสลับสำคัญกว่าจำนวนการเปรียบเทียบ |
| ปริมาณงาน (จำนวนการเปรียบเทียบ) คาดการณ์ได้ — n(n-1)/2 ทุกครั้ง | ช้ากับข้อมูลใหญ่ — O(n²) ไม่เหมาะกับ n > 1,000 | ใช้เป็นขั้นตอนย่อยในอัลกอริทึมอื่น — เช่น Heap Sort ใช้แนวคิดเลือก max/min คล้ายกัน |
ข้อแตกต่างสำคัญ: จำนวนการสลับ
Bubble Sort สลับทุกครั้งที่คู่ติดกันผิดลำดับ (อาจหลายสิบครั้ง) ส่วน Selection Sort สลับเพียง 1 ครั้งต่อรอบ (สูงสุด n-1 ครั้งทั้งอัลกอริทึม) — ถ้าต้นทุนการสลับสูง (เช่น การย้ายข้อมูลขนาดใหญ่) Selection Sort จะได้เปรียบชัดเจน
| หัวข้อ | Bubble Sort | Selection Sort |
|---|---|---|
| แนวคิด | เปรียบเทียบ-สลับสมาชิกติดกัน | ค้นหา minimum แล้วสลับทีเดียว |
| จำนวนการสลับ (Worst) | ≈ n²/2 ครั้ง | ≤ n-1 ครั้ง |
| Best Time | O(n) — แบบ optimized | O(n²) — ไม่มี early exit |
| Average Time | O(n²) | O(n²) |
| Worst Time | O(n²) | O(n²) |
| Stable | ใช่ | ไม่ (ในรูปแบบพื้นฐาน) |
| เหมาะกับ | โค้ดง่าย + ข้อมูลเกือบเรียง | จำนวนสลับต้องน้อย + ต้นทุนสลับสูง |
หัวใจสำคัญของ Selection Sort ที่ต้องจำให้ขึ้นใจ
ใช้ลูปใน (j จาก i+1 ถึง n-1) ไล่เปรียบเทียบ arr[j] กับ arr[minIndex] — ถ้าเจอค่าน้อยกว่า ให้อัปเดต minIndex
หลังหา minIndex ได้แล้ว → `if (minIndex !== i)` แล้วสลับ arr[i] กับ arr[minIndex] — ไม่เหมือน Bubble Sort ที่สลับตลอดเวลา
หลังแต่ละรอบเสร็จ ตำแหน่ง 0..i จะเรียงถูกต้อง — ตำแหน่ง i+1..n-1 คือส่วนที่ยังไม่เรียงที่ต้องจัดการต่อ
ไม่ว่า Best, Average, หรือ Worst — ต้องเปรียบเทียบ n(n-1)/2 ครั้งเสมอ เพราะต้องสแกนหาค่าน้อยสุดในทุกช่วง ต่างจาก Bubble Sort ที่ Best Case เป็น O(n)
ถึงแม้ข้อมูลเรียงอยู่แล้ว Selection Sort ก็ยังต้องวนหาค่าน้อยสุดในทุกช่วง — ถ้าต้องการ Best Case O(n) ให้ใช้ Insertion Sort หรือ Bubble Sort แบบ optimized แทน
ทดสอบความเข้าใจก่อนไปต่อ
คิดถึงสิ่งที่ Selection Sort ต้องทำในแต่ละรอบ