On this page
การค้นหา (Searching)
Linear search ไล่ดูทีละตัว O(n) เทียบกับ Binary search แบ่งครึ่ง O(log n) ที่เร็วกว่ามากบนข้อมูลที่เรียงแล้ว
การค้นหาข้อมูลคือสิ่งที่ทำบ่อยที่สุดในโปรแกรม มี 2 อัลกอริทึมพื้นฐานที่ต้องรู้ และความต่างของมันคือตัวอย่างที่ดีที่สุดของพลัง Big-O
Linear Search — ไล่ดูทีละตัว O(n)
วิธีตรงไปตรงมาที่สุด: ดูทีละตัวตั้งแต่ต้นจนเจอ ใช้ได้กับข้อมูลทุกแบบ ไม่ต้องเรียงก่อน แต่ถ้าข้อมูลมีล้านตัวและเป้าหมายอยู่ท้าย ก็ต้องดูล้านครั้ง
def linear_search(arr, target):
for i in range(len(arr)):
if arr[i] == target:
return i # เจอ คืน index
return -1 # ไม่เจอ
print(linear_search([4, 2, 7, 1, 9], 7)) # 2
print(linear_search([4, 2, 7, 1, 9], 5)) # -1
# Python มี in และ index() ให้ใช้อยู่แล้ว (ก็เป็น O(n))
print(7 in [4, 2, 7]) # TrueBinary Search — แบ่งครึ่งค้นหา O(log n)
ใช้ได้เฉพาะกับข้อมูลที่ "เรียงแล้ว" หลักการคือดูค่ากลาง ถ้าน้อยไปตัดครึ่งซ้ายทิ้ง ถ้ามากไปตัดครึ่งขวาทิ้ง ทุกรอบตัดข้อมูลเหลือครึ่ง เหมือนเปิดพจนานุกรมหาคำ ไม่ได้เปิดทีละหน้า
def binary_search(arr, target):
left, right = 0, len(arr) - 1
while left <= right:
mid = (left + right) // 2 # ตำแหน่งกลาง
if arr[mid] == target:
return mid # เจอ
elif arr[mid] < target:
left = mid + 1 # เป้าอยู่ครึ่งขวา
else:
right = mid - 1 # เป้าอยู่ครึ่งซ้าย
return -1
print(binary_search([1, 3, 5, 7, 9, 11], 7)) # 3
print(binary_search([1, 3, 5, 7, 9, 11], 4)) # -1ข้อมูล 1,000,000 ตัว linear search ต้องดูสูงสุด 1 ล้านครั้ง แต่ binary search ดูแค่ ~20 ครั้ง! เพราะทุกรอบตัดเหลือครึ่ง (1M → 500k → 250k → ...) นี่คือพลังของ O(log n)
Binary search ใช้ได้ก็ต่อเมื่อข้อมูลเรียงแล้วเท่านั้น ถ้ายังไม่เรียงต้อง sort ก่อน (O(n log n)) ระวัง off-by-one ตรง mid + 1 และ mid - 1 ซึ่งเป็นจุดที่พลาดบ่อย
เปรียบเทียบ
| Linear Search | Binary Search | |
|---|---|---|
| Big-O | O(n) | O(log n) |
| ต้องเรียงก่อนไหม | ไม่ต้อง | ต้อง |
| 1 ล้านตัว (worst) | ~1,000,000 ครั้ง | ~20 ครั้ง |
| เหมาะเมื่อ | ข้อมูลน้อย/ไม่เรียง | ข้อมูลเยอะและเรียงแล้ว |
ถ้าแค่ต้องเช็คว่า "มีค่านี้ไหม" บ่อย ๆ ไม่ต้องเรียงแล้ว binary search — โยนลง set/dict แล้วใช้ x in s ได้ O(1) เลย (เร็วกว่า O(log n) อีก) เลือก binary search เมื่อข้อมูลเรียงอยู่แล้วหรือต้องหา "ตำแหน่ง/ขอบเขต" ส่วนเช็คสมาชิกล้วน ๆ ใช้ set
สรุปหัวข้อนี้
- Linear search ไล่ดูทีละตัว O(n) ใช้ได้กับข้อมูลทุกแบบ ไม่ต้องเรียง
- Binary search แบ่งครึ่งทุกรอบ O(log n) เร็วกว่ามาก แต่ข้อมูลต้องเรียงแล้ว
- ทุกรอบของ binary search ตัดข้อมูลเหลือครึ่ง — ล้านตัวค้นแค่ ~20 ครั้ง
- ระวัง off-by-one ตรง mid+1 / mid-1
1) เขียน linear search คืน index ของค่าที่หา 2) เขียน binary search เอง แล้วทดสอบกับลิสต์เรียงแล้ว 3) นับว่า binary search บนลิสต์ 1000 ตัว ใช้กี่รอบ (ลองใส่ print นับ) 4) ดัดแปลง binary search ให้หา "ค่าแรกที่มากกว่าหรือเท่ากับ target"