Big-O Notation
O(log n) — Logarithmic Time
เรียนรู้ O(log n) Logarithmic Time — operations ที่ตัดข้อมูลทิ้งครึ่งหนึ่งทุกขั้นตอน พร้อม 6 Labs ฝึกเขียน halving, number guessing, boundary search, doubling, power of 2, และ binary search
O(log n) คืออะไร
O(log n) หรือ **Logarithmic Time** หมายความว่า ทุกขั้นตอนจะ **ตัดข้อมูลทิ้งครึ่งหนึ่ง** — ทำให้จำนวนขั้นตอนเติบโตช้ามาก แม้ n จะใหญ่ขึ้นมาก
ลองนึกภาพ: คุณมีหนังสือพจนานุกรม 1,000 หน้า และต้องหาคำว่า "mongoose" คุณไม่ไล่หน้าทีละหน้า (นั่นคือ O(n)) แต่เปิดกลางเล่มก่อน ดูว่าคำที่หาอยู่ก่อนหรือหลังจุดนั้น แล้วตัดครึ่งที่ไม่เกี่ยวทิ้ง — ทำซ้ำจนเจอ นี่คือ O(log n)
ทำไม log₂(n) ถึงเติบโตช้ามาก
เพราะทุกรอบตัดทิ้งครึ่งหนึ่ง จำนวนขั้นตอนจึงเป็น **logarithm base 2** ของ n — คือ 2 ยกกำลังเท่าไหร่จึงจะได้ n
| n (ขนาดข้อมูล) | log₂(n) (จำนวนขั้นตอน) | เปรียบเทียบ |
|---|---|---|
| 10 | ~3 | 3 รอบ |
| 100 | ~7 | 7 รอบ |
| 1,000 | ~10 | 10 รอบ |
| 1,000,000 | ~20 | แค่ 20 รอบ! |
| 1,000,000,000 | ~30 | แค่ 30 รอบ! |
สังเกต: เมื่อ n เพิ่ม 1,000 เท่า (จาก 1,000 เป็น 1,000,000) จำนวนขั้นตอนเพิ่มแค่ 10 (จาก 10 เป็น 20) — นี่คือพลังของ O(log n)
ตัวอย่าง O(log n): การตัดครึ่งซ้ำๆ
รูปแบบที่พบบ่อยที่สุดของ O(log n) คือ **การวนลูปที่ทุกรอบลดขนาดปัญหาลงครึ่งหนึ่ง** — เช่น หารด้วย 2, ย้ายขอบเขตซ้าย/ขวา, หรือข้ามไปครึ่งทาง
กฎง่ายๆ: **ถ้าทุกรอบของ loop ลดขนาดข้อมูลลงคงที่ (เช่น ครึ่งหนึ่ง) นั่นคือ O(log n)**
ตัวอย่าง O(log n): ค้นหาในข้อมูลที่เรียงแล้ว
เมื่อข้อมูล **เรียงลำดับแล้ว** เราสามารถตรวจจุดกลางแล้วตัดครึ่งทิ้งได้เลย — ไม่ต้องไล่ดูทุกตัว เทคนิคนี้เรียกว่า binary search
ทุกรอบของ while loop ตัดช่วงค้นหาทิ้งครึ่งหนึ่ง (ย้าย left หรือ right) ทำให้จำนวนรอบ = log₂(n) — เราจะเจาะจง binary search เพิ่มเติมในบทเรียนถัดไปของ phase Searching
สิ่งที่ **ไม่ใช่** O(log n)
เข้าใจผิดบ่อยที่สุดคือ คิดว่า loop ที่ใช้ / 2 ทุกรอบเป็น O(log n) เสมอ ความจริงคือ **ถ้า loop ไม่ได้ลดขนาดปัญหาลงอย่างก้าวหน้า มันไม่ใช่ O(log n)**
กฎง่ายๆ: **O(log n) ต้องมีการ "ตัดทิ้ง" ส่วนของข้อมูลอย่างก้าวหน้าทุกรอบ** — ถ้าทุกรอบยังต้องดูข้อมูลทั้งหมด นั่นคือ O(n) หรือมากกว่า
กฎสำคัญ: O(log n) Patterns
O(log n) — Logarithmic Time
Operations ที่ลดขนาดปัญหาลงครึ่งหนึ่งทุกขั้นตอน
Halving loop (หาร 2 ซ้ำ)
ทุกรอบ n = n / 2 จำนวนรอบ = log₂(n) เช่น n=1024 ใช้ 10 รอบ
Binary search (ค้นหาใน sorted array)
ตรวจจุดกลาง ตัดครึ่งทิ้ง ทำซ้ำจนเจอ — ไม่ต้องไล่ทุกตัว
Doubling loop (คูณ 2 ซ้ำ)
Inverse ของ halving — log คือ inverse ของ exponent
Power of 2 check (หาร 2 ซ้ำจนเหลือ 1)
จำนวนรอบไม่เกิน log₂(n)
Linear scan, nested loops, sort ทั้ง array
ไล่ทุกตัว = O(n) ซ้อน = O(n²) sort = O(n log n) — ไม่ใช่ O(log n)
Lab 1: นับจำนวนครั้งที่ตัดครึ่ง
Lab 2: เดาเลขโดยตัดครึ่ง
Lab 3: หาตำแหน่งแรกที่เกินค่า
Lab 4: นับจำนวนครั้งที่คูณสอง
Lab 5: ตรวจสอบว่าเป็น power of 2
Lab 6: ค้นหาใน array ที่เรียงแล้ว
สรุป O(log n) Operations
| Operation | ตัวอย่าง | ความเร็ว |
|---|---|---|
| หาร 2 ซ้ำจนเหลือ 1 | countHalvings(n) | O(log n) |
| เดาเลขตัดครึ่ง | guessNumber(max, secret) | O(log n) |
| ค้นหาใน sorted array | binaryContains(arr, x) | O(log n) |
| หา boundary ใน sorted | findFirstGreater(arr, t) | O(log n) |
| คูณ 2 ซ้ำจนถึงเป้า | countDoublings(s, t) | O(log n) |
| ตรวจ power of 2 | isPowerOfTwo(n) | O(log n) |
| ไล่ทุกตัวใน array | arr.indexOf(x) | O(n) ❌ |
| ซ้อน loop | for-for | O(n²) ❌ |
ทบทวนความเข้าใจ
O(log n) — Logarithmic Time
ทดสอบความเข้าใจเกี่ยวกับ O(log n) patterns