Chọn đến phần học sinh cần nhanh chóng thông qua mục lục bằng cách click đến phần đó
- I. Lý thuyết trọng tâm
- Giới thiệu bài toán sắp xếp
- 1. Thuật toán sắp xếp chèn (Insertion Sort)
- 2. Thuật toán sắp xếp chọn (Selection Sort)
- 3. Thuật toán sắp xếp nổi bọt (Bubble Sort)
- 4. So sánh ba thuật toán
- II. Phương pháp giải các dạng bài tập
- Dạng 1: Sắp xếp dãy cho trước bằng ba thuật toán
- Dạng 2: Nhập dãy từ bàn phím rồi sắp xếp
- Dạng 3: Viết thuật toán sắp xếp giảm dần
- Dạng 4: Ý nghĩa thực tế của thuật toán sắp xếp
- III. Sơ đồ tư duy
I. Lý thuyết trọng tâm
Giới thiệu bài toán sắp xếp
Ở bài học trước, ta đã thấy tìm kiếm nhị phân trên dãy đã sắp xếp nhanh hơn rất nhiều so với tìm kiếm tuần tự. Vì vậy, bài toán sắp xếp có vai trò quan trọng, gắn liền với bài toán tìm kiếm.
Phát biểu bài toán sắp xếp:
- Đầu vào: Dãy A gồm n phần tử: A[0], A[1], …, A[n−1].
- Đầu ra: Dãy A được sắp xếp lại theo thứ tự tăng dần: A[0] ≤ A[1] ≤ … ≤ A[n−1].
Có nhiều thuật toán sắp xếp khác nhau. Trong bài này, ta tìm hiểu ba thuật toán đơn giản và dễ hiểu nhất: sắp xếp chèn, sắp xếp chọn và sắp xếp nổi bọt.
1. Thuật toán sắp xếp chèn (Insertion Sort)
1.1. Ý tưởng
Hãy tưởng tượng bạn đang cầm một bộ bài trên tay và muốn xếp theo thứ tự. Bạn lấy từng lá bài từ trái sang phải, mỗi lá bài mới được chèn vào đúng vị trí trong phần đã sắp xếp phía trước.
Cụ thể, thuật toán cho chỉ số i chạy từ 1 (phần tử thứ hai) đến n − 1 (phần tử cuối). Tại mỗi bước, phần tử A[i] được “nhấc lên” rồi chèn vào vị trí đúng trong dãy con đã sắp xếp A[0], A[1], ..., A[i−1]. Sau n − 1 bước lặp, toàn bộ dãy được sắp xếp xong.
Thao tác chèn thực hiện bằng cách: lưu giá trị A[i] vào biến tạm, sau đó dịch chuyển các phần tử bên trái lớn hơn A[i] sang phải một vị trí, cuối cùng đặt A[i] vào ô trống.
1.2. Minh hoạ từng bước
Xét dãy A = [5, 3, 9, 7, 2]:
| Bước | Chỉ số i | Thao tác | Kết quả dãy |
|---|---|---|---|
| Ban đầu | – | – | 5, 3, 9, 7, 2 |
| Vòng 1 | i = 1 | A[1] = 3 nhỏ hơn 5 → chèn 3 vào trước 5 | 3, 5, 9, 7, 2 |
| Vòng 2 | i = 2 | A[2] = 9 đã lớn hơn 5 → giữ nguyên | 3, 5, 9, 7, 2 |
| Vòng 3 | i = 3 | A[3] = 7, vì 5 < 7 < 9 → chèn 7 vào giữa 5 và 9 | 3, 5, 7, 9, 2 |
| Vòng 4 | i = 4 | A[4] = 2 nhỏ hơn tất cả → chèn 2 vào đầu | 2, 3, 5, 7, 9 |

