Danh sách câu hỏi của đề

Câu hỏi: CSD201 Cấu trúc dữ liệu và giải thuật – Bộ ôn tập cuối kỳ số 3

50 câu trắc nghiệm kèm lời giải của môn CSD201 - Cấu trúc dữ liệu và giải thuật, xếp đúng thứ tự trong đề.

Danh sách câu hỏi

20/50 câuCòn 30
ANode f = head; while(f.next != null) f = f.next; f.next = p.next;
BNode f = head; while(f != p) f = f.next; f.next = p.next;
CNode f = head; while(f.next != p) f = f.next; f.next = p.next;
DNode f = head; while(f != null) f = f.next; f.next = p.next;
Lời giải

Đáp án đúng: "Node f = head; while(f.next != p) f = f.next; f.next = p.next;". Danh sách liên kết đơn không có liên kết lùi, nên muốn tháo p ta buộc phải dò từ head để tìm nút tiền nhiệm; điều kiện f.next khác p dừng đúng lúc f là nút đứng ngay trước p, và f.next bằng p.next nối tiền nhiệm sang hậu nhiệm, đưa p ra khỏi chuỗi. Vì vậy "Node f = head; while(f.next != null) f = f.next; f.next = p.next;" sai vì vòng lặp chạy tới nút cuối rồi cho nút cuối trỏ về một nút nằm phía trước nó, tạo vòng tròn trong danh sách mà p vẫn còn nguyên. "Node f = head; while(f != p) f = f.next; f.next = p.next;" sai vì vòng lặp dừng khi f chính là p, nên f.next bằng p.next là gán cho chính nó, không liên kết nào thay đổi. "Node f = head; while(f != null) f = f.next; f.next = p.next;" sai vì vòng lặp chỉ kết thúc khi f đã bằng null, nên lệnh f.next ngay sau đó ném NullPointerException.

Mở trang câu hỏi này →
AO(n^2)
BO(n)
CO(log n)
DO(1)
Lời giải
Đáp án đúng: "O(n)". Danh sách liên kết đơn chỉ cho đi từ nút đầu theo con trỏ next và không tính được địa chỉ của phần tử ở giữa, nên phép tìm phải so sánh lần lượt; trường hợp xấu nhất là khoá nằm ở nút cuối hoặc không có trong danh sách, khi đó phải thăm đủ n nút. Con số "O(log n)" đòi mỗi bước loại được một nửa dữ liệu như tìm nhị phân, nhưng muốn nhảy tới phần tử giữa thì phải truy cập ngẫu nhiên, điều danh sách liên kết không có. Con số "O(1)" chỉ đúng khi khoá tình cờ nằm ngay nút đầu, đó là trường hợp tốt nhất chứ không phải xấu nhất. Con số "O(n^2)" ứng với hai vòng lặp lồng nhau, trong khi phép tìm chỉ đi một lượt qua danh sách.
Mở trang câu hỏi này →
Đề bài
Node p1,p2; p1 = p.next;
 p2 = p1.next;
 p.next = p2;
