Mục lục bài họcĐang ở d04-b3
← IB Computer Science
0/32 bài đã học xong
Chương 4 · Computational Thinking, Problem-Solving and Programming · Bài 3/4 của chương · bài 15/32 của IB Computer Science

Two-Dimensional Arrays, Nested Loops and String Processing

Mảng hai chiều, vòng lặp lồng nhau và xử lý chuỗi
← Mục lục bài học
Lý thuyết · English

Two-dimensional arrays. A table of marks — students in rows, tests in columns — is stored as an array of arrays. In IB pseudocode MARKS[R][C] names the element in row R and column C, and both indices start at 0, so a 3 × 4 table has rows 0–2 and columns 0–3. The row index always comes first; MARKS[1][2] is row 1, column 2. The most common exam error is running a loop to 3 instead of 2 and stepping outside the array. Keep the dimensions as named constants (ROWS, COLS) and loop from 0 to ROWS − 1.

Nested loops. Visiting every element needs a loop inside a loop. The outer loop chooses a row, the inner loop walks along it; the inner loop's counter restarts every time the outer loop advances. For 3 rows and 4 columns the inner body runs 3 × 4 = 12 times, and when both dimensions grow to n the work grows as n², which is why nested loops are the usual source of O(n²) algorithms. Which loop is outside determines what you can accumulate: rows outside gives a total per student, columns outside gives a total per test. The classic bug is placing TOTAL = 0 before both loops instead of inside the outer loop, so that totals accumulate across every row. Other nested-loop patterns to recognise: finding the largest element and its position (two variables updated together), counting how many elements satisfy a condition, and checking whether every row sums to the same value.

Strings as sequences. A string is a sequence of characters that can be indexed like an array. The operations examiners expect: length; extracting one character; joining (concatenation); comparing two strings, which works character by character using the character codes, so uppercase letters sort before lowercase and "10" sorts before "9"; converting between a character and its code; and searching for a substring. Standard algorithms built from these: counting vowels (a loop and a condition), reversing a string (build a new string from the last character backwards), checking a palindrome (compare position I with position LENGTH − 1 − I until they meet), and validating a password (loop once, set flags for length, digit, uppercase, then decide). Every string algorithm is a loop from 0 to LENGTH − 1 plus a condition, and the trace table has one row per character.

Collections versus arrays. The IB collection has no index: you reset it, then loop with hasNext and getNext until the end. It grows as items are added, which arrays cannot, but you cannot jump to the fifth item directly. Choose an array when position matters or when the size is known; choose a collection when the number of items is unknown and you only ever process them in order.

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

Mảng hai chiều. Một bảng điểm — học sinh theo hàng, bài kiểm tra theo cột — được lưu như một mảng của các mảng. Trong mã giả IB, MARKS[R][C] gọi tên phần tử ở hàng R cột C, và cả hai chỉ số bắt đầu từ 0, nên bảng 3 × 4 có hàng 0–2 và cột 0–3. Chỉ số hàng luôn đứng trước; MARKS[1][2] là hàng 1, cột 2. Lỗi thi phổ biến nhất là cho vòng lặp chạy tới 3 thay vì 2 và bước ra ngoài mảng. Hãy giữ kích thước dưới dạng hằng có tên (ROWS, COLS) và lặp từ 0 tới ROWS − 1.

Vòng lặp lồng nhau. Thăm mọi phần tử cần một vòng lặp bên trong một vòng lặp. Vòng ngoài chọn một hàng, vòng trong đi dọc hàng đó; biến đếm của vòng trong khởi động lại mỗi khi vòng ngoài tiến lên. Với 3 hàng và 4 cột, thân vòng trong chạy 3 × 4 = 12 lần, và khi cả hai chiều tăng tới n thì khối lượng tăng theo n², đó là lý do vòng lồng là nguồn thường gặp của thuật toán O(n²). Vòng nào ở ngoài quyết định bạn tích luỹ được gì: hàng ở ngoài cho tổng mỗi học sinh, cột ở ngoài cho tổng mỗi bài. Lỗi kinh điển là đặt TOTAL = 0 trước cả hai vòng thay vì bên trong vòng ngoài, khiến tổng cộng dồn qua mọi hàng. Các mẫu vòng lồng khác cần nhận ra: tìm phần tử lớn nhất và vị trí của nó (hai biến cập nhật cùng lúc), đếm số phần tử thoả điều kiện, và kiểm xem mọi hàng có cùng tổng không.

