Mục lục bài họcĐang ở d06-b2
← A-Level Computer Science
0/30 bài đã học xong
Chương 6 · Algorithms and Data Structures · Bài 2/3 của chương · bài 17/30 của A-Level Computer Science

Searching, sorting and algorithm efficiency

Tìm kiếm, sắp xếp và hiệu quả thuật toán
← Mục lục bài học
Lý thuyết · English

Linear search

Check each element in turn. Works on unsorted data, needs no preparation, but on average examines half the list and in the worst case all of it — $O(n)$.

Binary search

Requires a sorted list. Compare the middle element; if the target is larger discard the lower half, if smaller discard the upper half, and repeat. Each comparison halves the remaining data, so the worst case is $O(\log_2 n)$: $1\,000\,000$ items need about $20$ comparisons. The precondition is the whole point — a binary search on unsorted data returns wrong answers, not slow ones.

Bubble sort

Repeatedly pass through the list swapping adjacent elements that are out of order; after each pass the largest remaining value has 'bubbled' to the end. A flag that records whether any swap occurred lets it stop early on nearly sorted data. Simple to code, but $O(n^2)$.

Insertion sort

Take each element and insert it into its correct place among those already sorted. Also $O(n^2)$, but usually faster than bubble sort in practice and very fast on nearly sorted data.

Talking about efficiency properly

Big-O describes how run time grows with input size, not the actual time. Doubling $n$ roughly doubles the work of an $O(n)$ algorithm and quadruples that of an $O(n^2)$ one — that difference is invisible at $n=10$ and decisive at $n=100\,000$. Also consider memory: an algorithm that is faster but needs a second copy of the data may not fit.

Choosing

Sort once and search many times, and the cost of sorting is repaid by binary searches. Search a small list once, and a linear search on unsorted data is the right answer.

Giải thích tiếng Việt

Tìm tuần tự

Kiểm tra từng phần tử một. Chạy được trên dữ liệu chưa sắp xếp, không cần chuẩn bị gì, nhưng trung bình phải xét nửa danh sách và trường hợp xấu nhất là toàn bộ — $O(n)$.

Tìm nhị phân

Đòi hỏi danh sách đã sắp xếp. So với phần tử giữa; nếu giá trị cần tìm lớn hơn thì bỏ nửa dưới, nhỏ hơn thì bỏ nửa trên, rồi lặp lại. Mỗi lần so làm dữ liệu còn lại giảm một nửa, nên trường hợp xấu nhất là $O(\log_2 n)$: $1\,000\,000$ phần tử chỉ cần khoảng $20$ lần so. Điều kiện tiên quyết mới là điểm mấu chốt — tìm nhị phân trên dữ liệu chưa sắp xếp cho ra kết quả SAI, chứ không phải kết quả chậm.

Sắp xếp nổi bọt

Duyệt danh sách nhiều lượt, đổi chỗ hai phần tử kề nhau nếu sai thứ tự; sau mỗi lượt, giá trị lớn nhất còn lại đã ‘nổi’ về cuối. Một cờ ghi nhận có xảy ra đổi chỗ hay không cho phép dừng sớm với dữ liệu gần như đã sắp. Dễ viết, nhưng $O(n^2)$.

Sắp xếp chèn

Lấy từng phần tử và chèn vào đúng vị trí trong phần đã sắp. Cũng $O(n^2)$, nhưng thực tế thường nhanh hơn nổi bọt và rất nhanh với dữ liệu gần như đã sắp.

Nói về hiệu quả cho đúng

Ký hiệu $O$ lớn mô tả thời gian chạy TĂNG THẾ NÀO theo kích thước đầu vào, không phải thời gian thực tế. Nhân đôi $n$ thì thuật toán $O(n)$ tốn gấp đôi công còn $O(n^2)$ tốn gấp bốn — khác biệt đó không thấy được ở $n=10$ và mang tính quyết định ở $n=100\,000$. Cũng phải xét bộ nhớ: một thuật toán nhanh hơn nhưng cần thêm một bản sao dữ liệu có thể không đủ chỗ chạy.

Chọn thế nào

Sắp một lần rồi tìm nhiều lần thì chi phí sắp xếp được đền bù bằng các lần tìm nhị phân. Còn tìm một lần trên danh sách nhỏ chưa sắp thì tìm tuần tự mới là đáp án đúng.