if(p2!=null) p2.prev=p;
AIt does not make any change on the list.
BIt deletes the node before p.
CIt deletes the node p.
DIt deletes the node after p.
Lời giải
Đáp án đúng: "It deletes the node after p.". Đoạn mã lấy p1 = p.next là nút liền sau p, rồi p2 = p1.next là nút sau nữa; lệnh p.next = p2 cho p trỏ vượt qua p1, và p2.prev = p vá chiều ngược lại khi p2 còn tồn tại. Sau hai phép gán đó không còn liên kết nào chỉ vào p1, nên nút liền sau p bị loại; phép kiểm tra p2 != null chỉ để tránh truy cập prev của null trong trường hợp p1 là nút cuối. Phương án "It deletes the node p." sai vì p vẫn nằm trong danh sách và còn là nơi phát ra liên kết mới. Phương án "It deletes the node before p." sai vì mã không đọc cũng không gán p.prev, nên phía trước p không hề thay đổi. Phương án "It does not make any change on the list." sai vì p.next bị trỏ sang nút cách hai bước, làm danh sách ngắn đi đúng một nút.
Mở trang câu hỏi này →
Đề bài
Node f = head;
while(f.next != p) f = f.next;
f.next = p.next;
AIt deletes the node p.
BIt deletes the node before p.
CIt deletes the node after p.
DIt does not make any change on the list.
Lời giải
Đáp án đúng: "It deletes the node p.". Danh sách liên kết đơn không lùi được, nên vòng lặp while(f.next != p) f = f.next chạy từ head để dừng đúng ở nút đứng liền trước p. Lệnh f.next = p.next khiến nút đó trỏ vượt qua p sang nút kế tiếp, vậy p không còn ai trỏ tới và biến mất khỏi đường đi từ head, đúng nghĩa xoá p. "It deletes the node before p." sai vì nút trước p chính là f, nó vẫn nằm trong danh sách và còn là nút giữ liên kết mới. "It deletes the node after p." sai vì nút sau p vẫn được f.next trỏ tới nên vẫn truy cập được từ head; muốn xoá nó phải viết p.next = p.next.next. "It does not make any change on the list." sai vì liên kết f.next đã bị ghi lại, danh sách ngắn đi một nút.
Mở trang câu hỏi này →
Asorted linear array
Bsorted doubly linked list
CBinary search tree
Lời giải
Đáp án đúng: "sorted doubly linked list". Tìm nhị phân cần nhảy thẳng tới phần tử giữa của đoạn đang xét với chi phí hằng số, vì mỗi lần so sánh phải cắt đôi vùng tìm kiếm. Danh sách liên kết kép dù đã có thứ tự vẫn chỉ cho đi từng bước qua liên kết tiến và liên kết lùi, muốn tới giữa đoạn phải lần lượt qua từng nút, nên phép chia đôi mất hết cái lợi của nó và tổng chi phí trở lại tỉ lệ với số nút. Cấu trúc "sorted linear array" là nơi tìm nhị phân phát huy đúng sức: chỉ số giữa tính được bằng một phép cộng rồi chia, nên lấy phần tử giữa tốn thời gian hằng số. Cấu trúc "Binary search tree" vốn đã gói sẵn ý tưởng chia đôi vào hình dạng của nó, mỗi nút chia miền giá trị thành hai nửa nên đi từ gốc xuống chính là một phép tìm nhị phân.
Mở trang câu hỏi này →
Đề bài
Node p1,p2; p1 = p.next;
 p2 = p1.next;
 p.next = p2;
