Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 58

1.

Cho đoạn code xử lý danh sách liên kết đơn sau

struct node {
int data;
struct node* next;
} node;

void func(struct node* head)


{
if (head == NULL || head->next == NULL) return;
int tmp = head->next->data;
head->next->data = head->data;
head->data = tmp;
func(head->next);
}

Nếu head đang trỏ tới danh sách 3,7 thì gọi hàm func(head) danh sách sẽ là 7,3
Nếu head đang trỏ tới danh sách 3,7 thì gọi hàm func(head) danh sách sẽ là 3,7
Nếu head đang trỏ tới danh sách rỗng thì gọi hàm func(head) sẽ bị lỗi
Nếu head đang trỏ tới danh sách 3,7,6 thì gọi hàm func(head) danh sách sẽ là 6,7,3
Nếu head đang trỏ tới danh sách 3,7,6 thì gọi hàm func(head) danh sách sẽ là 7,6,3
Nếu head đang trỏ tới danh sách 3,7,6,5 thì gọi hàm func(head) danh sách sẽ là 7,6,5,3
Nếu head đang trỏ tới danh sách 3,7,6,5 thì gọi hàm func(head) danh sách sẽ là 5,6,7,3

2.Cho đoạn code xử lý danh sách liên kết đơn sau

struct NODE
{
int data;
struct NODE* next;
};

// head là đầu danh sách


void func(struct NODE* head, int data)
{
// cấp phát phần tử mới
struct NODE* newNode = createNewNode(data);

if (head == NULL) {
head = newNode;
return;
}

struct NODE* last = head;


while (last->next != NULL) {
last = last->next;
}
last->next = newNode;
}

Nếu head đang trỏ tới NULL thì gọi hàm liên tiếp func(head,3), func(head,7) sẽ cho danh sách 3,7
Nếu head đang trỏ tới NULL thì gọi hàm liên tiếp func(head,3), func(head,7) sẽ cho danh sách
rỗng
nếu head đang trỏ tới danh sách gồm 3,4, việc gọi hàm func(head,7) sẽ cho danh sách 7,3,4
nếu head đang trỏ tới danh sách gồm 3,4, việc gọi hàm func(head,7) sẽ cho danh sách 3,4,7
nếu head đang trỏ tới danh sách gồm 3,4, việc gọi hàm func(head,7) sẽ cho danh sách 3,4

3.Đâu là các thao tác cơ bản mà 1 cấu trúc dữ liệu cần phải có
Duyệt
Tìm kiếm
Thêm
Xóa
Đảo ngược dãy
Copy - clone
4.Cho đoạn code xử lý danh sách liên kết đơn sau

struct NODE
{
int data;
struct NODE* next;
};

// head là đầu danh sách


void func(struct NODE* head, int data)
{
struct NODE* newNode = createNewNode(data);
newNode->next = head;
head = newNode;
}

Nếu head đang trỏ tới NULL thì gọi hàm liên tiếp func(head,3), func(head,7) sẽ cho danh sách 7,3
Nếu head đang trỏ tới NULL thì gọi hàm liên tiếp func(head,3), func(head,7) sẽ cho danh sách
rỗng
nếu head đang trỏ tới danh sách gồm 3,4, việc gọi hàm func(head,7) sẽ cho danh sách 7,3,4
nếu head đang trỏ tới danh sách gồm 3,4, việc gọi hàm func(head,7) sẽ cho danh sách 3,4,7
nếu head đang trỏ tới danh sách gồm 3,4, việc gọi hàm func(head,7) sẽ cho danh sách 3,4

5.Cho đoạn code xử lý danh sách liên kết đơn sau

struct node {
int data;
struct node* next;
} node;

void func(struct node* head) {


if (head == NULL) return;
func(head->next);
printf("%d ", head->data);
}

Nếu head đang trỏ tới danh sách 3,7 thì gọi hàm func(head) sẽ in ra 7 3
Nếu head đang trỏ tới danh sách 3,7 thì gọi hàm func(head) sẽ in ra 3 7
Nếu head đang trỏ tới danh sách rỗng thì gọi hàm func(head) sẽ bị lỗi
Nếu head đang trỏ tới danh sách 3,7,3 thì gọi hàm func(head) sẽ in ra 3 7 3
nếu head đang trỏ tới danh sách gồm 3,4, việc gọi hàm func(head) sẽ cho danh sách 3

6.Deep copy - copy sâu và shallow copy - copy nông là gì


Deep copy tạo ra bản copy riêng (vùng nhớ riêng) của các giá trị mới
shallow copy thì bản copy cũng chỉ về vùng nhớ của bản gốc
deep copy và shallow copy liên quan đến việc copy các dữ liệu có thành phần con trỏ
Deep copy và Shallow Copy chỉ xảy ra trong Java

7.Điểm khác biệt giữa cấu trúc danh sách liên kết đơn và mảng là
Trong danh sách liên kết đơn, mỗi phần tử phải có ít nhất 1 trường kiểu con trỏ
Danh sách liên kết đơn có thể di chuyển - duyệt theo nhiều hướng
Danh sách liên kết đơn chỉ cấp phát và lưu trữ đủ các phần tử hiện có
Thêm/xóa với danh sách liên kết đơn chỉ cần xử lý với con trỏ, không cần di chuyển phần tử
Danh sách liên kết đơn luôn tiết kiệm bộ nhớ hơn mảng
Muốn truy cập vào danh sách luôn phải có địa chỉ phần tử đầu tiên
Thêm/xoá phần tử trong danh sách liên kết đơn có chi phí thấp hơn so với mảng trong trường
hợp tổng quát

8.Cho cấu trúc 1 danh sách liên kết đơn như sau

struct node {
int data;
struct node* next;
} node;

// Hàm để xóa các phần tử có giá trị x khỏi danh sách


void removeX(A, int x) {
struct node* current = *headRef;
struct node* prev = NULL;

// Xóa các phần tử đứng đầu có giá trị x


while (current != NULL && current->data == x) {
*headRef = current->next;
B;
current = *headRef;
}

// Xóa các phần tử có giá trị x khác


while (current != NULL) {
while (current != NULL && C) {
prev = current;
current = current->next;
}
if (current == NULL) return;
prev->next = D;
free(current);
current = prev->next;
}
}

A: struct node** headRef


A: struct node* headRef
B: free(*headRef)
B: free(current)
C: current->data == x
C: current->data != x
D: current->next
D: current

9.Cho cấu trúc 1 danh sách liên kết đơn như sau

struct node {
int data;
struct node* next;
} node;

// Hàm để xóa phần tử thứ k trong danh sách


// phần tử đầu tiên sẽ có thứ tự là 1
void deleteKth(A, int k) {
if (*headRef == NULL) return;

struct node* temp = *headRef;

// Nếu phần tử cần xóa là phần tử đầu tiên


if (k == 1) {
*headRef = temp->next;
B;
return;
}

// Duyệt đến phần tử thứ k - 1


for (int i = 1; C && D; i++) {
temp = temp->next;
}

// Nếu k lớn hơn số lượng phần tử trong danh sách


if (temp == NULL || temp->next == NULL) {
printf("Position out of range.\n");
return;
}

// Xóa phần tử thứ k


struct node* nextNode = temp->next->next;
E;
temp->next = nextNode;
}

A: struct node** headRef


A: struct node* headRef
B: free(*headRef)
B: free(temp)
C: temp->next != NULL
C: temp != NULL
D: i < k - 1
D: i <= k - 1
E: free(temp->next)
E: free(temp)

10.Cho đoạn code xử lý danh sách liên kết đơn sau

struct node {
int data;
struct node* next;
} node;

void func(struct node* head) {


if (head->next !=NULL) func(head->next);
printf("%d ", head->data);
}

Nếu head đang trỏ tới danh sách 3,7 thì gọi hàm func(head) sẽ in ra 7 3
Nếu head đang trỏ tới danh sách 3,7 thì gọi hàm func(head) sẽ in ra 3 7
Nếu head đang trỏ tới danh sách rỗng thì gọi hàm func(head) sẽ bị lỗi
Nếu head đang trỏ tới danh sách 3,7,3 thì gọi hàm func(head) sẽ in ra 3 7 3
nếu head đang trỏ tới danh sách gồm 3, việc gọi hàm func(head) sẽ bị lỗi