Tim nhi phan — moi lan doan bo mot NUA371219253144586371Tim 63: giua = vi tri 5 (gia tri 31) → 63 > 31, bo NUA TRAI44586371giua = 58 → 63 > 58, bo tiep nua trai6371giua = 63 → TIM THAY sau 3 lan soTim tuan tu can toi 9 lan. Voi 1 trieu phan tu: 20 lan vs 1 trieu lanDieu kien bat buoc: danh sach phai DA SAP XEP
Ba dòng này là toàn bộ ý tưởng tìm nhị phân. Câu hỏi hay gặp nhất không phải ‘tìm mấy bước’ mà là ‘vì sao phải sắp xếp trước’ — và câu trả lời là: không sắp thì phép loại bỏ một nửa không còn cơ sở.
Ví dụ — truy vết sắp xếp nổi bọt và đếm số phép so

Sắp xếp tăng dần dãy $[7,\ 3,\ 9,\ 2,\ 5]$ bằng sắp xếp nổi bọt. Ghi lại dãy sau mỗi lượt và đếm tổng số phép so nếu KHÔNG dùng cờ dừng sớm.

Giải.

Lượt 1 (so $4$ cặp):

$(7,3)$ đổi ⇒ $[3,7,9,2,5]$
$(7,9)$ giữ ⇒ $[3,7,9,2,5]$
$(9,2)$ đổi ⇒ $[3,7,2,9,5]$
$(9,5)$ đổi ⇒ $[3,7,2,5,9]$

Kết thúc lượt 1: $[3,7,2,5,\mathbf{9}]$ — giá trị lớn nhất đã về đúng chỗ.

Lượt 2 (so $3$ cặp):

$(3,7)$ giữ; $(7,2)$ đổi ⇒ $[3,2,7,5,9]$; $(7,5)$ đổi ⇒ $[3,2,5,7,9]$

Kết thúc lượt 2: $[3,2,5,\mathbf{7},9]$

Lượt 3 (so $2$ cặp):

$(3,2)$ đổi ⇒ $[2,3,5,7,9]$; $(3,5)$ giữ

Kết thúc lượt 3: $[2,3,\mathbf{5},7,9]$

Lượt 4 (so $1$ cặp): $(2,3)$ giữ ⇒ $[2,3,5,7,9]$

Kết quả: $[2,3,5,7,9]$.

Tổng số phép so $=4+3+2+1=\mathbf{10}$, đúng bằng $\dfrac{n(n-1)}{2}=\dfrac{5\times4}{2}=10$.

Nếu dùng cờ dừng sớm: lượt 4 không có phép đổi nào, nhưng thuật toán phải chạy hết lượt 4 mới biết điều đó. Ở dãy này, cờ tiết kiệm được lượt 5 trở đi (không có), tức không tiết kiệm gì. Cờ chỉ có giá trị lớn khi dữ liệu đã gần như sắp sẵn — ví dụ dãy $[1,2,3,5,4]$ chỉ cần hai lượt thay vì bốn.

Vì sao đây là $O(n^2)$: công thức $\dfrac{n(n-1)}{2}$ có số hạng bậc hai chi phối, nên gấp đôi $n$ làm số phép so tăng khoảng bốn lần.

Bẫy hay mất điểm — Áp tìm nhị phân lên dữ liệu chưa sắp xếp. Thuật toán vẫn chạy và vẫn trả về một kết quả — nhưng là kết quả SAI, vì phép loại bỏ nửa danh sách dựa hoàn toàn vào giả định dữ liệu có thứ tự. Đây là lỗi nguy hiểm vì nó không báo lỗi.
Phải nhớ — Tìm tuần tự $O(n)$ chạy trên mọi dữ liệu; tìm nhị phân $O(\log_2 n)$ nhưng bắt buộc dữ liệu đã sắp. Nổi bọt và chèn đều $O(n^2)$. Khi so sánh, hãy nói về cách chi phí TĂNG theo $n$ chứ đừng nói thuật toán nào ‘nhanh hơn’ chung chung.

Đọc xong rồi — làm thử ngay

Bài tập của chương Algorithms and Data Structures gồm 14 câu trắc nghiệm và 3 đề tự luận. Đáp án hiện ngay khi chọn, miễn phí.

Làm bài tập chương →