if(p2!=null) p2.prev=p;
A7 1 6 4 3 8 2
B7 1 6 3 9 8 2
C7 1 6 4 3 9 2
D7 1 4 3 9 8 2
E1 6 4 3 9 8 2
Lời giải
Đáp án đúng: "7 1 6 4 3 8 2". Hai lệnh đầu chỉ lấy tham chiếu: p1 là nút 9 ngay sau p chứa 3, p2 là nút 8 đứng sau 9. Lệnh p.next=p2 cho 3 trỏ vượt qua 9 để tới 8, còn p2.prev=p nối lại chiều ngược, nên nút 9 không còn ai trỏ tới và rời khỏi danh sách; các nút khác không bị chạm. "7 1 6 3 9 8 2" xoá nút 4 là nút đứng trước p, muốn vậy phải đi qua p.prev chứ không phải p.next. "7 1 6 4 3 9 2" xoá nút 8, nhưng 8 chính là p2, là nút được nối vào nên nó phải còn. "7 1 4 3 9 8 2" xoá nút 6 ở giữa, không liên quan gì tới ba lệnh chỉ làm việc quanh p. "1 6 4 3 9 8 2" xoá nút đầu, việc đó cần gán lại head mà đoạn mã không hề chạm tới head.
Mở trang câu hỏi này →
Đề bài
int x = 13;
Node f = p.prev; //prev is a link to predecessor node
Node q = new Node(x);
q.prev = f; q.next = p;
f.next = q; p.prev = q;
A7 1 6 4 3 12 8 2 13
B7 1 6 4 3 13 12 8 2
C7 1 6 4 3 12 13 8 2
D7 13 1 6 4 3 12 8 2
E13 7 1 6 4 3 12 8 2
Lời giải
Đáp án đúng: "7 1 6 4 3 13 12 8 2". Đoạn mã dùng liên kết lùi của danh sách liên kết đôi: f = p.prev là nút đứng ngay trước p, tức nút 3, còn q là nút mới mang giá trị 13. Bốn lệnh gán khâu q vào đúng giữa f và p theo cả hai chiều: q.prev = f cùng q.next = p cho q biết hai láng giềng, f.next = q cùng p.prev = q cho hai láng giềng nhận lại q. Vậy 13 nằm giữa 3 và 12, cho 7 1 6 4 3 13 12 8 2. "7 1 6 4 3 12 13 8 2" đặt 13 sau 12, kết quả của việc lấy mốc là p.next rồi khâu vào phía sau p. "7 1 6 4 3 12 8 2 13" là chèn vào cuối danh sách, chẳng dùng tới p. "7 13 1 6 4 3 12 8 2" và "13 7 1 6 4 3 12 8 2" chèn ở đầu danh sách, trong khi đoạn mã chỉ chạm tới hai nút kề p là 3 và 12.
Mở trang câu hỏi này →
Đề bài
int x = 9;
Node q = new Node(x);
q.prev=null;
q.next = head;
head.prev = q;
head = q;
A7 11 6 4 3 13 8 2 9
B7 11 6 4 3 13 8 9 2
C7 11 6 4 3 13 9 8 2
D7 9 11 6 4 3 13 8 2
E9 7 11 6 4 3 13 8 2
Lời giải
Đáp án đúng: "9 7 11 6 4 3 13 8 2". Điều đáng chú ý là đoạn mã không dùng tới p một lần nào: nó tạo q mang giá trị 9, đặt q.prev bằng null và q.next bằng head, rồi head.prev bằng q và head bằng q. Bốn lệnh ấy là khuôn chèn vào đầu danh sách liên kết đôi, nên 9 trở thành nút đầu đứng trước 7, còn mọi nút khác giữ đúng trật tự cũ. Vì vậy "7 11 6 4 3 13 8 2 9" sai vì nối vào cuối phải sửa tail.next và tail; "7 11 6 4 3 13 8 9 2" sai vì chèn trước nút cuối phải lấy mốc là tail.prev; "7 11 6 4 3 13 9 8 2" sai vì nó chèn ngay sau nút 13, đúng chỗ mà p trỏ tới, nhưng đoạn mã không hề đọc p; "7 9 11 6 4 3 13 8 2" sai vì chèn sau head thì q.next phải là head.next và head.next mới trỏ sang q, trong khi ở đây q.next chính là head.
Mở trang câu hỏi này →
AObject pop() { if(isEmpty()) return(null); Node p = head; head=head.next; if(head==tail) tail=null; return(p.info); }
BObject pop() { if(isEmpty()) return(null); Node p = head; head=head.next; return(p.info); }
CObject pop() { if(isEmpty()) return(null); Node p = head; head=head.next; if(head==null) tail=null; return(p.info); }
DObject pop() { if(isEmpty()) return(null); head=head.next; if(head.next==null) tail=null; return(head.info); }
Lời giải

Đáp án đúng: "Object pop() { if(isEmpty()) return(null); Node p = head; head=head.next;

Lời giải
if(head==null) tail=null;
return(p.info);

}". Phép lấy ra phải giữ nút đỉnh vào biến p trước khi dời head rồi trả về p.info, và khi head trở thành null tức danh sách vừa hết thì phải xoá luôn tail để hai con trỏ không còn chỉ vào nút đã bỏ. Bản "Object pop() { if(isEmpty()) return(null); Node p = head; head=head.next;

Lời giải
if(head==tail) tail=null;
return(p.info);

}" kiểm sai điều kiện: khi danh sách còn đúng một nút thì head và tail trùng nhau một cách hợp lệ, xoá tail lúc đó làm hỏng một danh sách chưa rỗng. Bản "Object pop() { if(isEmpty()) return(null); Node p = head; head=head.next; return(p.info); }" trả về đúng giá trị nhưng bỏ quên tail, nên khi ngăn xếp rỗng tail vẫn trỏ vào nút đã bị loại. Bản "Object pop() { if(isEmpty()) return(null); head=head.next;

Lời giải
if(head.next==null) tail=null;
return(head.info);

}" dời head trước rồi trả head.info nên trả về phần tử thứ hai chứ không phải đỉnh vừa lấy, và khi danh sách chỉ có một nút thì head thành null nên head.next gây lỗi con trỏ rỗng.