11.Để lưu trữ một danh sách n số nguyên với số lượng n tối đa có thể lên
tới 1tr (số lượng thực sự biến động trong quá trình dùng) thì nên dùng
CTDL nào để tiết kiệm bộ nhớ nhất
Mảng cấp phát 1 lần 1tr phần tử
Mảng động - hoặc vector
Danh sách liên kết đơn
Tất cả các phương án trên đều tiết kiệm bộ nhớ như nhau

12.struct Node là cấu trúc đã được định nghĩa để lưu trữ 1 nút của danh
sách liên kết, với dữ liệu 1 nút là kiểu DATATYPE
*head là con trỏ trỏ tới đầu danh sách liên kết
Code thực hiện với C/C++
Khi thêm 1 phần tử vào danh sách trong trường hợp tổng quát cần định nghĩa hàm là: void
insertNode (struct Node *head, DATATYPE data)
Khi thêm 1 phần tử vào danh sách trong trường hợp tổng quát cần định nghĩa hàm là: void
insertNode (struct Node **head, DATATYPE data)
Khi thêm 1 phần tử vào danh sách trong trường hợp tổng quát cần định nghĩa hàm là: struct
Node* insertNode (struct Node *head, DATATYPE data)
Khi thêm 1 phần tử vào danh sách trong trường hợp tổng quát cần định nghĩa hàm là: struct Node
insertNode (struct Node *head, DATATYPE data)

13.Bạn cần lưu trữ thông tin các sản phẩm trong giỏ hàng của mỗi khác
hàng khi mua sắm trên website, bạn sẽ
Dùng mảng để lưu trữ thông tin vì tìm kiếm thông tin sản phẩm trong giỏ hàng nhanh hơn
Dùng mảng để lưu trữ thông tin giỏ hàng vì duyệt khi checkout nhanh hơn
Dùng danh sách liên kết đơn để lưu trữ vì tối ưu bộ nhớ hơn
Dùng danh sách liên kết đơn để lưu trữ vì thêm và xóa sản phẩm dễ dàng hơn
Dùng mảng để lưu trữ vì thêm và xóa sản phẩm dễ dàng hơn

14.Với mảng kích thước biến đổi và giả sử ban đầu mảng cấp phát với 1
phần tử thì khi thêm lần lượt n phần tử vào mảng ta sẽ cần giãn mảng tối
đa bao nhiêu lần
n
logn
sqrt(n)
n/2
loglogn
15.So với mảng truyền thống thì kiểu vector trong C++ STL có đặc điểm gì
nổi bật
Không cần khai báo số lượng phần tử trước
Tự động thay đổi kích thước tùy vào nhu cầu sử dụng
Hỗ trợ một số hàm sẵn để xử lý
Thời gian thực hiện thêm hoặc xóa không phải hằng số
Trong trường hơp tổng quát vector tiết kiệm bộ nhớ hơn mảng truyền thống

16.Đâu là khẳng định đúng về kiểu dữ liệu con trỏ


Con trỏ chỉ lưu trữ địa chỉ ô nhớ
Phép cộng và trừ với kiểu con trỏ sẽ là cộng hoặc trừ địa chỉ ô nhớ
Con trỏ void về lý thuyết có thể truy cập đến bất kỳ ô nhớ nào trong RAM
Có thể gán trực tiếp giá trị biến con trỏ bằng địa chỉ ô nhớ

17.Cho đoạn code quản lý mảng cấp phát động ở trong C như sau, các
đoạn còn thiếu cần điền gì?

int n;
printf("Enter the size of the array: ");
scanf("%d", &n);

// Cấp phát bộ nhớ động cho mảng


double* arr =A;

// Kiểm tra xem việc cấp phát bộ nhớ có thành công không
if (B) {
printf("Memory allocation failed.\n");
return 1; // Kết thúc chương trình với mã lỗi 1
}

// Nhập dữ liệu vào mảng


printf("Enter %d elements:\n", n);
for (int i = 0; i < n; i++) {
scanf("%d", &arr[i]);
}

// Xử lý mảng
......

// Giải phóng bộ nhớ sau khi sử dụng xong


C;

A : (double*)malloc(n * sizeof(double))
A: (double)malloc(n * sizeof(double))
A: (double*)malloc(n * sizeof(double*))
B: arr != NULL
B: arr == NULL
B: arr = NULL
C: delete(arr)
C: free(arr)
C :free(*arr)

18.Đâu là khẳng định đúng với kiểu dữ liệu mảng


Các phần tử trong mảng phải có cùng kiểu
Địa chỉ của phần tử đầu mảng rất quan trọng
Mảng nhiều chiều chỉ là cách nhìn logic của mảng 1 chiều trên máy tính
Các phần tử trong mảng có tính cục bộ về bộ nhớ rất cao
Có thể tăng hoặc giảm kích thước mảng dễ dàng trong quá trình thực hiện chương trình
Các phần tử trong mảng luôn có địa chỉ liên tiếp nhau trong bộ nhớ
Cache dữ liệu với kiểu mảng dễ dàng hơn

19.Cho đoạn code xử lý mảng cấp phát nhiều lần trong C sau, cần điền gì
vào chỗ trống

int n;
printf("Enter the size of the array: ");
scanf("%d", &n);

// Cấp phát bộ nhớ động cho mảng


double* arr = A;
// XỬ LÝ MẢNG
....

// thay đổi kích thước mảng


int newSize;
printf("Enter new size of the array: ");
scanf("%d", &newSize);

arr = B;

if (arr == NULL) {
printf("Memory reallocation failed.\n");
return 1;
}

// XỬ LÝ MẢNG
....
// Giải phóng bộ nhớ sau khi sử dụng xong
C;

A: (double*)malloc(n * sizeof(double))
A: (double)malloc(n * sizeof(double*))
A: (double)malloc(n)
B: (double*)realloc(arr, newSize * sizeof(double*))
B: (double)realloc(arr, newSize * sizeof(double))
B: (double*)realloc(arr, newSize * sizeof(double))
B: (double*)malloc(arr, newSize * sizeof(double))
C: free(arr)
free(&arr)

20.Cho cấu trúc 1 danh sách liên kết đơn như sau

struct node {
int data;
struct node* next;
} node;

// hàm đếm số lượng khóa k trong danh sách


int countKeys(struct node* head, int k) {
int count = A;
struct node* current = head;
while (B) {
if (current->data == k) {
count++;
}
C;
}
return count;
}

A: 0
A: 1
B: current != NULL
B: current->data != k
C: current = NULL
C: current = current->next

1.Cho thuật toán mô tả bằng mã giả sau

Đọc lần lượt từng ký tự trong xâu đầu vào


Nếu là ký tự chữ số thì in ra màn hình
Nếu là ký tự chữ cái thì đẩy vào stack

Sau khi xử lý hết xâu đầu vào thì lần lượt lấy từng phần tử trong stack ra và in ra màn hình

Nếu áp dụng thuật toán trên vào xâu đầu vào thì sẽ thu được gì
xâu đầu vào INC12 sẽ in ra INC12
xâu đầu vào INC12 sẽ in ra INC21
xâu đầu vào INC12 sẽ in ra 21INC
xâu đầu vào INC12 sẽ in ra 12CNI
xâu đầu vào INC12 sẽ in ra 12INCCNI

2.Khẳng định nào về kiểu dữ liệu Ngăn xếp - stack là đúng


Đây là 1 loại container dạng LIFO
Đây là 1 loại container dạng FIFO
Việc thêm và xóa có thể diễn ra tại các đầu khác nhau
Phần tử thêm vào sau cùng luôn lấy ra trước tiên
Các phần tử trong ngăn xếp là ngang hàng nhau

3.Cho hàm sau trên danh sách liên kết đôi


struct DNODE {
int data;
struct DNODE* next, * prev;
};

void func(struct DNODE** headRef) {


struct DNODE* current = *headRef;
struct DNODE* prev = NULL;

while (current != NULL) {


if (current->data < 0) {
if (prev == NULL) {
*headRef = current->next;
if (*headRef != NULL)
(*headRef)->prev = NULL;
free(current);
current = *headRef;
} else {
prev->next = current->next;
if (current->next != NULL)
current->next->prev = prev;
free(current);
current = prev->next;
}
} else {
prev = current;
current = current->next;
}
}
}