Quy luật: Tại mỗi bước, phần in đậm là dãy con đã sắp xếp. Phần tử tiếp theo được chèn vào đúng vị trí trong dãy con này.
1.3. Cài đặt bằng Python
def InsertionSort(A):
n = len(A)
for i in range(1, n):
value = A[i]
j = i - 1
while j >= 0 and A[j] > value:
A[j + 1] = A[j]
j = j - 1
A[j + 1] = value
Giải thích từng dòng:
- Dòng 3: Vòng
forchạyitừ 1 đến n−1 (duyệt từ phần tử thứ hai đến cuối). - Dòng 4: Lưu giá trị
A[i]vào biếnvalue(giống việc “nhấc” phần tử lên). - Dòng 5: Biến
jbắt đầu từ vị trí ngay bên tráii, dùng để duyệt ngược dãy con đã sắp xếp. - Dòng 6–8: Vòng
whilekiểm tra: nếuA[j]lớn hơnvaluethì dịchA[j]sang phải một ô (A[j+1] = A[j]), rồi lùijvề trái. Quá trình này tạo ra “khoảng trống” chovalue. - Dòng 9: Đặt
valuevào vị trí đúng (ô trống vừa tạo ra).
2. Thuật toán sắp xếp chọn (Selection Sort)
2.1. Ý tưởng
Ý tưởng rất trực quan: tại mỗi bước, tìm phần tử nhỏ nhất trong phần chưa sắp xếp rồi đổi chỗ nó với phần tử đầu tiên của phần chưa sắp xếp.
Cụ thể, chỉ số i chạy từ 0 đến n − 2. Tại bước thứ i, tìm phần tử nhỏ nhất trong đoạn A[i], A[i+1], ..., A[n−1] rồi đổi chỗ phần tử đó với A[i]. Sau mỗi bước, A[0], A[1], ..., A[i] đã nằm đúng vị trí cuối cùng.
2.2. Minh hoạ từng bước
Xét dãy A = [5, 3, 9, 7, 2]:
| Bước | Chỉ số i | Thao tác | Kết quả dãy |
|---|---|---|---|
| Ban đầu | – | – | 5, 3, 9, 7, 2 |
| Vòng 1 | i = 0 | Nhỏ nhất trong cả dãy là 2 → đổi chỗ 2 với 5 | 2, 3, 9, 7, 5 |
| Vòng 2 | i = 1 | Nhỏ nhất từ vị trí 1 trở đi là 3 → đã đúng chỗ | 2, 3, 9, 7, 5 |
| Vòng 3 | i = 2 | Nhỏ nhất từ vị trí 2 trở đi là 5 → đổi chỗ 5 với 9 | 2, 3, 5, 7, 9 |
| Vòng 4 | i = 3 | Nhỏ nhất từ vị trí 3 trở đi là 7 → đã đúng chỗ | 2, 3, 5, 7, 9 |