Chuỗi là dãy. Chuỗi là một dãy ký tự có thể đánh chỉ số như mảng. Các phép giám khảo mong đợi: độ dài; lấy một ký tự; nối (ghép chuỗi); so sánh hai chuỗi, làm từng ký tự theo mã ký tự, nên chữ hoa xếp trước chữ thường và "10" xếp trước "9"; chuyển giữa ký tự và mã của nó; và tìm chuỗi con. Các thuật toán chuẩn xây từ đó: đếm nguyên âm (một vòng và một điều kiện), đảo chuỗi (xây chuỗi mới từ ký tự cuối lùi về), kiểm đối xứng (so vị trí I với vị trí LENGTH − 1 − I cho tới khi gặp nhau), và kiểm mật khẩu (lặp một lần, đặt cờ cho độ dài, chữ số, chữ hoa, rồi quyết định). Mọi thuật toán chuỗi là một vòng từ 0 tới LENGTH − 1 cộng một điều kiện, và bảng lần vết có một dòng cho mỗi ký tự.

Collection và mảng. Collection của IB không có chỉ số: bạn đặt lại về đầu, rồi lặp với hasNext và getNext tới khi hết. Nó lớn dần khi thêm phần tử, điều mảng không làm được, nhưng bạn không nhảy thẳng tới phần tử thứ năm được. Chọn mảng khi vị trí quan trọng hoặc kích thước đã biết; chọn collection khi số phần tử chưa biết và bạn chỉ xử lý chúng theo thứ tự.

MẢNG HAI CHIỀU: HÀNG TRƯỚC, CỘT SAU — VÀ AI LÀ VÒNG NGOÀI MARKS[hàng][cột] — 3 học sinh × 4 bài [0] [1] [2] [3] [0] [1] [2] 72 85 64 90 55 61 78 70 93 88 95 82 MARKS[1][2] = 78: hàng 1 trước, cột 2 sau chỉ số bắt đầu từ 0 · hàng cuối là [2], không phải [3] HAI VÒNG LỒNG NHAU Tổng mỗi HỌC SINH (theo hàng): loop R from 0 to 2 TOTAL = 0 loop C from 0 to 3 TOTAL = TOTAL + MARKS[R][C] end loop output TOTAL end loop TOTAL = 0 phải nằm TRONG vòng ngoài, TRƯỚC vòng trong — sai chỗ là cộng dồn cả lớp tổng mỗi BÀI: đảo hai vòng, C ngoài R trong 3 × 4 = 12 lần thân vòng trong — hai vòng lồng là O(n²) khi cả hai đều tới n vòng ngoài chạy 3 lần · mỗi lần vòng trong chạy 4 lần · biến đếm vòng trong được ĐẶT LẠI mỗi lần vòng ngoài lặp bảng lần vết cho vòng lồng: cột R, cột C, cột TOTAL, cột output — 12 dòng, không được viết tắt lỗi thi phổ biến nhất: chạy tới 3 thay vì 2, tới 4 thay vì 3 — vượt biên mảng
Hình bên trái là một mảng hai chiều MARKS với 3 hàng cho 3 học sinh và 4 cột cho 4 bài kiểm tra, chỉ số bắt đầu từ 0 nên hàng cuối là [2] và cột cuối là [3]. Quy ước phải thuộc: chỉ số hàng đứng trước, chỉ số cột đứng sau, nên MARKS[1][2] là ô hàng 1 cột 2 có giá trị 78, không phải 61. Hộp bên phải là đoạn mã giả tính tổng điểm của mỗi học sinh bằng hai vòng lặp lồng nhau: vòng ngoài đi qua từng hàng, vòng trong đi qua từng cột của hàng đó. Dòng đỏ chỉ ra lỗi phổ biến nhất ở dạng bài này: câu lệnh TOTAL = 0 phải nằm bên trong vòng ngoài và trước vòng trong, để mỗi học sinh bắt đầu từ 0; đặt nó trước cả hai vòng thì kết quả là tổng cộng dồn của cả lớp. Muốn tổng của mỗi bài thay vì mỗi học sinh thì đảo hai vòng, cột ở ngoài và hàng ở trong. Hộp dưới cùng nêu các con số của việc lần vết: vòng ngoài chạy 3 lần, mỗi lần vòng trong chạy 4 lần, tổng 12 lần thân vòng trong, và biến đếm của vòng trong được đặt lại mỗi khi vòng ngoài lặp. Bảng lần vết cho vòng lồng có cột R, cột C, cột TOTAL và cột output với đủ 12 dòng. Lỗi thi phổ biến nhất là cho vòng chạy tới 3 thay vì 2 hoặc tới 4 thay vì 3 và vượt biên mảng.
Ví dụ — Ví dụ 1 — viết và lần vết thuật toán tìm học sinh có điểm trung bình cao nhất

MARKS là mảng 3 × 4 như trong hình (hàng 0: 72, 85, 64, 90; hàng 1: 55, 61, 78, 70; hàng 2: 93, 88, 95, 82). Viết mã giả tìm chỉ số hàng có tổng cao nhất, rồi lần vết.

Giải.

Mã giả.

BEST = -1
BESTTOTAL = -1
loop R from 0 to 2
  TOTAL = 0
  loop C from 0 to 3
    TOTAL = TOTAL + MARKS[R][C]
  end loop
  if TOTAL > BESTTOTAL then
    BESTTOTAL = TOTAL
    BEST = R
  end if