Nếu danh sách hiện tại là 1,3,-5,7 thì sau khi gọi hàm func danh sách sẽ chỉ còn 1,3,7
Nếu danh sách hiện tại là NULL thì khi gọi hàm func sẽ lỗi
Nếu danh sách hiện tại là -3 thì khi gọi hàm func danh sách sẽ là -3
Nếu danh sách hiện tại là -3,-5,-7,0 thì khi gọi hàm func danh sách sẽ là NULL

4.Giả sử bạn thêm lần lượt các phần tử số nguyên vào 1 stack và mỗi thao
tác thêm vào bạn cần biết giá trị lớn nhất trong các phân tử hiện tại là bao
nhiêu
VD.
push(5) --> giá trị lớn nhất hiện tại là 5
push(7) --> giá trị lớn nhất hiện tại là 7
push(3) --> giá trị lớn nhất hiện tại là 7
pop() --> giá trị lớn nhất hiện tại là 7
pop() --> giá trị lớn nhất hiện tại là 5
pop() --> giá trị lớn nhất không tồn tại (do stack rỗng)

Đâu là khẳng định đúng

Chú ý. Có thể dùng thêm bộ nhớ phụ nếu cần


Chỉ có thể thực hiện được thao tác tìm max trên với thời gian O(n) trong trường hợp tồi nhất
Có thể thực hiện được thao tác tìm max trên với thời gian O(1) trong trường hợp tồi nhất
Không thể thực hiện thao tác tìm max vì trong stack không hỗ trợ duyệt tuần tự các phần tử
Chỉ có thể thực hiện được thao tác tìm max trên với thời gian O(logn) trong trường hợp tồi nhất

5.Đâu là thao tác để kiểm tra phần tử hiện tại (đang trỏ bởi con trỏ p) đã ở
cuối danh sách trong trường hợp danh sách liên kết đơn nối vòng (đầu
danh sách là head)
Danh sách khác rỗng và có ít nhất 1 phần tử
p==head
p->next == NULL
p==NULL
p->next == head
p->next->next == head->next
6.Trong danh sách liên kết đôi nối vòng đâu là khẳng định đúng
Nếu dùng nút giả thì danh sách rỗng khi head->next == head hoặc head->prev = head
Nếu không dùng nút giả thì danh sách rỗng khi head->next == NULL
Nếu dùng nút giả thì p là phần tử cuối danh sách khi p->next == head hoặc head->prev = p
Nếu không dùng nút giả thì p là phần tử cuối danh sách khi p->next == head hoặc head-
>prev = p

7.Hàm giải phóng bộ nhớ của các phần tử trong danh sách liên kết này có
vấn đề gì?

void freeList(struct DNODE* head) {


struct DNODE* current = head;
while (current != NULL) {
struct DNODE* temp = current;
current = current->next;
free(temp);
}
}

Hàm không có vấn đề gì


Hàm không thể xóa danh sách
Hàm vẫn để lại phần tử đầu danh sách chưa giải phóng
Hàm để lại phần tử đầu trỏ vào vùng nhớ đã xóa

8.Khẳng định nào sau đây về kiểu dữ liệu Stack là đúng (Stack trong STL và
trong Java)
Các thao tác thêm và lấy ra có thời gian O(1)
Thao tác tìm kiếm phần tử có thời gian O(n)
Thao tác tìm kiếm phần tử cũng có thời gian O(1)
Thao tác kiểm tra stack số lượng phần tử hiện có trong Stack có thời gian O(n)
Thao tác trả về số lượng các phần tử hiện có trong Stack là O(1)

9.Ma trận M gồm n hàng và m cột, số lượng phần tử sẽ mà nxm. Ma trận


thưa là ma trận mà phần lớn các phần tử trong ma trận bằng 0, chỉ có 1 số
lượng nhỏ khác 0. Giả sử cần thực hiện các thao tác cơ bản như cộng, trừ,
chuyển vị ma trận, chúng ta nên dùng ctdl nào để lưu trữ ma trận cho tiết
kiệm bộ nhớ
Dùng danh sách liên kết đơn
Dùng mảng
Dùng danh sách liên kết đôi
Dùng danh sách liên kết đôi nối vòng

10.Cho hàm sau trên danh sách liên kết đôi


struct DNODE {
int data;
struct DNODE* next, * prev;
};

int func(struct DNODE* head) {


int count = 0;
struct DNODE* current = head;

while (current != NULL && current->next != NULL) {


if (current->data < current->next->data) {
count++;
}
current = current->next;
}

return count;
}

Nếu danh sách hiện tại là 1,3,-5,7 thì sau khi gọi hàm func sẽ trả về giá trị 2
Nếu danh sách hiện tại là NULL thì khi gọi hàm func sẽ lỗi
Nếu danh sách hiện tại là -3 thì khi gọi hàm func trả về giá trị 1
Nếu danh sách hiện tại là -3,-5,-7,0 thì khi gọi hàm func sẽ trả về giá trị 4
Nếu danh sách hiện tại là -3,-5,-7,0 thì khi gọi hàm func sẽ bị lỗi

11.Cho hàm sau trên danh sách liên kết đôi


struct DNODE {
int data;
struct DNODE* next, * prev;
};

void func(struct DNODE* headRef) {


struct DNODE* current = headRef;
struct DNODE* temp = NULL;

while (current != NULL) {


temp = current->prev;
current->prev = current->next;
current->next = temp;
current = current->prev;
}

// Kiểm tra nếu danh sách không rỗng


if (temp != NULL) {
headRef = temp->prev;
}
}

Nếu danh sách hiện tại là 1,3,-5,7 thì sau khi gọi hàm func danh sách sẽ chỉ còn 7,-5,3,1
Nếu danh sách hiện tại là NULL thì khi gọi hàm func sẽ lỗi
Nếu danh sách hiện tại là -3 thì khi gọi hàm func danh sách sẽ là -3
Nếu danh sách hiện tại là -3,-5,-7,0 thì khi gọi hàm func danh sách sẽ là 0
Nếu danh sách hiện tại là -3,-5,-7,0 thì khi gọi hàm func danh sách sẽ là 3

12.Cho hàm sau xử lý trên danh sách liên kết đôi

struct DNODE
{
int data;
struct DNODE* next, * prev;
};

// Hàm thêm phần tử vào đâu danh sách


void push_front(A, int data)
{
struct DNODE* pnew = createNewNode(data);

if (B) {
*head = pnew;
}
else // ngươc lại gắn pnew vào vị trí thích hợp
{
C;
D;
E;
}
}

Cần điền gì vào chỗ trống


A: struct DNODE** head
A: struct DNODE* head
A: struct DNODE&& head
B: *head == NULL
B: head == NULL
C: *head->prev = pnew
C: *head = pnew
C: pnew->next = *head
D: *head->prev = pnew
D: (*head)->prev = pnew
D: *head = pnew
E: head = pnew
E: *head = pnew

13.Cho hàm sau trên danh sách liên kết đôi


struct DNODE {
int data;
struct DNODE* next, * prev;
};

void func(struct DNODE** headRef) {


if (*headRef == NULL || (*headRef)->next == NULL) {
return; // Danh sách trống hoặc chỉ có một nút
}

struct DNODE* tail = *headRef;


while (tail->next != NULL) {
tail = tail->next;
}

struct DNODE* current = *headRef;


while (current != tail) {
if (current->data < 0) {
if (current == *headRef) {
*headRef = current->next;
(*headRef)->prev = NULL;
} else {
current->prev->next = current->next;
current->next->prev = current->prev;
}
tail->next = current;
current->prev = tail;
tail = current;
current = current->next;
tail->next = NULL;
} else {
current = current->next;
}
}
}

Nếu danh sách hiện tại là 1,3,-5,7 thì sau khi gọi hàm func danh sách sẽ là -5,7,3,1
Nếu danh sách hiện tại là NULL thì khi gọi hàm func sẽ lỗi
Nếu danh sách hiện tại là -3 thì khi gọi hàm func danh sách sẽ là -3
Nếu danh sách hiện tại là -3,-5,-7,0 thì khi gọi hàm func danh sách sẽ là 0,-3,-5,-7
Nếu danh sách hiện tại là -3,-5,-7,0 thì khi gọi hàm func sẽ bị lỗi