Mở trang câu hỏi này →
Avoid enqueue(Object x) { Node p = new Node(x); p.next = null; tail.next = p; tail = p; }
Bvoid enqueue(Object x) { Node p = new Node(x); p.next = null; if(isEmpty()) head = tail = p; else { tail.next = p; tail = p; } }
Cvoid enqueue(Object x) { Node p = new Node(x); p.next = null; if(isEmpty()) head = tail = p; else tail.next = p; }
Dvoid enqueue(Object x) { Node p = new Node(x); p.next = null; if(isEmpty()) head = tail = p; else tail = p; }
Lời giải

Đáp án đúng: "

Lời giải
void enqueue(Object x) {
  Node p = new Node(x);
  p.next = null;
  if(isEmpty()) head = tail = p;
  else {
    tail.next = p;
    tail = p;
  }
}

". Thêm vào đuôi hàng đợi phải xử lý hai tình huống: khi danh sách rỗng chưa có tail nào để nối vào nên cả head và tail cùng trỏ vào nút mới; khi đã có phần tử thì nối tail.next = p để nút mới vào sau cùng rồi dời tail = p để đuôi luôn là nút cuối thật. Bản này làm đủ cả hai, còn p.next = null giữ cho đuôi kết thúc đúng. Phương án "

Lời giải
void enqueue(Object x) {
  Node p = new Node(x);
  p.next = null;
  tail.next = p;
  tail = p;
}

" bỏ hẳn nhánh rỗng, nên khi hàng đợi chưa có gì thì tail là null và lệnh tail.next gây lỗi truy cập null. Phương án "

Lời giải
void enqueue(Object x) {
  Node p = new Node(x);
  p.next = null;
  if(isEmpty()) head = tail = p;
  else tail.next = p;
}

" nối đúng nhưng quên dời tail, nên lần thêm sau lại nối vào đúng nút cũ và phần tử vừa thêm trước đó bị mất khỏi chuỗi. Phương án "

Lời giải
void enqueue(Object x) {
  Node p = new Node(x);
  p.next = null;
  if(isEmpty()) head = tail = p;
  else tail = p;
}

" chỉ dời tail mà không nối tail.next, nên nút mới trôi ra ngoài danh sách và đi từ head sẽ không bao giờ tới được nó.

Mở trang câu hỏi này →
AEvaluating arithmetic expressions.
BStore all variables in a program.
CStore a waiting list of printing jobs.
DMulti-programming.
Lời giải
Đáp án đúng: "Evaluating arithmetic expressions.". Định giá biểu thức số học cần lấy ra đúng toán hạng hoặc toán tử nạp vào gần nhất, chẳng hạn khi gặp dấu đóng ngoặc thì phải xử lý phần vừa mở gần nhất trước, nên quy tắc vào sau ra trước của ngăn xếp khớp hoàn toàn; cài đặt ký pháp Ba Lan ngược cũng chỉ là đẩy toán hạng vào rồi lấy ra khi gặp toán tử. "Store all variables in a program." sai vì bảng biến cần tra theo tên bất kỳ lúc nào, trong khi ngăn xếp chỉ cho đọc phần tử trên đỉnh. "Store a waiting list of printing jobs." sai vì danh sách chờ in phải phục vụ bản in gửi trước, đó là hàng đợi; dùng ngăn xếp thì bản gửi sớm nhất có thể đợi vô hạn. "Multi-programming." sai vì hệ điều hành xếp tiến trình chờ theo thứ tự đến để cấp lượt, cũng là hàng đợi chứ không phải vào sau ra trước.
Mở trang câu hỏi này →
Đề bài
while(there are more characters in the word to read)

{read a character if a character is '*' then pop and write the poped character to the screen

Đề bài
  else
  push the character into the stack
}

What is written to the screen for the input "GoodA**fter*****Noo*n" ?

