(ĐÁP ÁN THAM KHẢO CỦA ĐỀ THI CTDL> HK2 2024-2025)
CÂU HỎI ĐIỀN KHUYẾT (ĐỀ 1)
Câu 1 (0.5 điểm) (CLO1.1)
Cho danh sách liên kết chứa các khóa số nguyên có thứ tự như Hình 1 Khóa 12 được
tìm thấy nhanh nhất với _5 bước (lần so sánh giá trị khóa)
Hình 1 Danh sách liên kết đơn chứa các khóa số nguyên có thứ tự
Câu 2 (0.5 điểm) (CLO1.2)
Hàm A bên dưới cài đặt thuật toán (sắp xếp) chèn trực tiếp (insertion sort)
void A(int G[], int p) {
int i = 1;
int j, x;
while (i != p) {
x = G[i];
j = i - 1;
while (j >= 0 && G[j] > x) {
G[j+1] = G[j];
j ;
}
G[j+1] = x;
i++;
}
}
Trang 2Câu 3 (0.5 điểm) (CLO1.3)
Cho cây nhị phân T 1 như Hình 2 Kết quả duyệt LRN cho cây con bên phải của T 1 là
16 17 15 18 28 29 26 21
Nếu kết quả duyệt 6 7 5 10 9 12 11 8 16 17 15 18 28 29 26 21 13
vẫn chấm 0.5đ vì sinh viên đã bị mất thời gian
Hình 2 Cây nhị phân T 1
Câu 4 (0.5 điểm) (CLO1.4)
Cho cây nhị phân tìm kiếm T 2 như Hình 3
Hình 3 Cây nhị phân T 2
Hình ảnh của cây T 2 sau khi thêm các khóa 22, 11 và 33 là:
Nếu đúng 1 hoặc 2 nút thì được 0.25đ
Trang 3Câu 5 (0.5 điểm) (CLO1.5)
Cho B-Tree bậc 5, T 3 , như Hình 4
Hình 4 T 3 , B-Tree bậc 5
Hình vẽ của cây T 3 sau khi thêm khóa 40 là:
Nếu chỉ đúng gốc có khóa 40 thì được 0.25đ
Câu 6 (0.5 điểm) (CLO1.6)
Cho B-Tree bậc 5, T 4 , như Hình 5
Hình 5 T 4 , B-Tree bậc 5
Hình của cây T 4 sau khi xóa khóa 44 là:
Nếu chỉ đúng gốc có khóa 10,46,50,70 thì được 0.25đ
Đề bài bên dưới được sử dụng cho Câu 7, Câu 8 và Câu 9 (Lưu ý, các câu này độc lập
với nhau)
Cho bảng băm địa chỉ mở HT 1 như Hình 6 HT 1 có kích thước M=7, hàm băm f và hàm băm lại f’ lần lượt là:
𝑓(𝑘𝑒𝑦) = 𝑘𝑒𝑦 % 𝑀
𝑓′(𝑘𝑒𝑦, 𝑖) = [𝑓(𝑘𝑒𝑦) + 𝑖2] % 𝑀
Trong đó, phép toán % là phép toán lấy phần dư của phép chia nguyên
Trang 4Hình 6 Bảng băm HT 1
Câu 7 (0.5 điểm) (CLO1.7)
Sau khi xóa khóa 9, việc tìm khóa 9 kết thúc sau _2_(chấm đúng cho 3) bước thăm dò
Câu 8 (0.5 điểm) (CLO1.8)
Việc tìm khóa 8 trên HT 1 kết thúc sau 6_(chấm đúng cho 7)_ bước thăm dò Câu 9 (0.5 điểm) (CLO1.9)
Vị trí trên HT 1 khi thêm khóa 33 là _6 _
Câu 10 (0.75 điểm) (CLO1.10)
Cho đồ thị vô hướng G 1 như Hình 7
Hình 7 Đồ thị vô hướng G 1
Khi tìm đường đi ngắn nhất từ đỉnh A đến đỉnh G trên đồ thị G 1, độ dài đường đi từ
đỉnh A đến đỉnh D được cập nhật 4_(Có sinh viên nhầm lần đưa vào queue đầu tiên
là lần khởi tạo nên ghi 3, trường hợp này được 0.75đ) _ lần (không tính lần khởi
tạo giá trị)
CÂU HỎI ĐIỀN KHUYẾT (Đề 2)
Câu 1 (0.5 điểm) (CLO1.1)
Cho mảng chứa các khóa số nguyên có thứ tự như Hình 1 Khóa 12 được tìm thấy nhanh
nhất với 2_(Có sinh viên nhầm số phép so sánh nên ghi 3, trường hợp này vẫn chấm
đúng) bước (lần so sánh giá trị khóa)
Hình 1 Mảng chứa các khóa số nguyên có thứ tự
Câu 2 (0.5 điểm) (CLO1.2)
Hàm A bên dưới cài đặt thuật toán _(sắp xếp) chọn trực tiếp (selection sort) _ void A(int G[], int p) {
int i = 0;
int j, k;
while (i != p) {
Trang 5j = i + 1;
k = i;
while (j != p) {
if (G[k] > G[j])
k = j;
j++;
}
if (k != i) {
j = G[k];
G[k] = G[i];
G[i] = j;
}
i++;
}
}
Câu 3 (0.5 điểm) (CLO1.3)
Cho cây nhị phân T 1 như Hình 2 Kết quả duyệt LRN cho cây con bên trái của T 1 là
6 7 5 10 9 12 11 8
Nếu kết quả duyệt 6 7 5 10 9 12 11 8 16 17 15 18 28 29 26 21 13
vẫn chấm 0.5đ vì sinh viên đã bị mất thời gian
Hình 2 Cây nhị phân T 1
Câu 4 (0.5 điểm) (CLO1.4)
Cho cây nhị phân tìm kiếm T 2 như Hình 3
Trang 6Hình 3 Cây nhị phân T 2
Hình ảnh của cây T 2 sau khi thêm các khóa 22, 11 và 44 là:
Nếu đúng 1 hoặc 2 nút thì được 0.25đ
Câu 5 (0.5 điểm) (CLO1.5)
Cho B-Tree bậc 5, T 3 , như Hình 4
Hình 4 T 3 , B-Tree bậc 5
Hình vẽ của cây T 3 sau khi thêm khóa 38 là:
Nếu chỉ đúng gốc có khóa 39 thì được 0.25đ
Câu 6 (0.5 điểm) (CLO1.6)
Cho B-Tree bậc 5, T 4 , như Hình 5
Trang 7Hình 5 T 4 , B-Tree bậc 5
Hình của cây T 4 sau khi xóa khóa 47 là:
Nếu chỉ đúng gốc có các khóa 10,30,46,70 thì được 0.25đ
Đề bài bên dưới được sử dụng cho Câu 7, Câu 8 và Câu 9 (Lưu ý, các câu này độc lập
với nhau)
Cho bảng băm địa chỉ mở HT 1 như Hình 6 HT 1 có kích thước M=7, hàm băm f và hàm băm lại f’ lần lượt là:
𝑓(𝑘𝑒𝑦) = 𝑘𝑒𝑦 % 𝑀
𝑓′(𝑘𝑒𝑦, 𝑖) = [𝑓(𝑘𝑒𝑦) + 𝑖2] % 𝑀
Trong đó, phép toán % là phép toán lấy phần dư của phép chia nguyên
Hình 6 Bảng băm HT 1
Câu 7 (0.5 điểm) (CLO1.7)
Sau khi xóa khóa 9, việc tìm khóa 9 kết thúc sau _2_(chấm đúng cho 3) bước thăm dò Câu 8 (0.5 điểm) (CLO1.8)
Việc tìm khóa 8 trên HT 1 kết thúc sau 6_(chấm đúng cho 7) bước thăm dò Câu 9 (0.5 điểm) (CLO1.9)
Vị trí trên HT 1 khi thêm khóa 31 là _4 _
Câu 10 (0.75 điểm) (CLO1.10)
Cho đồ thị vô hướng G 1 như Hình 7
Trang 8Hình 7 Đồ thị vô hướng G 1
Khi tìm đường đi ngắn nhất từ đỉnh A đến đỉnh D trên đồ thị G 1, độ dài đường đi từ
đỉnh A đến đỉnh D được cập nhật _5_(Có sinh viên nhầm lần đưa vào queue đầu tiên
là lần khởi tạo nên ghi 4, trường hợp này được 0.75đ) lần (không tính lần khởi tạo giá
trị)
CÂU HỎI TỰ LUẬN
Giả sử các đoạn chương trình trong phần này đều có các chỉ thị #include, đảm bảo các kiểu
dữ liệu và các hàm được C++ hỗ trợ đều sẵn sàng để sử dụng
Câu 11 (2 điểm) (CLO2.1, CLO2.2)
Giả sử người sử dụng Facebook được gán cho một số nguyên từ 0 đến N-1 Mối quan
hệ bạn bè của người sử dụng được biểu diễn bằng một đồ thị đơn, vô hướng, có N đỉnh,
và được biểu diễn theo kiểu dữ liệu Banbe như sau:
struct Banbe {
int N;
bool Ban[MAX][MAX];
};
Trong đó:
- N là số người sử dụng Facebook;
- Ban[i][j]=true cho biết người sử dụng i là bạn của người sử dụng j;
- Ban[i][j]=false cho biết người sử dụng i không phải bạn của người sử dụng j
- Ban[i][i] luôn có giá trị false
1) Cài đặt hàm NguoiCodon để kết xuất ra màn hình những người sử dụng không có
bạn trên Facebook (1 điểm) (CLO2.1):
Vòng lặp duyệt tất cả người sử dụng 0.25đ
Vòng lặp để kiểm tra điều kiện người cô đơn: 0.25đ
Xác định đúng điều kiện người cô đơn: 0.25đ
In người đúng điều kiện: 0.25đ
void NguoiCodon(Banbe Facebook) {
for (int i=0; i < Facebook.N; i++) {
Trang 9bool ktra = true;
for (int j=0; j < Facebook.N; j++) {
if (Facebook.Ban[i][j]) { ktra = false;
break;
} }
if (ktra) cout << i << endl;
}
}
2) Cài đặt hàm DexuatKetBan để in ra những người k có thể kết bạn với người sử dụng user trên Facebook, chỉ in giá trị k một lần Biết rằng, người k là bạn t, t là bạn của user nhưng k không phải là bạn user (1 điểm) (CLO2.2)
Ví dụ: 1 là bạn của 2, 2 là bạn của 3, 3 không phải là bạn của 1, thì 3 được đề xuất
để kết bạn với 1
Vòng lặp duyệt tất cả bạn của người sử dụng: 0.25đ
Vòng lặp duyệt tất cả người cần đề xuất: 0.25đ
Kiểm tra trùng: 0.25đ
In những người được đề xuất: 0.25đ
void DexuatKetBan(Banbe Facebook, int user) {
unordered_set<int> dexuat;
for (int i = 0; i < Facebook.N; i++)
if (Facebook.Ban[user][i])
for (int j=0; j < Facebook.N; j++) {
if (!Facebook.Ban[i][j]) continue;
if (j == user) continue;
if (Facebook.Ban[j][user]) continue;
dexuat.insert(j);
} for (auto p = dexuat.begin(); p != dexuat.end(); p++)
cout << *p << endl;
}
Câu 12 (1 điểm) (CLO2.3)
Trang 10Giả sử hàm xemTrang(url) sẽ mở trang web ở địa chỉ url lên màn hình để xem thông
tin Hãy hoàn thành các hàm bên dưới bằng cách chỉ ra kiểu dữ liệu, lời gọi hàm hay biểu thức tính toán phù hợp Các hàm gồm:
- duyet(history, url, old) để mở trang web ở địa chỉ url lên màn hình và ghi địa chỉ trang web old đã duyệt trước đó vào lịch sử duyệt web history (0.5 điểm) (CLO2.3)
- quaylai(history) để mở trang web vừa duyệt trước đó lên màn hình dựa vào lịch sử duyệt web history, tương tự như chức năng của nút [Back] trên trình duyệt web (0.5
điểm) (CLO2.3)
Dùng thao tác với các kiểu dữ liệu sau là tương đương:
- push, top + pop với stack
- push_back, truy xuất phần tử cuối + pop_back với vector
- push_front, front + pop_front với list
- push_back, back + pop_back với list
Hàm duyệt:
Kiểu dữ liệu 0.25đ
Đưa biến old vào history 0.25đ
Nếu có sử dụng vòng lặp thì không tính điểm này
void duyet(stack<string> &history, string url, string old) {
xemTrang(url);
history.push(old);
}
Hàm quay lại:
Kiểu dữ liệu trùng với kiểu dữ liệu của hàm duyet và gọi hàm xemTrang 0.25đ Gọi hàm pop 0.25đ
Nếu có sử dụng vòng lặp thì không tính điểm này
void quaylai(stack<string> &history) {
xemTrang(history.top());
history.pop();
}
Câu 13 (1 điểm) (CLO2.4)
Cho kiểu dữ liệu TREE, để biểu diễn cây nhị phân tìm kiếm, được khai báo như bên dưới Hãy cài đặt hàm chonKhoaLoaiTru để in ra các khóa k trên cây nhị phân tìm kiếm
Trang 11t, sao cho, với sub là nút gốc của một cây con của t, sub có khóa m, thì k > m, và k không
là khóa của bất kỳ nút hậu duệ nào của sub Yêu cầu dùng queue thay cho hàm đệ quy
Ví dụ: với cây nhị phân tìm kiếm t là cây T 2 ở Hình 3, sub là nút có khóa 30 Kết quả in
ra màn hình là: 35 49
struct TNode {
int key;
TNode *left, *right;
};
typedef TNode *TREE;
Có hai cách làm:
1) Bỏ cây con sub khi in khóa
2) Kiểm tra khóa trong cây con sub khi in khóa
Cách 1:
- Vòng lặp duyệt các nút: 0.25đ
- Bổ sung các nút vào queue theo tính chất BST: 0.25đ
Trường hợp không sử dụng tính chất BST thì không được điểm này
- Bỏ cây con sub 0.25đ
- In nút: 0.25đ
vector<int> ChonKhoaLoaiTru(TREE t, TREE sub) {
queue<TREE> q;
q.push(t);
while (!q.empty()) {
TREE p = q.front(); q.pop();
if (p == sub) continue;
if (p->key > sub->key) {
cout << p->key << ‘ ‘;
if (p->left != null) q.push(p->left);
if (p->right != null) q.push(p->right);
} else
if (p->right != null) q.push(p->right);
}
}
Cách 2:
- Vòng lặp duyệt các nút: 0.25đ
- Bổ sung các nút vào queue theo tính chất BST: 0.25đ
Trường hợp không sử dụng tính chất BST thì không được điểm này
- Kiểm tra nút có là hậu duệ của sub thì bỏ qua 0.25đ
Nếu kết xuất các nút hậu duệ của sub ra mảng để kiểm tra thì không tính điểm này
- In nút: 0.25đ
Trang 12vector<int> ChonKhoaLoaiTru(TREE t, TREE sub) {
queue<TREE> q;
q.push(t);
while (!q.empty()) {
TREE p = q.front(); q.pop();
bool kt = false;
TREE tmp = sub;
while (tmp != NULL) {
if (tmp == p) { kt = true; break; }
if (tmp->key > p->key) tmp = tmp->left;
else tmp = tmp->right;
}
if (kt) continue;
if (p->key > sub->key) {
cout << p->key << ‘ ‘;
if (p->left != null) q.push(p->left);
if (p->right != null) q.push(p->right);
} else
if (p->right != null) q.push(p->right);
}
}
Câu 14 (0.75 điểm) (CLO2.5)
Cho một dãy số A có n=2k-1 số tự nhiên phân biệt nhau (kN*) Hãy trình bày ý tưởng
và giải thuật để tạo cây nhị phân tìm kiếm từ dãy số A, sao cho tất cả nút lá cùng nằm trên một mức
Ví dụ: A = {1, 5, 2, 7, 4, 3, 6} có n=23-1=7 Cây nhị phân tìm kiếm cần tạo như Hình 8
Hình 8 Cây nhị phân tìm kiếm có các nút lá cùng mức
Ý tưởng (0.5 điểm) (CLO2.5)
Gốc của cây có khóa là trung vị của tất cả các khóa trên cây 0.25đ Chỉ cần nhắc đến trung vị, không cần đúng nguyên văn đều được 0.25đ
Trung vị ở chính giữa mảng có thứ tự (đã sắp xếp) 0.25đ Chỉ cần nhắc đến sắp xếp, không cần đúng nguyên văn đều được 0.25đ
Giải thuật (0.25 điểm) (CLO2.5)
Quan trọng ở 2 điểm:
- Sắp xếp mảng A
Trang 13- Lấy trung vị thêm vào cây nhị phân tìm kiếm
Không cần trình bày hàm thêm nút vào cây
Thiếu một trong hai điểm quan trọng trên sẽ không tính điểm
Thuật toán tham khảo:
Đầu vào: mảng A có n phần tử
Đầu ra: cây NPTK T
1 Sort(A)
2 CreateBST(T, A, 0, n-1)
Hàm CreateBST(T, A, L, R):
1 M = (L+R)/2
2 AddNode(T, A[M])
3 If L <= M-1 then CreateBST(T, A, L, M-1)
4 If R >= M+1 then CreateBST(T, A, M+1, R)