14.Biểu thức dạng hậu tố có ưu điểm gì so với dạng trung tố


Chỉ có một cách tính giá trị duy nhất
Không cần xét độ ưu tiên toán tử và dấu ngoặc
Khi tính giá trị biểu thức, chỉ cần duyệt 1 lần
Toán tử nào gặp trước sẽ là toán tử được thực hiện đầu tiên
Không cần dùng dấu ngoặc

15.Cho hàm sau trên danh sách liên kết đôi


struct DNODE {
int data;
struct DNODE* next, * prev;
};

void func(struct DNODE* head) {


struct DNODE* current = head;
int position = 1;
while (current != NULL) {
if (position % 2 == 1) {
printf("%d ", current->data);
}
current = current->next;
position++;
}
printf("\n");
}

Nếu danh sách hiện tại là 1,3,-5,7 thì sau khi gọi hàm func các phần tử được in ra sẽ là 3,7
Nếu danh sách hiện tại là 1,3,-5,7 thì sau khi gọi hàm func các phần tử được in ra sẽ là 1, -5
Nếu danh sách hiện tại là -3 thì khi gọi hàm func các phần tử được in ra sẽ là -3
Nếu danh sách hiện tại là -3,-5,-7, 4,0 thì khi gọi hàm func các phần tử được in ra sẽ là -3,-5,4

16.Cho biểu thức dạng hậu tố sau, giá trị của biểu thức tính được sẽ là (các
toán tử là 2 ngôi)
483++*3-1++54-
Biểu thức bị sai
52
53
47

17.Giả sử ta sẽ thêm vào stack các chữ cái theo 1 thứ tự thêm là A B C D E F,
tuy nhiên giữa các lệnh thêm vào này lại đan xem các lệnh lấy ra.
Vậy thứ tự nào có thể là thứ tự lấy ra đúng trong các thứ tự sau
ABCDEF
ABCDFE
BCDEFA
ACDBEF
CDEFAB

18.Khi cài đặt cấu trúc dữ liệu ngăn xếp - Stack, đâu là khẳng định đúng
Cuối mảng là đỉnh của ngăn xếp khi cài đặt dùng mảng
Đầu mảng là đỉnh ngăn xếp khi cài đặt dùng mảng
Đầu danh sách liên kết đơn là đỉnh ngăn xếp khi cài đặt dùng DSLK đơn
Cuối danh sách liên kết đơn là đỉnh ngăn xếp khi cài đặt dùng DSLK đơn

19.Thao tác xóa 1 phần tử có giá trị x trong danh sách liên kết đơn sẽ có chi
phí trong trường hợp tốt nhất là
O(1)
O(logn)
O(n)
Không có lựa chọn nào là đúng

20.Đối với danh sách liên kết đôi thông thường, khi thêm phần tử vào sau
một phần tử đã có trong danh sách (đang trỏ bởi p) đâu là những công việc
cần làm
Cần kiểm tra phần tử p có phải cuối danh sách hay không
Cần kiểm tra phần tử p có phải đầu danh sách hay không
Cần kiểm tra danh sách hiện tại có rỗng
Cần kiểm tra p có rỗng
1.Cho biểu thức dạng trung tố sau, dạng hâu tố tương ứng sẽ là gì

(3+a-b)+5-2+6/c
(1 Point)
3ab-+52-+6c/+
3ab-+5+2-6c/+
3a+b-52-+6/+
3a+b-5+2-6c/+

2.Làm thế nào để có thể mô phỏng các thao tác của 1 stack dùng 2 hàng
đợi? Khẳng định nào là đúng
Không thể mô phỏng được vì hàng đợi không thể đảo được thứ tự
vẫn mô phỏng được, tuy nhiên mỗi lần lấy ra sẽ có chi phí O(n)
Mỗi lần thêm vào ta sẽ chỉ thêm vào hàng đợi đang có phần tử, hàng đợi còn lại dùng để hỗ
trợ lấy ra
Khi thêm mới ta luôn thêm vào hàng đơi đang trống, khi lấy ra thì lấy tại hàng đơi đang có phần tử
Luôn có 1 hàng đợi trống và 1 hàng đợi chứa các phần tử, hai hàng đợi không thể đồng thời
có phần tử

3.struct Node {
int data;
struct Node *next;
};

// Định nghĩa cấu trúc của hàng đợi


struct Queue {
struct Node *front, *rear;
};

// Hàm lấy phần tử ra khỏi hàng đợi


int dequeue(struct Queue* q) {
if (isEmpty(q)) {
printf("Hang doi trong!\n");
return -1;
}
struct Node* temp = A;
int item = temp->data;
q->front = B;

if (C) {
D;
}
free(temp);
return item;
}

A :q->front
A: q->rear
B: q->front->next
B: temp->next
C : q->front == NULL
C : q->rear == NULL
D: q->rear = NULL
D: q->front = NULL

4.Cho định nghĩa 1 Stack đơn giản

// Cấu trúc Stack


struct Stack {
char *items;
int top;
int capacity;
};

// Hàm kiểm tra xem Stack có trống không


int isEmpty(struct Stack *stack) {
return stack->top == -1;
}

int func(char *s) {


struct Stack *stack = createStack(strlen(s));

for (int i = 0; s[i] != '\0'; i++) {


if (s[i] == '(' || s[i] == '[' || s[i] == '{') {
push(stack, s[i]);
} else if (s[i] == ')' || s[i] == ']' || s[i] == '}') {
if (isEmpty(stack)) {
free(stack->items);
free(stack);
return 0;
}
char top = pop(stack);
if ((s[i] == ')' && top != '(') || (s[i] == ']' && top != '[') || (s[i] == '}' && top != '{')) {
free(stack->items);
free(stack);
return 0;
}
}
}
int result = isEmpty(stack);
free(stack->items);
free(stack);
return result;
}

func("((()])") trả về giá trị 1


func("((()])") trả về giá trị 0
func("ABA") trả về giá trị 0
func("ABA") trả về giá trị 1

5.// Cấu trúc hàng đợi


struct Queue {
int data[MAX_SIZE];
int front, rear; // chỉ số của các phần tử trong hàng đợi
};

// Hàm thêm phần tử vào hàng đợi


void enqueue(struct Queue *q, int item) {
// Kiểm tra hàng đợi có đầy không
if (isFull(q)) {
printf("Hang doi day!\n");
return;
}
// Nếu hàng đợi trống
if (isEmpty(q)) {
A;
}
// thêm phần tử mới vào
q->rear = B;
q->data[q->rear] = item;
}

A: q->front = 0
A: q->rear = 0
B: (q->rear + 1) % MAX_SIZE
B: (q->rear + 1)
B: (q->front + 1) % MAX_SIZE

6.Trong ý tưởng mô phỏng thao tác của 1 hàng đợi dùng 2 stack thì đâu là
khẳng định đúng
Việc thêm vào và lấy ra chỉ diễn ra tại 1 stack, stack còn lại chỉ là phụ
Luôn thêm vào tại Stack S1 và lấy ra tại stack S2
Nếu khi lấy ra mà Stack S2 rỗng thì sẽ lấy tại stack S1
Nếu khi thêm vào mà Stack S1 đang có phần tử thì sẽ thêm vào Stack S2
Nếu khi lấy ra mà Stack S2 rỗng thì ta sẽ lấy 1 phần tử của S1 đưa sang S2, sau đó lấy tại S2

7.Mảng dạng "vòng" trong cài đặt hàng đợi là mảng có đặc điểm gì
Bộ nhớ vật lý trên máy là mảng 1 chiều
Bộ nhớ vật lý trên máy là mảng 2 chiều
Bộ nhớ vật lý trên máy tạo thành hình vòng tròn
Duyệt hết phần tử cuối sẽ quay ngược về đầu mảng
Sử dụng bộ nhớ một cách tối ưu hơn so với các cài đặt dùng mảng thông thường

8.Cài đặt 2 hàng đợi chỉ dùng 1 mảng

struct Queue {
int items[MAX_SIZE];
int front1, rear1; // Front và rear của hàng đợi thứ nhất
int front2, rear2; // Front và rear của hàng đợi thứ hai
};

// Hàm khởi tạo hàng đợi