AAdretfdo
BAdretfon
CAdoretoo
DAdretfoo
Lời giải
Đáp án đúng: "Adretfoo". Mỗi dấu sao lấy phần tử trên đỉnh ngăn xếp rồi in ngay, nên thứ tự in luôn ngược thứ tự nạp. Nạp G, o, o, d, A; hai dấu sao in A rồi d, ngăn xếp còn G, o, o. Nạp f, t, e, r; năm dấu sao in r, e, t, f rồi o, ngăn xếp còn G, o. Nạp N, o, o; một dấu sao in o, ngăn xếp còn G, o, N, o. Sau đó nạp n và hết chuỗi nên không in thêm, tổng cộng tám ký tự ứng với tám dấu sao. Chuỗi "Adretfdo" thay ký tự thứ bảy bằng d, nhưng d đã bị in từ lần lấy ra thứ hai nên không thể ra lần nữa. Chuỗi "Adretfon" kết thúc bằng n, mà n là ký tự nạp sau cùng và chuỗi vào đã hết trước khi có thêm dấu sao nào để đẩy nó ra. Chuỗi "Adoretoo" đặt o ngay sau hai ký tự đầu, trong khi lúc ấy ngăn xếp vừa nhận f, t, e, r nên ba lần lấy ra kế tiếp phải cho r, e, t.
Mở trang câu hỏi này →
Đề bài
while(there are more characters in the word to read)

{read a character if a character is '*' then pop the stack

Đề bài
    else
     push the character into the stack
 }
while(the stack is not empty)

pop and write the poped character to the screen What is written to the screen for the input "Good**Mor*ni***ng" ?

AgnMoG
BgnMoo
CgnoMo
DGoMng
Lời giải
Đáp án đúng: "gnMoG". Mỗi dấu sao chỉ lấy một phần tử ra khỏi ngăn xếp mà không in gì; phần in chỉ xảy ra ở vòng lặp cuối, lấy lần lượt từ đỉnh xuống đáy. Chạy tay: Good vào thành G, o, o, d; hai dấu sao lấy d và o nên còn G, o; Mor vào thành G, o, M, o, r; một dấu sao lấy r nên còn G, o, M, o; n và i vào thành G, o, M, o, n, i; ba dấu sao lấy i, n, o nên còn G, o, M; n và g vào thành G, o, M, n, g. In từ đỉnh được g, n, M, o, G. "gnMoo" để chữ o ở đáy, nhưng đáy ngăn xếp là G vì G được đẩy vào đầu tiên và không dấu sao nào lấy tới nó. "gnoMo" đổi chỗ M với o, trái thứ tự đẩy vào là o trước rồi M. "GoMng" là đọc từ đáy lên đỉnh, tức in theo kiểu vào trước ra trước chứ không phải vào sau ra trước của ngăn xếp.
Mở trang câu hỏi này →
AInteger pop() {if (isEmpty()) return; return((Integer) pool.remove(pool.size()-1)); }
BInteger pop() { if (isEmpty()) return(null); return((Integer) pool.remove(pool.size()-1)); }
Cvoid pop(Integer x) { if (isEmpty()) return(null); pool.remove(pool.size()-1); }
DInteger pop() { if (isEmpty()) return(null); return(pool.remove(pool.size())); }
Lời giải

Đáp án đúng: "Integer pop() {

Lời giải
if (isEmpty()) return(null);
return((Integer) pool.remove(pool.size()-1));

}". Đỉnh ngăn xếp là cuối danh sách, nên lấy ra phải xoá phần tử ở chỉ số pool.size()-1 rồi trả về chính phần tử vừa xoá; khi ngăn xếp rỗng thì trả null để người gọi biết không có gì lấy, vẫn khớp kiểu trả về Integer đã khai báo. Phương án "Integer pop() {

Lời giải
if (isEmpty()) return;
return((Integer) pool.remove(pool.size()-1));

}" dùng lệnh return trống trong hàm có kiểu trả về nên không biên dịch được. Phương án "

Lời giải
void pop(Integer x) {
  if (isEmpty()) return(null);
  pool.remove(pool.size()-1);
}

" vừa trả giá trị trong hàm void, vừa nhận tham số vô nghĩa, lại không đưa phần tử lấy ra cho người gọi. Phương án "Integer pop() {

Lời giải
if (isEmpty()) return(null);
return(pool.remove(pool.size()));

}" lấy ở chỉ số pool.size(), vượt quá chỉ số hợp lệ cuối cùng là pool.size()-1, nên luôn gây lỗi chỉ số ngoài phạm vi.

Mở trang câu hỏi này →
Avoid pop(Integer x) { if (isEmpty()) return(null); pool.remove(pool.size()-1); }
BInteger pop() { if (isEmpty()) return(null); return((Integer) pool.removeLast()); }
CInteger pop() {if (isEmpty()) return; return((Integer) pool.remove(pool.size()-1)); }
DInteger pop() { if (isEmpty()) return(null); return((Integer) pool.remove(pool.size())); }
Lời giải