end loop
output BEST

Ba quyết định thiết kế cần giải thích. Một, TOTAL = 0 nằm trong vòng ngoài để mỗi hàng bắt đầu lại. Hai, BESTTOTAL khởi tạo là −1 (nhỏ hơn mọi tổng có thể) để hàng đầu tiên chắc chắn được nhận; khởi tạo bằng 0 cũng được ở đây vì điểm không âm, nhưng −1 là thói quen an toàn. Ba, cập nhật BEST và BESTTOTAL cùng nhau — quên một trong hai là lỗi kinh điển.

Lần vết. R = 0: TOTAL đi 0 → 72 → 157 → 221 → 311; 311 lớn hơn −1 nên BESTTOTAL = 311, BEST = 0. R = 1: TOTAL 0 → 55 → 116 → 194 → 264; 264 không lớn hơn 311, không đổi. R = 2: TOTAL 0 → 93 → 181 → 276 → 358; 358 lớn hơn 311 nên BESTTOTAL = 358, BEST = 2. Output 2. Bảng lần vết đầy đủ có 12 dòng cho vòng trong; trong phòng thi hãy viết đủ, vì điểm nằm ở bảng chứ không ở đáp số.

Biến thể hay hỏi. Tổng cao nhất và trung bình cao nhất cho cùng một hàng vì mọi hàng có cùng số cột — bài làm nhận ra điều này tiết kiệm được một phép chia và được cộng điểm hiểu bài.

Ví dụ — Ví dụ 2 — kiểm tra đối xứng và đếm từ trong một chuỗi

(a) Viết thuật toán kiểm một chuỗi S có phải đối xứng (đọc xuôi ngược như nhau) không, bỏ qua hoa thường. (b) Viết thuật toán đếm số từ trong một câu, các từ cách nhau bởi đúng một dấu cách. Nêu ca kiểm thử biên cho mỗi bài.

Giải.

(a) Đối xứng.

S = toLower(S)
N = length(S)
I = 0
OK = true
loop while I < N div 2 and OK
  if S[I] ≠ S[N - 1 - I] then OK = false
  I = I + 1
end loop
output OK

Điểm cần giải thích: chỉ cần so tới giữa chuỗi (N div 2), vì nửa sau là ảnh của nửa trước; ký tự đối xứng của vị trí I là N − 1 − I, không phải N − I — đây là lỗi thiếu một hay gặp nhất; và thoát sớm khi OK sai để không lặp vô ích. Ca biên: chuỗi rỗng (N = 0, không lặp, OK true — cần quyết định đó có đúng ý không), chuỗi một ký tự, chuỗi độ dài chẵn như "abba" và lẻ như "aba", và chuỗi khác nhau ở đúng ký tự giữa của độ dài chẵn.

(b) Đếm từ.

N = length(S)
if N = 0 then output 0
else
  COUNT = 1
  loop I from 0 to N - 1
    if S[I] = " " then COUNT = COUNT + 1
  end loop
  output COUNT
end if

Số từ bằng số dấu cách cộng một — với giả thiết đúng một dấu cách giữa các từ và không có dấu cách đầu cuối. Đó chính là tiền điều kiện, và bài phải nói rõ. Ca biên: chuỗi rỗng (tách riêng vì công thức cho 1 thay vì 0), một từ không có dấu cách, và các ca vi phạm tiền điều kiện như hai dấu cách liền nhau hoặc dấu cách ở cuối — thuật toán cho kết quả sai ở đó, và câu trả lời tốt nêu cách chắc hơn: chỉ đếm khi gặp ký tự không phải dấu cách mà ký tự trước nó là dấu cách hoặc là đầu chuỗi.

Bẫy hay mất điểm — Bẫy 1 — đặt TOTAL = 0 trước cả hai vòng. Tổng sẽ cộng dồn qua mọi hàng; khởi tạo phải nằm trong vòng ngoài, trước vòng trong.
Bẫy 2 — vượt biên mảng. Chỉ số từ 0 nên hàng cuối của 3 hàng là 2; ký tự đối xứng của I là N − 1 − I.
Bẫy 3 — cập nhật giá trị lớn nhất mà quên vị trí. BEST và BESTTOTAL phải đổi cùng nhau trong cùng một khối if.
Phải nhớ — Chốt bài 3. Bốn thứ mang vào phòng thi. Một, hàng trước cột sau, chỉ số từ 0, lặp tới ROWS − 1. Hai, vòng ngoài quyết định tích luỹ theo gì, và khởi tạo nằm trong vòng ngoài. Ba, chuỗi là mảng ký tự: mọi thuật toán chuỗi là vòng 0 tới LENGTH − 1 cộng điều kiện. Bốn, mảng khi cần vị trí, collection khi số phần tử chưa biết.

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

Bài tập của chương Computational Thinking, Problem-Solving and Programming gồm 14 câu trắc nghiệm và 5 đề tự luận. Đáp án hiện ngay khi chọn, miễn phí.

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