struct Queue* initQueue() {
struct Queue* q = (struct Queue*)malloc(sizeof(struct Queue));
q->front1 = q->rear1 = -1; // Khởi tạo hàng đợi thứ nhất rỗng
q->front2 = q->rear2 = MAX_SIZE; // Khởi tạo hàng đợi thứ hai rỗng
return q;
}

// Hàm kiểm tra hàng đợi có đầy không


int isFull(struct Queue* q)

Hàng đợi đầy khi (q->rear1 == MAX_SIZE - 1 && q->rear2 == 0)


Hàng đợi đầy khi (q->rear1 == -1 && q->rear2 == MAX_SIZE - 1)
q->rear1 + 1 == q->rear2
q->rear1 + q->rear2 == MAX_SIZE - 1
q->rear1 + q->rear2 == MAX_SIZE

9.Nếu cài đặt hàng đợi ưu tiên bằng các cấu trúc dữ liệu cơ bản thì
Thao tác them và lấy ra sẽ có thời gian O(n) nếu cài đặt bằng mảng
Thao tác them vào có thời gian O(n) và lấy ra sẽ có thời gian O(1) nếu cài đặt bằng mảng
Thao tác them và lấy ra sẽ có thời gian O(n) nếu cài đặt bằng danh sách liên kết
Thao tác them vào có thời gian O(n) và lấy ra sẽ có thời gian O(1) nếu cài đặt bằng danh sách
liên kết

10.Trong bài toán kiểm tra thẻ tag trong file html hoặc XML có hợp lệ hay
không (thẻ mở phải có thẻ đóng, trừ 1 số thẻ đặc biệt) dùng stack, đâu là
khẳng định đúng
Chỉ lưu trữ Stack bằng danh sách liên kết đơn
Chỉ lưu trữ Stack bằng mảng
Mỗi phần tử của Stack sẽ có thông tin mã thẻ (VD. thẻ body, p, a,..) lưu trữ bằng xâu ký tự
Lưu trữ bằng Mảng hay Danh sách liên kết đơn đều được
Độ phức tạp thời gian là O(n) trong trường hợp tồi nhất

11.Trong cài đặt hàng đợi dùng danh sách móc nối, việc sử dụng thêm con
trỏ rear - trỏ vào cuối danh sách có tác dụng là
Thêm phần tử vào cuối danh sách nhanh hơn
Đếm số phần tử trong danh sách nhanh hơn
Để phân biệt khi hàng đợi đầy và rỗng dễ dàng hơn
Để lấy phần tử khỏi hàng đợi dễ dàng hơn

12.Trong máy in mạng, để quản lý các công việc in đến từ các máy trong
LAN thì printer spooling đó nên tổ chức hàng đợi như thế nào?
Nên tổ chức hàng đợi bằng mảng với số lượng phần tử hàng đợi bằng số lượng máy tính trong LAN
Nên tổ chức hàng đợi dùng danh sách liên kết đơn để tối ưu bộ nhớ
Hàng đợi chỉ cần chứa địa chỉ IP máy yêu cầu in
Hàng đợi cần chứa nội dung công việc cần in

13.Cho hàm check thẻ html hợp lệ sau

// Hàm kiểm tra tính hợp lệ của các thẻ HTML


int isValidHTMLTags(char *html) {
struct Stack *stack = createStack(strlen(html));

for (int i = 0; html[i] != '\0'; i++) {


// Nếu gặp ký tự '<', ta đẩy nó vào Stack
if (html[i] == '<') {
push(stack, '<');
}
else if (html[i] == '>') {
if (!isEmpty(stack) && stack->items[stack->top] == '<') {
pop(stack);
} else {
free(stack->items);
free(stack);
return 0;
}
}
}

// Nếu Stack rỗng sau khi duyệt qua toàn bộ chuỗi HTML, thì các thẻ HTML hợp lệ
int result = isEmpty(stack);
free(stack->items);
free(stack);
return result;
}

Hàm trên check được mọi loại thẻ html


Hàm trên chỉ check được cặp <> chứ chưa check được thẻ theo tên
Hàm trên trả về giá trị 0 nếu số lượng < khác với >
Hàm trên không check đâu là mở thẻ và đâu là đóng thẻ

14.// Hàm kiểm tra tính hợp lệ của các thẻ HTML
int isValidHTMLTags(char *html) {
struct Node *stack = NULL;

// Duyệt qua từng ký tự trong chuỗi HTML


char *token = strtok(html, "<>");
while (token != NULL) {
// Nếu token là thẻ mở, thêm nó vào Stack
if (token[0] == '<' && token[1] != '/') {
push(&stack, token);
}
// Nếu token là thẻ đóng
else if (token[0] == '<' && token[1] == '/') {
// Kiểm tra xem Stack có rỗng không
if (isEmpty(stack)) {
return 0;
}
// Lấy thẻ mở khỏi Stack và so sánh tên thẻ
char *openTag = pop(&stack);
if (openTag == NULL || strcmp(openTag + 1, token + 2) != 0) {
return 0;
}
}
token = strtok(NULL, "<>");
}

// Nếu Stack còn phần tử sau khi duyệt xong, thì các thẻ HTML không hợp lệ
if (!isEmpty(stack)) {
return 0;
}
return 1;
}
Hàm trên check được mọi loại thẻ html
isValidHTMLTags("<div><p>Hello, world!</p></div>") trả về giá trị 1
isValidHTMLTags("<div><p>Hello, world!</div>") trả về giá trị 1
isValidHTMLTags("<div><p>Hello, world!</div>") trả về giá trị 0
15.Cài đặt 2 hàng đợi chỉ dùng 1 mảng

struct Queue {
int items[MAX_SIZE];
int front1, rear1; // Front và rear của hàng đợi thứ nhất
int front2, rear2; // Front và rear của hàng đợi thứ hai
};

// Hàm khởi tạo hàng đợi


struct Queue* initQueue() {
struct Queue* q = (struct Queue*)malloc(sizeof(struct Queue));
q->front1 = q->rear1 = -1; // Khởi tạo hàng đợi thứ nhất rỗng
q->front2 = q->rear2 = MAX_SIZE; // Khởi tạo hàng đợi thứ hai rỗng
return q;
}

// Hàm thêm phần tử vào hàng đợi thứ nhất


void enqueue1(struct Queue* q, int item) {
if (isFull(q)) {
printf("Hang doi day!\n");
return;
}

if (q->front1 == A) {
q->front1 = 0;
}
q->rear1 = B;
q->items[q->rear1] = item;
}

// Hàm thêm phần tử vào hàng đợi thứ hai


void enqueue2(struct Queue* q, int item) {
if (isFull(q)) {
printf("Hang doi day!\n");
return;
}
if (q->front2 == C) {
q->front2 = MAX_SIZE - 1;
}
q->rear2 =D % MAX_SIZE;
q->items[q->rear2] = item;
}

(1 Point)
A :-1
A: 0
B: (q->rear1 + 1) % MAX_SIZE
B: q->rear1 + 1
C: MAX_SIZE-1
C: MAX_SIZE
D: (q->rear2 - 1 + MAX_SIZE)
D: (q->rear2 - 1)
16.struct Node {
int data;
struct Node *next;
};

// Định nghĩa cấu trúc của hàng đợi


struct Queue {
struct Node *front, *rear;
};

// Hàm thêm phần tử vào hàng đợi


void enqueue(struct Queue* q, int item) {

struct Node* temp = (struct Node*)malloc(sizeof(struct Node));


temp->data = item;
A;

if (isEmpty(q)) {
B;
C;
return;
}

D;
q->rear = temp;
}

A :front->next = NULL
A: temp->next = NULL
B: q->front = temp
B: q->front = NULL
C : q->rear = temp
C : q->rear = NULL
D: q->rear->next = temp
D: q->rear= temp

17.Cho thuật toán sau

Lặp lại công việc sau trên xâu đầu vào


+ đọc từng ký tự của xâu đầu vào
+ Đẩy ký tự vừa đọc vào Stack

Lặp lại công việc sau cho tới khi Stack rỗng
+ Lấy phần tử ở đỉnh Stack ra
+ In phần tử đó ra màn hình

Nếu xâu đầu vào là Stack thì kết quả in ra là kcatS