Đáp án đúng: "Integer pop() {

Lời giải
if (isEmpty()) return(null);
return((Integer) pool.removeLast());

}". Cuối danh sách là đỉnh ngăn xếp, và java.util.LinkedList có sẵn removeLast() tháo nút cuối rồi trả về phần tử đó, đúng ngữ nghĩa pop là lấy ra và trả về; kiểu trả Integer cho phép trả null khi rỗng, còn phép ép sang Integer hợp với việc danh sách thô lưu Object. Vì vậy "

Lời giải
void pop(Integer x) {
  if (isEmpty()) return(null);
  pool.remove(pool.size()-1);
}

" sai vì hàm void không được return(null), lại nhận tham số và không trả gì nên phần tử đỉnh không bao giờ tới tay người gọi. "Integer pop() {

Lời giải
if (isEmpty()) return;
return((Integer) pool.remove(pool.size()-1));

}" sai vì hàm khai báo trả Integer mà có lệnh return trống, trình biên dịch báo thiếu giá trị trả về. "Integer pop() {

Lời giải
if (isEmpty()) return(null);
return((Integer) pool.remove(pool.size()));

}" sai vì chỉ số hợp lệ chỉ đến size()-1, nên remove(pool.size()) luôn vượt biên và ném IndexOutOfBoundsException.

Mở trang câu hỏi này →
AStore a waiting list of printing jobs.
BStore all variables in a program.
CKeeping track of local variables at run time.
DUndo sequence in a text editor.
Lời giải
Đáp án đúng: "Store a waiting list of printing jobs.". Hàng đợi phục vụ theo nguyên tắc vào trước ra trước, đúng như hàng chờ in: việc nào gửi tới máy in sớm hơn thì được in trước, việc mới luôn thêm vào cuối hàng và không ai chen ngang. Phương án "Store all variables in a program." cần tra theo tên ở bất kỳ thứ tự nào, đó là việc của bảng băm hay bảng ký hiệu, không phải cấu trúc chỉ cho lấy phần tử ở đầu. Phương án "Keeping track of local variables at run time." dùng ngăn xếp lời gọi: hàm gọi sau phải kết thúc trước, tức vào sau ra trước, trái hẳn hàng đợi. Phương án "Undo sequence in a text editor." cũng là ngăn xếp vì thao tác vừa làm phải được hoàn tác đầu tiên, còn hàng đợi sẽ hoàn tác thao tác cũ nhất trước.
Mở trang câu hỏi này →
Đề bài
while(there are more characters in the word to read)

{read a character if a character is '*' then dequeue and write the dequeued character to the screen

Đề bài
  else
  enqueue the character into the queue
}

What is written to the screen for the input "Goo**dAft***erno*on" ?

AGoodAT
BGoodAf
CGoodAE
DfAdooG
Lời giải
Đáp án đúng: "GoodAf". Hàng đợi vào trước ra trước, nên mỗi dấu sao lấy ra phần tử được nạp sớm nhất còn lại. Chuỗi vào lần lượt là G, o, o, hai dấu sao, d, A, f, t, ba dấu sao, e, r, n, o, một dấu sao, o, n. Chạy theo đó: nạp G, o, o; hai dấu sao lấy ra G rồi o, in được Go; nạp d, A, f, t; ba dấu sao kế tiếp lấy ra o, d, A, in thêm odA; nạp e, r, n, o; dấu sao tiếp theo lấy ra f, in thêm f; hai ký tự o và n cuối chỉ được nạp vào mà không còn dấu sao nào kéo ra. Chuỗi in ra là G, o, o, d, A, f tức GoodAf. Phương án "fAdooG" là đúng dãy ấy đọc ngược, ứng với việc dùng ngăn xếp vào sau ra trước thay cho hàng đợi. Phương án "GoodAT" và phương án "GoodAE" đều đúng năm ký tự đầu rồi sai ký tự thứ sáu: sau khi G, o, o, d, A đã ra, phần tử vào sớm nhất còn lại là f, vì f được nạp trước cả t và e.
Mở trang câu hỏi này →
Đề bài
while(there are more characters in the word to read)

{read a character if a character is '*' then dequeue the queue

Đề bài
else
enqueue the character into the queue
}