Quy luật: Phần in đậm là các phần tử đã được đặt đúng vị trí cuối cùng. Mỗi vòng lặp thêm một phần tử vào phần đã sắp xếp.
2.3. Cài đặt bằng Python
def SelectionSort(A):
n = len(A)
for i in range(n - 1):
iMin = i
for j in range(i + 1, n):
if A[j] < A[iMin]:
iMin = j
A[i], A[iMin] = A[iMin], A[i]
Giải thích từng dòng:
- Dòng 3: Vòng
forngoài chạyitừ 0 đến n−2 (không cần đến n−1 vì phần tử cuối tự động đúng chỗ). - Dòng 4: Giả sử phần tử nhỏ nhất nằm tại vị trí
i(biếniMinlưu chỉ số). - Dòng 5–7: Vòng
fortrong duyệt từi+1đếnn−1, nếu tìm thấy phần tử nhỏ hơnA[iMin]thì cập nhậtiMin. - Dòng 8: Đổi chỗ
A[i]vớiA[iMin]bằng phép gán đồng thời của Python.
3. Thuật toán sắp xếp nổi bọt (Bubble Sort)
3.1. Ý tưởng
Thuật toán lấy cảm hứng từ hiện tượng bọt khí nổi dần lên mặt nước. Ý tưởng: liên tục so sánh hai phần tử cạnh nhau, nếu chúng chưa đúng thứ tự thì đổi chỗ. Phần tử lớn sẽ dần “nổi” về cuối dãy sau mỗi vòng lặp.
Cụ thể, thuật toán dùng hai vòng lặp lồng nhau. Vòng ngoài (biến i) chạy n − 1 lần. Vòng trong (biến j) duyệt từ đầu dãy, so sánh A[j] với A[j+1] – nếu A[j] > A[j+1] thì đổi chỗ. Sau vòng lặp thứ nhất, phần tử lớn nhất được đẩy về cuối dãy. Sau vòng thứ hai, phần tử lớn thứ hai về đúng chỗ. Cứ tiếp tục cho đến khi dãy sắp xếp xong.
3.2. Minh hoạ vòng lặp đầu tiên
Xét dãy A = [5, 3, 9, 7, 2], theo dõi chi tiết vòng lặp 1 (i = 0):
| Bước | j | So sánh | Thao tác | Trạng thái dãy |
|---|---|---|---|---|
| Ban đầu | – | – | – | 5, 3, 9, 7, 2 |
| Bước 1 | j = 0 | A[0]=5 > A[1]=3 ? Có | Đổi chỗ 5 và 3 | 3, 5, 9, 7, 2 |
| Bước 2 | j = 1 | A[1]=5 > A[2]=9 ? Không | Giữ nguyên | 3, 5, 9, 7, 2 |
| Bước 3 | j = 2 | A[2]=9 > A[3]=7 ? Có | Đổi chỗ 9 và 7 | 3, 5, 7, 9, 2 |
| Bước 4 | j = 3 | A[3]=9 > A[4]=2 ? Có | Đổi chỗ 9 và 2 | 3, 5, 7, 2, 9 |
Kết thúc vòng 1: [3, 5, 7, 2, 9]. Phần tử lớn nhất (9) đã “nổi” về cuối dãy.
Tiếp tục các vòng sau:
| Vòng | Kết quả sau vòng lặp | Phần tử đã “nổi” đúng chỗ |
|---|---|---|
| Vòng 1 | 3, 5, 7, 2, 9 | 9 |
| Vòng 2 | 3, 5, 2, 7, 9 | 7, 9 |
| Vòng 3 | 3, 2, 5, 7, 9 | 5, 7, 9 |
| Vòng 4 | 2, 3, 5, 7, 9 | Toàn bộ |
3.3. Cài đặt bằng Python
def BubbleSort(A):
n = len(A)
for i in range(n - 1):
for j in range(n - 1 - i):
if A[j] > A[j + 1]:
A[j], A[j + 1] = A[j + 1], A[j]
Giải thích từng dòng:
- Dòng 3: Vòng
forngoài chạy n − 1 lần (cần tối đa n − 1 vòng để sắp xếp xong). - Dòng 4: Vòng
fortrong chạyjtừ 0 đếnn − 2 − i. Tại sao lại trừi? Vì sauivòng lặp ngoài,iphần tử lớn nhất đã nằm đúng chỗ ở cuối dãy → không cần so sánh lại. - Dòng 5–6: Nếu hai phần tử cạnh nhau ngược thứ tự (
A[j] > A[j+1]) thì đổi chỗ.
4. So sánh ba thuật toán
| Tiêu chí | Sắp xếp chèn | Sắp xếp chọn | Sắp xếp nổi bọt |
|---|---|---|---|
| Ý tưởng chính | Chèn phần tử vào vị trí đúng trong dãy con đã sắp xếp | Chọn phần tử nhỏ nhất rồi đặt vào đầu phần chưa sắp xếp | Đổi chỗ hai phần tử cạnh nhau sai thứ tự |
| Vòng lặp ngoài | i: 1 → n−1 | i: 0 → n−2 | i: 0 → n−2 |
| Thao tác chính | Dịch chuyển phần tử | Tìm min + đổi chỗ | So sánh + đổi chỗ cặp liền kề |
| Hiệu quả nhất khi | Dãy gần như đã sắp xếp | Dãy bất kỳ | Dãy bất kỳ |
II. Phương pháp giải các dạng bài tập
Dạng 1: Sắp xếp dãy cho trước bằng ba thuật toán
Phương pháp: Áp dụng trực tiếp ba hàm InsertionSort, SelectionSort, BubbleSort đã học. Lưu ý cả ba thuật toán đều sắp xếp tại chỗ (thay đổi trực tiếp trên dãy A), nên cần tạo bản sao nếu muốn giữ dãy gốc.
Bài 1 (Luyện tập SGK). Cho dãy A = [5, 8, 1, 0, 10, 4, 3]. Viết các chương trình sắp xếp dãy A theo thứ tự tăng dần theo ba thuật toán.
Lời giải:
# --- Sắp xếp chèn ---
def InsertionSort(A):
n = len(A)
for i in range(1, n):
value = A[i]
j = i - 1
while j >= 0 and A[j] > value:
A[j + 1] = A[j]
j = j - 1
A[j + 1] = value
# --- Sắp xếp chọn ---
def SelectionSort(A):
n = len(A)
for i in range(n - 1):
iMin = i
for j in range(i + 1, n):
if A[j] < A[iMin]:
iMin = j
A[i], A[iMin] = A[iMin], A[i]
# --- Sắp xếp nổi bọt ---
def BubbleSort(A):
n = len(A)
for i in range(n - 1):
for j in range(n - 1 - i):
if A[j] > A[j + 1]:
A[j], A[j + 1] = A[j + 1], A[j]
# Thử nghiệm
A1 = [5, 8, 1, 0, 10, 4, 3]
A2 = A1.copy()
A3 = A1.copy()
InsertionSort(A1)
print("Sắp xếp chèn:", A1)
SelectionSort(A2)
print("Sắp xếp chọn:", A2)
BubbleSort(A3)
print("Sắp xếp nổi bọt:", A3)
Kết quả cả ba đều cho: [0, 1, 3, 4, 5, 8, 10].
Giải thích: Dùng A1.copy() để tạo bản sao, vì mỗi thuật toán sắp xếp tại chỗ sẽ thay đổi dãy truyền vào. Nếu không copy, sau khi chạy InsertionSort(A1) thì A1 đã thay đổi, ảnh hưởng đến kết quả của hai thuật toán còn lại.
Dạng 2: Nhập dãy từ bàn phím rồi sắp xếp
Phương pháp: Dùng input().split() để nhập dãy số trên một dòng, chuyển đổi kiểu bằng list comprehension, sau đó gọi hàm sắp xếp.
Bài 2 (Luyện tập SGK). Viết chương trình nhập một dãy số từ bàn phím (các số cách nhau bởi dấu cách), sắp xếp rồi in kết quả.
Lời giải:
def BubbleSort(A):
n = len(A)
for i in range(n - 1):
for j in range(n - 1 - i):
if A[j] > A[j + 1]:
A[j], A[j + 1] = A[j + 1], A[j]
line = input("Nhập dãy số cách nhau bởi dấu cách: ")
A = [int(x) for x in line.split()]
print("Dãy ban đầu:", A)
BubbleSort(A)
print("Dãy sau khi sắp xếp:", A)
Giải thích: Bài này có thể dùng bất kỳ thuật toán nào trong ba thuật toán. Ở đây dùng Bubble Sort cho ngắn gọn. Phần nhập dữ liệu dùng kỹ thuật quen thuộc: input() → split() → chuyển int().
Dạng 3: Viết thuật toán sắp xếp giảm dần
Phương pháp: Để đổi từ sắp xếp tăng dần sang giảm dần, chỉ cần đảo chiều điều kiện so sánh. Cụ thể: thay > thành < (hoặc ngược lại) trong các phép so sánh quyết định đổi chỗ/dịch chuyển.
Bài 3 (Vận dụng SGK). Viết lại các thuật toán sắp xếp trong bài theo thứ tự giảm dần.
Lời giải:
# --- Sắp xếp chèn – giảm dần ---
def InsertionSortDesc(A):
n = len(A)
for i in range(1, n):
value = A[i]
j = i - 1
while j >= 0 and A[j] < value: # Đổi > thành <
A[j + 1] = A[j]
j = j - 1
A[j + 1] = value
# --- Sắp xếp chọn – giảm dần ---
def SelectionSortDesc(A):
n = len(A)
for i in range(n - 1):
iMax = i # Tìm phần tử LỚN NHẤT thay vì nhỏ nhất
for j in range(i + 1, n):
if A[j] > A[iMax]: # Đổi < thành >
iMax = j
A[i], A[iMax] = A[iMax], A[i]
# --- Sắp xếp nổi bọt – giảm dần ---
def BubbleSortDesc(A):
n = len(A)
for i in range(n - 1):
for j in range(n - 1 - i):
if A[j] < A[j + 1]: # Đổi > thành <
A[j], A[j + 1] = A[j + 1], A[j]
# Thử nghiệm
A = [5, 8, 1, 0, 10, 4, 3]
BubbleSortDesc(A)
print("Giảm dần:", A)
Kết quả: [10, 8, 5, 4, 3, 1, 0].
Giải thích chi tiết sự thay đổi:
- Sắp xếp chèn: Điều kiện
A[j] > value(dịch phần tử lớn hơn sang phải) → đổi thànhA[j] < value(dịch phần tử nhỏ hơn sang phải). - Sắp xếp chọn: Thay vì tìm phần tử nhỏ nhất (
A[j] < A[iMin]), ta tìm phần tử lớn nhất (A[j] > A[iMax]) rồi đưa về đầu. - Sắp xếp nổi bọt: Điều kiện đổi chỗ
A[j] > A[j+1]→ đổi thànhA[j] < A[j+1]. Phần tử nhỏ nhất sẽ “chìm” về cuối thay vì phần tử lớn nhất “nổi” lên.
Dạng 4: Ý nghĩa thực tế của thuật toán sắp xếp
Bài 4 (Vận dụng SGK). Nêu ý nghĩa thực tế của các thuật toán sắp xếp đã học.
Lời giải:
Các thuật toán sắp xếp có ứng dụng rộng rãi trong thực tế:
- Sắp xếp học sinh theo chiều cao tăng dần để xếp hàng trong giờ thể dục hay chụp ảnh lớp. Có thể dùng thuật toán sắp xếp chọn: mỗi lần tìm bạn thấp nhất trong nhóm chưa xếp và đưa lên đầu hàng.
- Sắp xếp danh sách học sinh theo tên (thứ tự bảng chữ cái) để dễ tra cứu trong sổ điểm, danh sách lớp. Khi có học sinh mới chuyển đến, có thể dùng ý tưởng sắp xếp chèn: tìm đúng vị trí trong danh sách theo bảng chữ cái rồi chèn vào.
- Sắp xếp điểm thi từ cao xuống thấp để xếp hạng, trao giải. Sau khi sắp xếp, việc tìm kiếm (ví dụ tìm ai đạt trên 8 điểm) sẽ nhanh hơn nhờ áp dụng tìm kiếm nhị phân.
- Sắp xếp sản phẩm theo giá trên các trang thương mại điện tử, sắp xếp email theo thời gian, sắp xếp danh bạ điện thoại theo tên,… đều là ứng dụng của bài toán sắp xếp.
Nói chung, sắp xếp giúp dữ liệu trở nên có tổ chức, từ đó việc tìm kiếm, tra cứu và xử lí trở nên nhanh chóng và hiệu quả hơn.
III. Sơ đồ tư duy
┌─ Ý tưởng: chèn A[i] vào đúng vị trí
┌─ Sắp xếp chèn ─┤ trong dãy con đã sắp xếp phía trước
│ (Insertion) ├─ i: 1 → n-1
│ ├─ Dịch phần tử lớn hơn sang phải
│ └─ Đặt A[i] vào ô trống
│
│ ┌─ Ý tưởng: chọn phần tử nhỏ nhất
CÁC ├─ Sắp xếp chọn ──┤ trong phần chưa sắp, đổi chỗ với A[i]
THUẬT │ (Selection) ├─ i: 0 → n-2
TOÁN │ └─ Dùng biến iMin lưu chỉ số min
SẮP │
XẾP │ ┌─ Ý tưởng: đổi chỗ 2 phần tử cạnh nhau
├─ Sắp xếp nổi bọt┤ nếu chưa đúng thứ tự
│ (Bubble) ├─ 2 vòng for lồng nhau
│ ├─ Vòng trong: j chạy n-1-i bước
│ └─ Phần tử lớn "nổi" về cuối sau mỗi vòng
│
└─ Điểm chung ──── Cả 3 đều sắp xếp tại chỗ trên dãy A
Đổi sang giảm dần: chỉ cần đảo chiều so sánh

Thầy Phạm Thành Danh
(Người kiểm duyệt, ra đề)
Chức vụ: Trưởng ban biên soạn môn Tin Học THPT
Trình độ: Cử nhân Sư phạm Tin học, Chứng chỉ hạng II, Chứng chỉ Tin học, Ngoại ngữ B1
Kinh nghiệm: 8+ năm kinh nghiệm tại Trường THPT Thuận Hóa