Nếu xâu đầu vào là Stack thì kết quả in ra là Stack
Nếu xâu đầu vào là Stack thì kết quả in ra là kStac
Nếu xâu đầu vào là ABC thì kết quả in ra là CAB

18.Trong thuật toán chuyển biểu thức dạng trung tố sang dạng hậu tố
dùng Stack thì khẳng định nào sau đây là đúng
Stack dùng để chưa các toán hạng
Stack dùng để chứa toán tử
Stack dùng để chứa toán tử và dấu (
Stack dùng để chứa cả toán tử và toán hạng và dấu (
Stack dùng để chứa toán tử và dấu ( )
19.// Hàm kiểm tra tính hợp lệ của các thẻ HTML
int isValidHTMLTags(char* html) {
struct Node* stack = NULL;
// Duyệt qua từng ký tự trong chuỗi HTML
char* token = strtok(html, ">"), * subToken;
while (token != NULL) {
subToken = strchr(token, '<');
if (subToken == NULL) return 0;
subToken++;
// Nếu token là thẻ mở, thêm nó vào Stack
if (subToken[0] != '/') {
push(&stack, subToken);
printf("push %s\n", subToken);
}
// Nếu token là thẻ đóng
else if (subToken[0] == '/') {
// Kiểm tra xem Stack có rỗng không
if (isEmpty(stack)) {
return 0;
}
// Lấy thẻ mở khỏi Stack và so sánh tên thẻ
char* openTag = pop(&stack);
printf("Pop %s\n", openTag);
if (openTag == NULL || strcmp(openTag, subToken+1) != 0) {
return 0;
}
}
token = strtok(NULL, ">");
}

// Nếu Stack còn phần tử sau khi duyệt xong, thì các thẻ HTML không hợp lệ
if (!isEmpty(stack)) {
return 0;
}
return 1;
}
Hàm trên check được mọi loại thẻ html
isValidHTMLTags("<div><p>Hello, world!</p></div>") trả về giá trị 1
isValidHTMLTags("<div><p>Hello, world!</div>") trả về giá trị 1
isValidHTMLTags("<div><p>Hello, world!</div>") trả về giá trị 0
isValidHTMLTags("Hello, world!</p></div>") trả về giá trị 0
isValidHTMLTags("Hello, world!</p></div>") trả về giá trị 1

20.Cài đặt hàng đợi dùng mảng có đặc điểm gì


Phải biết trước số lượng phần tử tối đa nếu dùng mảng cấp phát 1 lần
Tiết kiệm bộ nhớ hơn cài đặt bằng danh sách liên kết nếu kiểu dữ liệu của các phần tử là kiểu
đơn giản
Thời gian thực hiện các thao tác thêm hoặc lấy ra (xóa) có thể lên tới O(n) trong trường hợp
tồi nhất
Thời gian thực hiện nhanh hơn so với cài đặt dùng danh sách liên kết
Thời gian thực hiện các thao tác cơ bản luôn là O(1) trong trường hợp tồi nhất

20232 IT3011 CTDL&TT Quiz 08 Cây tổng quát

Time:

54:07

14/18

Trong các phương án biểu diễn cây tổng quát, giả sử ta biết trước số lượng
nút thì phương án nào tiết kiệm bộ nhớ nhất: Biển diễn qua danh nhãn
nút cha, biểu diễn qua danh sách nút con, biểu diễn qua con đầu tiên và
anh chị em kế tiếp
Biển diễn qua danh sách nhãn nút cha

biểu diễn qua danh sách nút con

biểu diễn qua con đầu tiên và anh chị em kế tiếp

Các phương án đều tiết kiệm bộ nhớ như nhau

Cho cây nhị phân tổng quát với root như hình
Hàm sau sẽ in ra gì

void func(struct TNODE *root)


{
if(root==NULL) return;
printf("%c, ", root->label);
struct TNODE *nextBrother = root->firstChild;
while(nextBrother!=NULL)
{
func(nextBrother);
nextBrother=nextBrother->nextSibling;
}
}
A, C, B, E, G, H, F, D, I, J, K, L,

A, C, B, E, F, G, H, D, I, J, K, L,

C, G, H, E, F, B, J, K, L, I, D, A

Cho khai báo hàng đợi ưu tiên cài đặt bằng danh sách liên kết đơn sau
// Khai báo cấu trúc phần tử của hàng đợi
typedef struct Node {
int data;
int priority;
struct Node* next;
} Node;

// Khai báo cấu trúc của hàng đợi ưu tiên


typedef struct {
Node* front;
} PriorityQueue;

// Hàm thêm một phần tử vào hàng đợi ưu tiên


void enqueue(PriorityQueue* queue, int data, int priority) {
Node* newNode = createNode(data, priority);

if (isEmpty(queue) || A) {
B;
queue->front = newNode;
} else {
Node* current = queue->front;
while (current->next != NULL && C) {
current = current->next;
}
D;
current->next = newNode;
}
}

A: priority > queue->front->priority

A: priority >= queue->front->priority


A: priority < queue->front->priority

B: newNode->next = queue->front->next

B: newNode->next = queue->front

C: current->next->priority >= priority

C: current->next->priority > priority

C: current->next->priority < priority

D: newNode->next = current

D: newNode->next = current->next

Có những loại nút nào trên cây


nút gốc

nút giữa

nút lá

nút rìa

nút trong

nút đỉnh

Cho cây nhị phân tổng quát với root như hình
Hàm sau sẽ trả về gì
int func(struct TNODE *root)
{
if(root==NULL) return 0;
if(root->firstChild==NULL) return 0;
struct TNODE *nextBrother = root->firstChild;
int max = -1, cur;
while(nextBrother!=NULL)
{
cur = func(nextBrother);
if(cur>max)max=cur;
nextBrother=nextBrother->nextSibling;
}
return 1+max;
}

11

Trong duyệt cây tổng quát, nếu nút lá luôn được xử lý đầu tiên thì quá
trình duyệt này có thể là
duyệt theo thứ tự trước

duyệt theo thứ tự sau

duyệt theo mức

duyệt theo thứ tự giữa


7

trong khi duyệt cây, dữ liệu tại gốc được xử lý sau khi xử lý hết tại các nút
con của nó. Thuật toán duyệt này được gọi là
duyệt theo thứ tự trước

duyệt theo thứ tự sau

duyệt tuần tự

duyệt theo thứ tự giữa

duyệt quay lui

Cho cây nhị phân tổng quát với root như hình
Hàm sau sẽ trả về gì

int func(struct TNODE *root)


{
if(root==NULL) return 0;
if(root->firstChild==NULL) return 0;
struct TNODE *nextBrother = root->firstChild;
int sum = 0;
while(nextBrother!=NULL)
{
sum += func(nextBrother);
nextBrother=nextBrother->nextSibling;
}
return 1+sum;
}

12

3
9

Để in ra các nút trên cây theo thứ tự lần lượt nút gốc, sau đó tới các nút
gần gốc trước, sau đó tới các nút xa hơn thì thuật toán duyệt cây đó ta cần
dùng thêm cấu trúc dữ liệu phụ nào
ngăn xếp

hàng đợi

gọi đệ quy, không cần dùng thêm cấu trức dữ liệu phụ

dùng vòng lặp và không cần dùng thêm cấu trúc dữ liệu phụ

10

Cho khai báo hàng đợi ưu tiên dùng mảng sau, cần điền gì vào chỗ khuyết
// Khai báo cấu trúc phần tử của hàng đợi
typedef struct {
int data;
int priority;
} Element;

// Khai báo cấu trúc của hàng đợi ưu tiên


typedef struct {
Element elements[MAX_SIZE];
int size;
} PriorityQueue;

// Hàm thêm một phần tử vào hàng đợi ưu tiên


void enqueue(PriorityQueue *queue, int data, int priority) {
if (isFull(queue)) {
printf("Hang doi day!\n");
return;
}

int index = A;
while (index > 0 && B< priority) {
queue->elements[index] = queue->elements[index - 1];
C;
}

queue->elements[index].data = data;
queue->elements[index].priority = priority;
D;
}

A : queue->size

A: MAX_SIZE

A: 0

B: queue->elements[index].priority

B: queue->elements[index - 1].priority

B: queue->elements[MAX_SIZE- 1].priority

C : index--

C: index++

C: index=index-1

D: queue->size++

D: queue->size

11

Để tạo ra một cây nhị phân đầy đủ chiều cao h, số lượng nút cần phải có là
bao nhiêu
2^h

(2^(h+1))-1

2*h+1

2*(h+1)
12

// hàm tạo cây mặc định ban đầu


struct TNODE *initTree()
{
struct TNODE *root;

root = createNewNode('A');

addNewChild(root, 'B');
addNewChild(root, 'H');
addNewChild(root, 'I');

addNewChild(root->firstChild, 'C');

addNewChild(root->firstChild->nextSibling, 'F');
addNewChild(root->firstChild->nextSibling, 'G');

addNewChild(root->firstChild->firstChild, 'D');
addNewChild(root->firstChild->firstChild, 'E');

return root;
}

ĐÂu là khẳng định đúng

F là con đầu tiên của H

I là con của G

E là con của B

Độ sâu của B là 2

Độ sâu của I là 1

Độ cao của A là 2

Nút anh chị em kế tiếp của C là F


13

Nếu cài đặt hàng đợi ưu tiên bằng các cấu trúc dữ liệu cơ bản thì
Thao tác thêm và lấy ra sẽ có thời gian O(n) nếu cài đặt bằng mảng

Thao tác thêm vào có thời gian O(n) và lấy ra sẽ có thời gian O(1) nếu cài đặt bằng mảng

Thao tác thêm và lấy ra sẽ có thời gian O(n) nếu cài đặt bằng danh sách liên kết

Thao tác thêm vào có thời gian O(n) và lấy ra sẽ có thời gian O(1) nếu cài đặt bằng danh sách
liên kết

14

Cho cây nhị phân tổng quát với root như hình
Hàm sau sẽ trả về giá trị gì
nếu root là A

int func(struct TNODE *root, struct TNODE *cur)


{
if(root==NULL) return 0;
if(root==cur) return 0;
struct TNODE *nextBrother = root->firstChild;
int childRet;
while(nextBrother!=NULL)
{
if(cur==nextBrother) return 1;
childRet = func(nextBrother,cur);
if(childRet>0) return 1+ childRet;
nextBrother=nextBrother->nextSibling;
}
}

root là A và cur là A thì hàm lỗi

root là A và cur là F thì hàm lỗi

root là A và cur là F thì hàm trả về 1

root là A và cur là H thì hàm trả về 3

root là A và cur là C thì hàm trả về 0


15

Cho khai báo hàng đợi ưu tiên cài đặt bằng danh sách liên kết đơn sau
// Khai báo cấu trúc phần tử của hàng đợi
typedef struct Node {
int data;
int priority;
struct Node* next;
} Node;
// Khai báo cấu trúc của hàng đợi ưu tiên
typedef struct {
Node* front;
} PriorityQueue;

// Hàm lấy phần tử ưu tiên cao nhất từ hàng đợi ưu tiên


int dequeue(A) {
if (isEmpty(queue)) {
printf("Hang doi rong!\n");
exit(1);
}
Node* temp = B;
int data = C;
queue->front = D;
free(temp);
return data;
}

A: PriorityQueue queue

A: PriorityQueue* queue

B: queue

B: queue->front

C: temp->data

C: queue->front->data

D: temp->next

D: queue->front->next
16

Chiều cao/độ sâu của của cây được tính như thế nào
là đường đi từ gốc tới lá dài nhất

là độ sâu của nút lá lớn nhất

là đường đi tới lá ngắn nhất

là đường đi từ gốc tới nút lá ở xa gốc nhất

17

Cho cây nhị phân tổng quát với root như hình
Hàm sau sẽ in ra gì

void func(struct TNODE *root, int k)


{
if(root==NULL) return 0;
if(k==0) {
printf("%c, ", root->label);
return ;
}
struct TNODE *nextBrother = root->firstChild;
while(nextBrother!=NULL)
{
func(nextBrother,k-1);
nextBrother=nextBrother->nextSibling;
}
}

root là A và k = 1 sẽ in ra C

root là A và k = 1 sẽ in ra D, B, C

root là A và k = 2 sẽ in ra E, F, I

root là B và k = 3 sẽ in ra G, H

root là D và k = 3 sẽ không in gì ra màn hình


18

Có những kiểu quan hệ nào giữa các nút trên cây


quan hệ ngang hàng

quan hệ bác - cháu

quan hệ cha-con

quan hệ tổ tiên-con cháu

quan hệ anh chị em họ hàng (khác cha)

1
Cho hàm sau, điền gì vào chỗ khuyết ?

struct BNODE *findNode(struct BNODE *root, char label)


{
if(root==NULL||A) return root;
struct BNODE *left = findNode(root->left, label);
if(B) return left;
return findNode(C, label);
}

A: root->label=label
A: root->label==label
B: left!= NULL
B: left== NULL
C: root->right
C: root->left

2
Cho hàm sau, khi áp dụng với đầu vào là 2 cây trên thì kết quả trả về sẽ là
gì?

int compareTree(TN* r1, TN* r2)


{
if(r1==NULL && r2==NULL) return 1;
if((r1->left==NULL && r2->left==NULL)||(r1->right==NULL && r2->right==NULL)) return 1;
return compareTree(r1->left, r2->left) + compareTree(r1->right, r2->right);
}

0
1
Hàm lỗi

3
// Định nghĩa cấu trúc của một nút trong cây nhị phân
struct Node {
int data; // giá trị nút chỉ là 1 hoặc 0
struct Node* left;
struct Node* right;
};

// Hàm tìm độ dài đường đi chứa số 1 dài nhất từ gốc


int longestPath(struct Node* root)
{
if(root==NULL) return A;
if(root->data==0) return B;
int left = longestPath(root->left);
int right = longestPath(root->right);
return C;
}

A: 0
A: -1
B: 0
B: -1
C: left>right?left:right
C: 1+ (left>right?left:right)
4
Cho hàm sau, đâu là khẳng định đúng
Nút gốc root luôn là A

int calDepth(struct BNODE *root, struct BNODE *curr)


{
if (root==NULL) return 0;

if ((root->leftChild == curr) || (root->rightChild == curr))


{
return 1;
}

int leftDepth = calDepth(root->leftChild, curr);


if (leftDepth > 0 ) leftDepth = leftDepth + 1;
int rightDepth = calDepth(root->rightChild, curr);
if (rightDepth > 0) rightDepth = rightDepth + 1;

return (leftDepth > rightDepth) ? leftDepth : rightDepth;


}
Nếu curr cũng là A thì hàm lỗi
Nếu curr cũng là A thì hàm trả về 0
Nếu curr là E thì hàm trả về 0
Nếu curr là C thì hàm trả về 1
Nếu curr là F thì hàm trả về 2

5
// Hàm kiểm tra xem hai cây nhị phân có đối xứng với nhau hay không (giá
trị tại các nút đối xứng cũng phải bằng nhau)
bool isMirror(struct Node* left, struct Node* right) {
if (A)
return true;
if (B)
return false;
return (C) && isMirror(left->left, right->right) && isMirror(left->right, right->left);
}

// Hàm kiểm tra xem cây nhị phân có đối xứng hay không
bool isSymmetric(struct Node* root) {
if (root == NULL)
return D;
return isMirror(root->left, root->right);
}
A: left == NULL && right == NULL
A: left == NULL || right == NULL
B: left == NULL || right == NULL
B: left == NULL && right == NULL
C: left->data != right->data
C: left->data == right->data
D: true
D: false

6
Cho cây nhị phân tìm tổng quát như hình.
Khi chạy thuật toán ở dưới thì giá trị trả về của hàm sẽ là

int calculate(TN* root)


{
if(NULL==root) return 0;
int l = calculate(root->left);
int r = calculate(root->right);
return 1+ (l>r?l:r);
}
3
4
2
Không có kết quả nào ở trên là đúng
5

7
Cho hàm sau, khi áp dụng với đầu vào là processTree(root->left, root-
>right) thì kết quả trả về sẽ là gì?
root là gốc của cây

int processTree(TN* r1, TN* r2)


{
if(r1==NULL && r2==NULL) return 1;
if((r1!=NULL && r2==NULL)||(r1==NULL&&r2!=NULL)) return 0;
return 1 + processTree(r1->left, r2->left) + processTree(r1->right, r2->right);
}

processTree(root->left, root->right);

1
2
0
3
Hàm bị lỗi

8
Cho cây nhị phân tìm tổng quát như hình.
Khi chạy thuật toán ở dưới thì
void printLeaves(TN* root)
{
if(NULL==root) return;
queue<pair<TN*, int>> Q;
Q.push(make_pair(root, 0));
int currDepth=0, firstLeafDepth=-1;
while (Q.size() > 0)
{
// lay nut tiep trong hang doi
TN* p = Q.front().first; // la truong thu 1 cuar pair
currDepth = Q.front().second; // la truong thu 2 cua pair
Q.pop();

// meu gap nut la dau tien trong queue --> Khong them tiep cac nut nua
if(p->left==NULL && p->right==NULL)
{
if(firstLeafDepth==-1) firstLeafDepth = currDepth;
if(currDepth==firstLeafDepth)
printf("%c ", p->label);
continue;
}
else if(firstLeafDepth==-1)
{
if (NULL != p->left) Q.push(make_pair(p->left, currDepth + 1));
if (NULL != p->right) Q.push(make_pair(p->right, currDepth + 1));
}
}
printf("\n");
}

Chú ý: Root là gốc cây, nút A


printLeaves(root) in ra D E
printLeaves(root) in ra D
printLeaves(root) in ra D E G
printLeaves(root) in ra D E F H
printLeaves(root->right) in ra F H
printLeaves(root->right) in ra C

9
Cho hàm sau, khi áp dụng với đầu vào là 2 cây trên thì kết quả trả về sẽ là
gì?

int compareTree(TN* r1, TN* r2)


{
if(r1==NULL && r2==NULL) return 1;
if((r1!=NULL && r2==NULL)||(r1==NULL&&r2!=NULL)) return 0;
return compareTree(r1->left, r2->right) && compareTree(r1->right, r2->left);
}

0
1
Hàm lỗi

10
Cho cây nhị phân tìm tổng quát như hình.
Khi chạy thuật toán ở dưới thì thứ tự các nút được in ra sẽ là

void treeTravel(TN* root)


{
if(NULL==root) return;
treeTravel(root->left);
treeTravel(root->right);
printf("%c ",root->label);
}
DEBFHGCA
DBEACFGH
ABDECGFH
Không có thứ tự nào ở trên là đúng

11
Cho cây nhị phân tìm tổng quát như hình.
Khi chạy thuật toán ở dưới thì giá trị trả về của hàm sẽ là

int calculate(TN* root)


{
if(NULL==root) return 0;
int l = calculate(root->left);
int r = calculate(root->right);
return 1+ l+r;
}

7
8
9
Không có kết quả nào ở trên là đúng
10

12
Cho đoạn code sau

struct Node* find(struct Node* root, struct Node* rNode)


{
if(root==NULL||root->left==rNode
|| root->right==rNode) return root;
struct Node *left = find(root->left, rNode);
if(left!=NULL) return left;
return find(root->right, rNode);
}

Nếu root là A và rNode là F thì sẽ trả về nút A


Nếu root là A và rNode là F thì sẽ trả về nút B
Nếu root là A và rNode là A thì sẽ trả về NULL
Nếu root là A và rNode là A thì hàm lỗi
Nếu root là A và rNode là G thì sẽ trả về B
Nếu root là A và rNode là I thì sẽ trả về J

13
Cho cây nhị phân tìm tổng quát như hình.
Khi chạy thuật toán ở dưới thì giá trị trả về của hàm sẽ là

int calculate(TN* root)


{
if(NULL==root) return 0;
if(root->left==NULL && root->right==NULL) return 1;
int l = calculate(root->left);
int r = calculate(root->right);
return l+r;
}
5
4
8
Không có kết quả nào ở trên là đúng
3

14
Cho đoạn code sau

void printNodes(struct Node* root, int level) {


if (root == NULL) return;
if (level == 1 && root->left==NULL
&& root->right==NULL) {
printf("%c ", root->data);
} else if (level > 1) {
printDeepestLeafNodes(root->left, level - 1);
printDeepestLeafNodes(root->right, level - 1);
}
}

Nếu root là A và level =1 hàm sẽ in ra A


Nếu root là A và level =2 hàm sẽ in ra B,C
Nếu root là A và level =0 hàm lỗi
Nếu root là A và level =3 hàm sẽ in ra G H I
Nếu root là A và level =3 hàm sẽ in ra E F J D
Nếu root là A và level =3 hàm sẽ in ra F
Nếu root là A và level = 5 hàm lỗi
Nếu root là A và level =3 hàm sẽ in ra J F
Nếu root là A và level =4 hàm sẽ in ra G H I

15
Cây nhị phân tổng quát chỉ chứa nút trong có 2 con hoặc nút lá
Cho thứ tự duyệt trước A C D F E G J B I K H L M
thứ tự duyệt giữa D C E F G A B J H K L I M

Đâu là khẳng định đúng


Con của J là B và F
Chiều cao cây là 4 (chiều cao nút lá là 0)
L là con của K
G là con của C
H là nút 1 lá sâu nhất trên cây
16
Cho đoạn code sau

void findNode(struct BNODE *root, struct BNODE **aNode)


{
if(root==NULL) return;
if(root->label > (*maxNode)->label) *aNode= root;
findMaxNode(root->left, aNode);
findMaxNode(root->right,aNode);
}

Đâu là khẳng định đúng

Hàm trên bị lỗi


Nếu root là A và aNode là A thì sau khi gọi hàm aNode sẽ trả về nút I
Nếu root là A và aNode là A thì sau khi gọi hàm aNode sẽ trả về nút J
Nếu root là B và aNode là A thì sau khi gọi hàm aNode sẽ trả về nút G
Nếu root là B và aNode là NULL thì sau khi gọi hàm aNode sẽ trả về nút H
Nếu root là E và aNode là A thì sau khi gọi hàm sẽ bị lỗi

17
Cho cây nhị phân tìm tổng quát như hình.
Khi chạy thuật toán ở dưới thì thứ tự các nút được in ra sẽ là

void treeTravel(TN* root)


{
if(NULL==root) return;
treeTravel(root->right);
printf("%c ",root->label);
treeTravel(root->left);
}

DEBFHGCA
DBEACFGH
ABDECGFH
Không có thứ tự nào ở trên là đúng

18
Cho cây nhị phân tìm tổng quát như hình.
Khi chạy thuật toán ở dưới thì

int calculate(TN* root, int level)


{
if(NULL==root) return -1;
if(level==0) {printf("%c ", root->label); return 1;}
calculate(root->left,level-1);
calculate(root->right,level-1);
}

Chú ý: Root là gốc cây, nút A

calculate(root,1) in ra B C
calculate(root,1) in ra A
calculate(root,2) in ra D E G
Không có kết quả nào ở trên là đúng
calculate(root,2) in ra B C

19
Hàm đếm tần số xuất hiện của khóa k trong cây nhị phân
int countOccurrences(struct Node* root, int k) {
if (root == NULL)
return 0;

int A;

queue<B> Q;
Q.push(root);
struct Node *cur;
while (!Q.empty()) {
C;
Q.pop();
if(cur->data == k) count++;
D Q.push(cur->left);
E Q.push(cur->right);
}
return count;
}

A: count = 0
A: count
B: struct Node
B: struct Node*
C: cur = Q.front()
C: cur = Q.pop()
D:
D: if(cur->left!=NULL)
E: if(cur->left!=NULL)
E: if(cur->right!=NULL)
E:

20
Cho đoạn code sau

int isBalanced(struct BNODE* root) {


if (root == NULL)
return 0;
int leftHeight = isBalanced(root->left);
int rightHeight = isBalanced(root->right);
int diff = abs(leftHeight-rightHeight);
if(leftHeight <0||rightHeight <0 || diff>1) return -1;
return 1 + (leftHeight>rightHeight? leftHeight:rightHeight);
}
Đâu là khẳng định đúng

Hàm trên bị lỗi


Nếu root là A thì giá trị trả về của hàm là -1
Nếu root là C thì giá trị trả về của hàm là -1
Nếu root là E thì giá trị trả về của hàm là 0
Nếu root là J thì gái trị trả về của hàm là 0

You might also like