How the queue looks like after processing the input "Goo**dMor***ning**"?

A(1)
B(2)
C(3)
D(4)
Lời giải
Đáp án đúng: "(4)", tức mảng vòng còn n ở ô 1, i ở ô 2, n ở ô 3 và g ở ô 4, hai ô 0 và 5 trống. Đếm trước cho nhanh: dãy nhập có mười một chữ cái và bảy dấu sao, nên hàng đợi còn đúng bốn phần tử, và vì dequeue chỉ lấy ở đầu nên bốn phần tử sót lại phải là bốn chữ vào sau cùng, theo thứ tự n, i, n, g. Vị trí thì chạy tay: G, o, o nằm ô 0, 1, 2; d, M, o nằm ô 3, 4, 5; r quay vòng về ô 0; rồi n, i, n, g lần lượt vào ô 1, 2, 3, 4; bảy lần dequeue đẩy đầu hàng từ ô 0 tới ô 1. "(1)" sai vì nội dung i, n, g, o của nó giữ lại chữ o của cụm Mor vốn đã bị dequeue và làm mất chữ n đầu của cụm ning. "(2)" sai vì cùng nội dung i, n, g, o lại còn đặt đầu hàng ở ô 0, trong khi bảy lần dequeue tính từ ô 0 phải đưa đầu hàng về ô 1. "(3)" sai vì vẫn là i, n, g, o xếp liền từ ô 1, tức đếm thiếu một lần enqueue so với dãy nhập.
Mở trang câu hỏi này →
19Consider the following function:4 lựa chọncó code
Đề bài
int fun(int n)
   {if(n==0)
     return(1);
      else
      return(n + fun(n/2));
   }

What is the output when the statement:

Đề bài
System.out.println(fun(9));

is run?

A18
B16
C17
D15
Lời giải
Đáp án đúng: "17". Hàm cộng n vào kết quả của fun(n/2) và dừng ở n bằng 0 với giá trị trả về 1, phép chia là chia nguyên. Chuỗi lời gọi là fun(9), fun(4), fun(2), fun(1), fun(0), nên tổng bằng 9 cộng 4 cộng 2 cộng 1 cộng 1, trong đó số 1 cuối là giá trị của trường hợp dừng. Số "16" bằng 9 cộng 4 cộng 2 cộng 1, tức quên rằng fun(0) trả về 1 chứ không phải 0. Số "18" lớn hơn kết quả đúng một đơn vị, nó đòi thêm một tầng nữa trong chuỗi chia đôi, nhưng sau fun(1) thì 1 chia 2 bằng 0 và đệ quy dừng ngay. Số "15" nhỏ hơn hai đơn vị, ứng với việc bỏ cả tầng fun(1) lẫn giá trị dừng, trong khi 1 lớn hơn 0 nên tầng ấy vẫn chạy và vẫn góp 1.
Mở trang câu hỏi này →
20Consider the following function:4 lựa chọncó code
Đề bài
void fun(int n)
   {if(n<=0)
     return;
      else if (n<7)
        {System.out.print("  " + n);
         fun(n-2);
        }
        else
         fun(n-2);
   }

What is the output when the statement fun(9); is run?

A1 3 5
B5 3 1
C7 5 3 1
D7 5 3
Lời giải
Đáp án đúng: "5 3 1". Đọc theo đúng thụt lề: n không lớn hơn 0 thì trả về ngay; n nhỏ hơn 7 thì in n rồi gọi fun(n-2); còn n từ 7 trở lên thì chỉ gọi fun(n-2) mà không in gì. Vậy fun(9) không in và gọi fun(7); fun(7) cũng không in vì 7 không nhỏ hơn 7, gọi fun(5); fun(5) in 5 rồi fun(3) in 3, rồi fun(1) in 1, rồi fun(-1) gặp n không lớn hơn 0 nên trả về. "1 3 5" là thứ tự ngược, chỉ xảy ra nếu lệnh in đặt sau lời gọi đệ quy. "7 5 3 1" in cả 7, nhưng điều kiện in là n nhỏ hơn 7 nên tại đúng 7 nhánh else được chọn và không in. "7 5 3" vừa in thêm 7 lại vừa bỏ mất 1, trong khi 1 vẫn nhỏ hơn 7 nên vẫn được in trước khi đệ quy xuống -1.
Mở trang câu hỏi này →