Tải bản đầy đủ (.docx) (29 trang)

Câu hỏi và đáp án thi hết môn Cấu trúc dữ liệu và giải thuật

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (266.26 KB, 29 trang )

Phần 1: Giải thuật và độ phức tạp tính tốn của giải thuật
Bài 1: Cho đoạn chương trình sau:
int Max(int a[], int n)
{
int temp,i;
temp=a[1];
for(i=2; i <=n; i++)
{1}
if (a[i]>temp) temp = a[i];
{2}
return temp;
}
a) Đoạn chương trình này thực hiện cơng việc gì?
b) Xác định độ phức tạp của đoạn chương trình trên.
Trả lời:
a) Đoạn chương trình này thực hiện việc sắp xếp mảng theo phương thức sắp xếp chọn
(Selection Sort).
b) Xác định độ phức tạp:
- Thời gian thực hiện lệnh {2} là O(1)
- Vòng lặp thực hiện n lần, mỗi lần O(1)
- Độ phức tạp của giải thuật là: T(n) = O(1).O(n) = O(n)
Bài 2:
a) Viết chương trình thực hiện phép tốn cộng hai ma trận vng cấp n
b) Xác định độ phức tạp của đoạn chương trình của câu a)
Trả lời:
a) Viết chương trình thực hiện phép tốn cộng hai ma trận vuông cấp n
#include <conio.h>
#include <stdio.h>
#define max 100
//Nhap ma tran vuong A cap n
void NhapMaTran(int A[max][max], int n)


{
for(int i = 0; ifor(int j = 0; j{
printf("[%d][%d] =",i,j);
scanf("%d", &A[i][j]);
}
}
//Xuat ma tran vuong A cap n
void XuatMaTran(int A[max][max], int n)
{
for(int i = 0; i{
printf("\n");
for(int j = 0; jprintf("%d\t",A[i][j]);
}


}
//Tong hai ma tran A va B luu vao trong ma tran C
void Tong(int A[max][max], int B[max][max], int C[max][max], int n){
for(int i = 0; ifor(int j = 0; jC[i][j] = A[i][j]+B[i][j];
}
//Tich hai ma tran A va B luu vao trong ma tran C
void Tich(int A[max][max], int B[max][max], int C[max][max], int n)
{
for(int i = 0; i

for(int k = 0; k{
C[i][k] = 0;
for(int j = 0; jC[i][k] = C[i][k] + A[i][j]*B[j][k];
}
}
int main()
{
int A[max][max],B[max][max], C[max][max], n;
//nhap cap n
printf("Nhap cap n= ");
scanf("%d",&n);
//nhap ma tran A
printf("Nhap vao ma tran A\n");
NhapMaTran(A,n);
//nhap ma tran B
printf("Nhap vao ma tran B\n");
NhapMaTran(B,n);
//In hai ma tran A va B vua nhap
printf("Ma tran A vua nhap\n");
XuatMaTran(A,n);
printf("\nMa tran B vua nhap\n");
XuatMaTran(B,n);
//C=A+B
Tong(A,B,C,n);
printf("\nMa tran C=A+B\n");
XuatMaTran(C,n);
//C=A*B
printf("\nMa tran C=A*B\n");

Tich(A,B,C,n);
XuatMaTran(C,n);
getch();
}
b) Xác định độ phức tạp của đoạn chương trình của câu a)


//Tong hai ma tran A va B luu vao trong ma tran C
void Tong(int A[max][max], int B[max][max], int C[max][max], int n){
for(int i = 0; i{1}
for(int j = 0; j{2}
C[i][j] = A[i][j]+B[i][j];
{3}
}
Lệnh {3} tốn O(1) thời gian.
Vòng lặp {2} thực hiện n lần, mỗi lần O(1). Do đó, vịng lặp {2} tốn O(n).
Vịng lặp {1} lặp n lần, vậy độ phức tạp của giải thuật là:

Phần 2. (2 điểm) - Kiểu dữ liệu trừu tượng cơ bản: Danh sách liên kết


Bài 1. Hãy tổ chức lưu trữ một dãy số nguyên với cấu trúc danh sách liên kết đơn và
thực hiện các yêu cầu sau:
1, Nhập danh sách (Thêm đầu - Thêm cuối)
2, Xuất danh sách ra màn hình
3, Liệt kê các phần tử mang phần tử chẵn.
4, Tìm phần tử có phần tử nhỏ nhất.
5, Đếm số lượng số nguyên tố có trong danh sách.

6, Thêm phần tử X vào trước phần tử chẵn đầu tiên (X được nhập và từ bàn phím)
7, Thêm phần tử X vào sau phần tử lẻ cuối cùng (X được nhập và từ bàn phím).
8, Xố phần tử nhỏ nhất trong danh sách.
9, Xoá phần tử đứng trước và sau X trong danh sách (X được nhập và từ bàn phím).
10, Tách danh sách hiện tại thành 2 danh sách sao cho danh sách thứ nhất chứa các
phần tử nguyên tố, danh sách thứ hai chứa các phần tử còn lại
11, Viết chương trình tính giá trị trung bình cộng của các phần tử trong danh sách.
12, Tìm phần tử có giá trị chẵn lớn nhất trong danh sách và xóa (tất cả) các phần tử
này.
13, Tìm phần tử có giá trị bé nhất trong danh sách và xóa (tất cả) phần tử này..
Trả lời:
//Danh sach lien ket don - cac nut luu tru so nguyen
#include<stdio.h>
struct NODE{
int Data;//Truong luu tru du lieu cua phan tu
NODE *Link;//truong lien ket - chua dia chi cua nut tiep theo
};
typedef struct NODE *DSLK;//Khai bao kieu DSLK
1) Nhập danh sách (thêm đầu)
//Ham chen vao dau danh sach 1 nut co truong du lieu la X
void Insert_Begin(DSLK &pHead,int X){
DSLK p;//p - nut moi
p=new NODE;//Xin cap phat dia chi cho nut moi
p->Data=X;//Gan gia tri X cho nut moi
if(pHead==NULL)//Dsnh sach rong
{
p->Link=NULL;//Gan gia tri cho truong dia chi
pHead=p;//Nut moi tro thanh nut dau danh sach
}
else{//Danh sach khong rong

p->Link=pHead;//Gan p vao dau danh sach
pHead=p;//Thay doi dia chi nut dau danh sach
}
}
1) Nhập danh sách (thêm cuối)
//Ham chen vao cuoi danh sach 1 nut co truong du lieu la X
void Insert_End(DSLK &pHead,int X){
DSLK p;//p - nut moi


p=new NODE;//Xin cap phat dia chi cho nut moi
p->Data=X;//Gan gia tri X cho nut moi
p->Link=NULL;//Nut p la nut cuoi cua dslk nen Link=NULL
if(pHead==NULL)//Danh sach rong
pHead=p;//Nut moi tro thanh nut dau danh sach
else{//Danh sach khong rong
//Tim nut cuoi danh sach
DSLK q;
q=pHead;
while (q->Link!=NULL)
q=q->Link;//Dich chuyen q sang nut tiep theo
//Gan p vao sau nut q
q->Link=p;
}
}
1) Nhập danh sách từ bàn phím
//Ham tao lap danh sach voi du lieu cua cac nut nhap vao tu ban phim
//Cac nut duoc chen vao cuoi danh sach
void Creat_List(DSLK &pHead){
int X,tl,i=0;

pHead=NULL;//Khoi tao danh sach rong
do{
printf("Nhap nut thu %d:",++i);//Cau thogn bao
scanf("%d",&X);
Insert_End(pHead,X);//Chen nut X vao dau danh sach
printf("Co nhap tiep hay khong?(0/1):");
scanf("%d",&tl);
}while (tl==1);
}
2) Xuất danh sách ra màn hình:
//Duyet danh sach - Hien thi danh sach ra man hinh
void View_List(DSLK pHead){
DSLK p;
p=pHead;
while(p!=NULL) {
printf("%d ",p->Data);//HIen thi nut p ra man hinh
p=p->Link;//Cho p tro sang nut tiep theo
}
printf("\n");
}
5) Đếm số lượng số nguyên tố có trong danh sách.
//Dem so nut co trong danh sach, so nut duoc tra ve thong qua ten ham
int Demsonut(DSLK pHead){
int dem=0;
DSLK p;
p=pHead;


while(p!=NULL){
dem++;

p=p->Link;
}
return dem;
}
//Xoa nut dau cua danh sach
void Delete_Begin(DSLK &pHead){
if(pHead==NULL)
printf("Danh sach rong!\n");
else{
DSLK p;
p=pHead;//p - nut de xoa
pHead=pHead->Link;//Dich chuyen nut dau danh sach
delete p;//Xoa nut p
}
}
8) Xoá phần tử nhỏ nhất trong danh sách.
9) Xoá phần tử đứng trước và sau X trong danh sách (X được nhập và từ bàn
phím).
//Xóa nut p la nut bat ky co trong danh sach
void Delete_Middle(DSLK pHead,DSLK p){
if(p==pHead){
//Xoa nut dau ds
pHead=pHead->Link;
delete p;//Xoa p
}
else{
//Tim nut q dung truoc nut p
DSLK q;
q=pHead;
while(q->Link!=p)

q=q->Link;
q->Link=p->Link;//Dieu chinh dia chi cua dung truoc
p->Link=NULL;
delete p;//Xoa nut p
}
}
6) Thêm phần tử X vào trước phần tử chẵn đầu tiên (X được nhập và từ bàn
phím)
7) Thêm phần tử X vào sau phần tử lẻ cuối cùng (X được nhập và từ bàn phím).
//Chen 1 nut co du lieu la X vao sau nut p - co trong danh sach
void Insert_Middle(DSLK &pHead,DSLK p,int X){
DSLK q;//Nut moi co truogn du lieu X
q=new NODE;
q->Data=X;
//Chen q vao sau p
q->Link=p->Link;


p->Link=q;
}
4) Tìm phần tử có phần tử nhỏ nhất.
//Ham xac dinh dia chi cua nut thu k co trong danh sach
DSLK Timnutk(DSLK pHead,int k){
int i;
DSLK p;
p=pHead;//tro vao nut dau danh sach
i=1;
while(i!=k && p!=NULL){
p=p->Link;//dich chuyen
i++;

}
return p;
}
int main(){
DSLK pHead,p;
int k;
Creat_List(pHead);
printf("Danh sach sau khi nhap:\n");
View_List(pHead);
printf("Danh sach co %d nut\n",Demsonut(pHead));
printf("Nhap vao gia tri k=");
scanf("%d",&k);
p=Timnutk(pHead,k);
if(p==NULL)
printf("\nKhong co nut thu %d trong danh sach!\n",k);
else{
printf("\nTim duoc nut thu %d trong danh sach!\n",k);
printf("Nut nay co du lieu =%d",p->Data);
}
//Xoa nut thu k
Delete_Middle(pHead,p);
printf("\nDanh sach sau khi xoa nut thu %d:\n",k);
View_List(pHead);
//Chen vao vi tri thu k mot nut X
int X;
printf("Nhap vao vi tri can chen k=");
scanf("%d",&k);
printf("Nhap vao gia tri can chen=");
scanf("%d",&X);
p=Timnutk(pHead,k);

Insert_Middle(pHead,p,X);//Goi ham chen
printf("\nDanh sach sau khi chen:\n",k);


View_List(pHead);
}
Bài 2. Cho 2 danh sách liên kết L1 và L2, gồm các phần tử là số nguyên, thực hiện các
yêu cầu sau:
a, Sắp xếp L1 và L2 tăng dần.
b, Nối L1 và L2 thành L3 sao cho L3 tăng dần.
Bài 3. Một danh sách sinh viên được tổ chức lưu trữ bằng cấu trúc danh sách liên kết
đơn. Mỗi sinh viên có những thơng tin sau:
Masv( kieu ngun),
họ tên (kiểu char[30]),
điểm toán (dt ; kiểu int),
điểm lý (dl ; kiểu int),
điểm hóa (dh; kiểu int)
điểm trung bình – tính dựa vào trung bình cộng của các điểm tốn, lý, hóa.
Viết chương trình thực hiện các cơng việc sau:
1, Viết chương trình nhập vào n sinh viên (n nhập từ bàn phím)
2, Đưa ra màn hình tất cả sinh viên thi lại ít nhất 1 mơn
3, Đưa ra màn hình tất cả sinh viên thi lại cả 3 môn
4, Đưa ra màn hình tất cả sinh viên là sinh viên giỏi (diem trung binh 3 mơn >=8 và
khơng có mơn nào thi lại)
5, Đưa ra màn hình tất cả sinh viên là sinh viên khá (8>diem trung binh 3 môn >=7;
và khơng có mơn nào thi lại)
6, Đưa ra màn hình tất cả sinh viên là sinh viên trung bình và khơng có mơn nào thi
lại)
7, Đưa ra màn hình tất cả sinh viên là sinh viên có điểm trung bình cao nhất
8, Đưa ra màn hình tất cả sinh viên là sinh viên có điểm trung bình thấp nhất

9, Nhập vào Masv nào đó, cho phép tìm kiếm tuần tự theo Masv
10, Xóa bỏ tất cả những sinh viên có điểm trung bình (dtb) =8
Trả lời:
1) Viết chương trình nhập vào n sinh viên (n nhập từ bàn phím).
Bài 4: Thực hiện các bài 1-3 bằng danh sách liên kết đôi
//Khai bao DSLK doi moi nut luu tru 1 so nguyen
#include <stdio.h>
struct NODE{
int Dl;
NODE *Trai;
NODE *Phai;
};
//Quan ly bang nut dau va nut cuoi
typedef struct NODE *DSKEP;
//L - dia chi cua nut ben trai nhat(nut dau ds)
//R - dia chi cua nut ben phai nhat(nut cuoi ds)
//Ham chen dau danh sach
void Insert_Begin(DSKEP &L,DSKEP &R,int X){
DSKEP p;


p=new NODE;
p->Dl=X;
p->Trai=NULL;
p->Phai=NULL;
if(L==NULL && R==NULL)//Ds rong
{
L=p;
R=p;
}

else{//Ds khong rong, p duoc gan vao dau ds
L->Trai=p;
p->Phai=L;
L=p;//Chinh dia chi nut dau ds
}
}
//Ham chen cuoi danh sach
void Insert_End(DSKEP &L,DSKEP &R,int X){
DSKEP p;
p=new NODE;
p->Dl=X;
p->Trai=NULL;
p->Phai=NULL;
if(L==NULL&&R==NULL)//Ds rong
L=R=p;
else{//Ds khong rong, p duoc gan vao cuoi ds
R->Phai=p;
p->Trai=R;
R=p;//Chinh dia chi nut cuoi ds
}
}
//Tao danh sach, du lieu nhap vao tu ban phim
void Creat_List(DSKEP &L,DSKEP &R){
int X,i=0,tl;
L=R=NULL;//Khoi tao danh sach rong
do{
printf("Nhap nut thu %d:",++i);
scanf("%d",&X);
//Insert_Begin(L,R,X);
Insert_End(L,R,X);

printf("Co tiep tuc khong?(0/1):");
scanf("%d",&tl);
}while(tl==1);
}
void Duyet(DSKEP L,DSKEP R){
DSKEP p;
p=L;


while(p!=NULL){
printf("%d ",p->Dl);
p=p->Phai;
}
printf("\n");
}
//ham dem so nut trong danh sach
int Demsonut(DSKEP L,DSKEP R){
int dem=0;
DSKEP p;
p=L;
while(p!=NULL){
dem++;
p=p->Phai;//Dich chuyen p sang nut ke tiep
}
return dem;
}
//ham tim nut thu k co trong danh sach
DSKEP Timk(DSKEP L,DSKEP R,int k){
DSKEP p;
int i;

p=L;i=1;
while(p!=NULL && i!=k){
i++;p=p->Phai;
}
return p;
}
//Chen vao sau nut thu k mot nut moi co truong du lieu la X
void Insert_Middle(DSKEP &L,DSKEP &R, int k,int X){
DSKEP p,q,r;
p=Timk(L,R,k);//p- luu dia chi cua nut thu k
q=new NODE;//q- la nut moi se chen vao ds
q->Dl=X;
if(p==NULL)
printf("Khong tim thay vi tri nut can chen!");
else{
//Chen q vao sau p
r=p->Phai;//r- la nut sau p
r->Trai=q;
q->Phai=r;//q->Phai=p->Phai
p->Phai=q;
q->Trai=p;
}
}
//Xoa mot nut o vi tri thu k
void Delete(DSKEP &L,DSKEP &R,int k){
DSKEP p,q,r;
p=Timk(L,R,k);//Tim dia chi nut can xoa


if(p==NULL)

printf("Khong co nut can xoa!");
else
if(p==L){//Nut can xoa la nut dau danh sach
L=L->Phai;//Chinh dia chi nut dau
L->Trai=NULL;//Dam bao L luon la nut danh ds
delete p;//Xoa nut p
}
else
if(p==R){//Nut can xoa la nut cuoi ds
R=R->Trai;//Chinh dia chi nut cuoi
R->Phai=NULL;
delete p;//Xoa nut p
}
else{//Nut can xoa la nut giua danh sach
q=p->Trai;//q la nut truoc p
r=p->Phai;//r la nut sau p
q->Phai=r;
r->Trai=q;
delete p;
}
}
//Sap xep danh sach theo thu tu tang dan
void Sapxep(DSKEP &L,DSKEP &R){
DSKEP p,q;
int tg;
for(p=L;p->Phai!=NULL;p=p->Phai)
for(q=p->Phai;q!=NULL;q=q->Phai)
if(p->Dl>q->Dl){
tg=p->Dl;
p->Dl=q->Dl;

q->Dl=tg;
}
}
int main(){
DSKEP L,R,p;
int k,X;
printf("Nhap du lieu cho danh sach:\n");
Creat_List(L,R);
printf("Danh sach vua nhap:\n");
Duyet(L,R);
printf("Danh sach co %d nut!\n",Demsonut(L,R));
Sapxep(L,R);
printf("Danh sach sau khi sap xep tang dan:\n");
Duyet(L,R);
}

Phần 3. (2 điểm) - Kiểu dữ liệu trừu tượng cơ bản: Stack, Queue
Bài 1: Cho một stack được hiện thực trên cơ sở mảng có tình trạng như sau:
0 1
2 3 4 5 6 7 8 9
Thêm vào
Đưa ra


I

T

Top
Hãy thực hiện một chuỗi các thao tác sau:

ĐAI *H ** OCT* ** I N**
Trong đó, các chữ cái tượng trưng thao tác PUSH – đẩy phần tử vào stack, dấu
* tượng trưng cho thao tác POP và in ra màn hình.
Hỏi: Sau khi kết thúc chuỗi thao tác trên:
a) Kết quả in ra màn hình như thế nào?
b) Tình trạng của stack như thế nào ? (Vẽ minh họa cụ thể)
Trả lời:
Khái niệm:
- Stack (ngăn xếp, bộ xếp chồng) là một cấu trúc dữ liệu trừu tượng hoạt động theo
nguyên lý “vào sau – ra trước” (Last In First Out – LIFO)
- Stack có 2 phép tốn cơ bản: PUSH và POP
+ PUSH bổ sung 1 phần tử vào đỉnh (top) của ngăn xếp, tức là sau các phần tử đã có
trong ngăn xếp.
+ POP là giải phóng và trả về phần tử đang đứng ở đỉnh của ngăn xếp.
- Trong ngăn xếp, các đối tượng có thể được thêm vào stack bất kỳ lúc nào nhưng
chỉ có đối tượng thêm vào sau cùng mới được phép lấy ra khỏi stack.

ĐAI*H**OCT***IN**
Bước
1
2
3
4
5
6
7
8
9
10
11

12
13
14
15
16
17

Ký tự đọc
được
Đ
A
I
*
H
*
*
O
C
T
*
*
*
I
N
*
*

Stack
(LIFO)
Đ

ĐA
ĐAI
ĐA
ĐAH
ĐA
Đ
ĐO
ĐOC
ĐOCT
ĐOC
ĐO
Đ
ĐI
ĐIN
ĐI
Đ

Output

I
I
IH
IHA
IHA
IHA
IHA
IHAT
IHATC
IHATCO
IHATCO

IHATCO
IHATCON
IHATCONI

Giải thích
Đẩy chữ cái vào stack (PUSH)
Đẩy chữ cái vào stack (PUSH)
Đẩy chữ cái vào stack (PUSH)
Lấy chữ cái ra màn hình (POP)
Đẩy chữ cái vào stack (PUSH)
Lấy chữ cái ra màn hình (POP)
Lấy chữ cái ra màn hình (POP)
Đẩy chữ cái vào stack (PUSH)
Đẩy chữ cái vào stack (PUSH)
Đẩy chữ cái vào stack (PUSH)
Lấy chữ cái ra màn hình (POP)
Lấy chữ cái ra màn hình (POP)
Lấy chữ cái ra màn hình (POP)
Đẩy chữ cái vào stack (PUSH)
Đẩy chữ cái vào stack (PUSH)
Lấy chữ cái ra màn hình (POP)
Lấy chữ cái ra màn hình (POP)

Kết quả: I H A T C O N I
a) Kết quả in ra màn hình là chuỗi ký tự: I H A T C O N I
b) Tình trạng của stack: Đang còn lưu trữ 1 ký tự Đ
Bài 2:


Cho một queue nối vòng được hiện thực trên cơ sở mảng có tình trạng như sau:

Thêm vào
Đưa ra

Hãy thực hiện một chuỗi các thao tác sau:
EAS*Y** QUE * ** ST** *I * ON
Trong đó, các chữ cái tượng trưng thao tác InsQueue – đưa phần tử vào hàng
đợi, dấu * tượng trưng cho thao tác deQueue và in ra màn hình.
Hỏi: Sau khi kết thúc chuỗi thao tác trên:
a) Kết quả in ra màn hình?
b) Tình trạng của queue như thế nào ? (Vẽ minh họa cụ thể)
Trả lời:
Khái niệm:
- Queue (hàng đợi) là một cấu trúc dữ liệu trừu tượng dùng để chứa các đối tượng
làm việc theo cơ chế “vào trước – ra trước” (First In First Out – FIFO)
- Trong hàng đợi, các đối tượng có thể được thêm vào queue bất kỳ lúc nào nhưng
chỉ có đối tượng thêm vào đầu tiên mới được phép lấy ra khỏi queue.
+ Thao tác thêm vào hàng đợi gọi là enqueue
+ Thao tác lấy ra khỏi hàng đợi gọi là dequeue
- Việc thêm vào 1 đối tượng luôn diễn ra ở cuối hàng đợi.
- Một phần tử luôn được lấy ra ở đầu hàng đợi.

EAS*Y**QUE***ST***I*ON
Bước
1
2
3
4
5
6
7

8
9
10
11
12
13
14
15
16
17
18
19
20
21

Ký tự đọc
được
E
A
S
*
Y
*
*
Q
U
E
*
*
*

S
T
*
*
*
I
*
O

Queue
(FIFO)
E
EA
EAS
AS
ASY
SY
Y
YQ
YQU
YQUE
QUE
UE
E
ES
EST
ST
T
I
O


Output

E
E
EA
EAS
EAS
EAS
EAS
EASY
EASYQ
EASYQU
EASYQU
EASYQU
EASYQUE
EASYQUES
EASYQUEST
EASYQUEST
EASYQUESTI
EASYQUESTI

Giải thích
Đẩy chữ cái vào queue (ENQUEUE)
Đẩy chữ cái vào queue (ENQUEUE)
Đẩy chữ cái vào queue (ENQUEUE)
Lấy chữ cái ra màn hình (DEQUEUE)
Đẩy chữ cái vào queue (ENQUEUE)
Lấy chữ cái ra màn hình (DEQUEUE)
Lấy chữ cái ra màn hình (DEQUEUE)

Đẩy chữ cái vào queue (ENQUEUE)
Đẩy chữ cái vào queue (ENQUEUE)
Đẩy chữ cái vào queue (ENQUEUE)
Lấy chữ cái ra màn hình (DEQUEUE)
Lấy chữ cái ra màn hình (DEQUEUE)
Lấy chữ cái ra màn hình (DEQUEUE)
Đẩy chữ cái vào queue (ENQUEUE)
Đẩy chữ cái vào queue (ENQUEUE)
Lấy chữ cái ra màn hình (DEQUEUE)
Lấy chữ cái ra màn hình (DEQUEUE)
Lấy chữ cái ra màn hình (DEQUEUE)
Đẩy chữ cái vào queue (ENQUEUE)
Lấy chữ cái ra màn hình (DEQUEUE)
Đẩy chữ cái vào queue (ENQUEUE)


22

N

ON

EASYQUESTI

Đẩy chữ cái vào queue (ENQUEUE)

Kết quả: E A S Y Q U E S T I
a) Kết quả in ra màn hình là chuỗi ký tự: E A S Y Q U E S T I
b) Tình trạng của queue: Đang còn lưu trữ 2 ký tự O N
Bài 3:

a) Bắt đầu bằng một hàng đợi (queue) rỗng, hãy vẽ minh họa hoạt động của hàng đợi
với cấu trúc là một mảng nối vịng có kích thước 10 khi thực hiện dãy thao tác dưới
đây:
- Đẩy phần tử X vào hàng đợi
- Đẩy phần tử L vào hàng đợi
- Đẩy phần tử R vào hàng đợi
- Lấy phần tử ra khỏi hàng đợi và đưa ra màn hình
- Đẩy phần tử A vào hàng đợi
- Lấy phần tử ra khỏi hàng đợi và đưa ra màn hình
- Lấy phần tử ra khỏi hàng đợi và đưa ra màn hình
- Đẩy phần tử Q vào hàng đợi
b) Kết quả hiển thị ra màn hình như thế nào?
Trả lời:
Khái niệm:
- Queue (hàng đợi) là một cấu trúc dữ liệu trừu tượng dùng để chứa các đối tượng
làm việc theo cơ chế “vào trước – ra trước” (First In First Out – FIFO)
- Trong hàng đợi, các đối tượng có thể được thêm vào queue bất kỳ lúc nào nhưng
chỉ có đối tượng thêm vào đầu tiên mới được phép lấy ra khỏi queue.
+ Thao tác thêm vào hàng đợi gọi là enqueue
+ Thao tác lấy ra khỏi hàng đợi gọi là dequeue
- Việc thêm vào 1 đối tượng luôn diễn ra ở cuối hàng đợi.
- Một phần tử luôn được lấy ra ở đầu hàng đợi.

XLR*A**Q
Bước
1

Ký tự đọc được
X


Queue (FIFO)
X

Output

Giải thích
Đẩy chữ cái vào queue (ENQUEUE)


2
3
4
5
6
7
8

L
R
*
A
*
*
Q

XL
XLR
LR
LRA
RA

A
AQ

X
X
XL
XLR
XLR

Đẩy chữ cái vào queue (ENQUEUE)
Đẩy chữ cái vào queue (ENQUEUE)
Lấy chữ cái ra màn hình (DEQUEUE)
Đẩy chữ cái vào queue (ENQUEUE)
Lấy chữ cái ra màn hình (DEQUEUE)
Lấy chữ cái ra màn hình (DEQUEUE)
Đẩy chữ cái vào queue (ENQUEUE)

Kết quả: X L R
Kết quả in ra màn hình là chuỗi ký tự: X L R
Bài 4: Cho biểu thức P dưới dạng trung tố: P = (a+b^2)*c – (d+e)
(trong đó ^ là ký hiệu chỉ lũy thừa) phép lũy thừa có mức ưu tiên cao nhất)
Hãy áp dụng giải thuật POLISH để biến đổi P sang dạng hậu tố. Nêu rõ tình trạng của
Stack và dạng hình thành của biểu thức hậu tố qua từng bước thực hiện, kèm theo
những thuyết minh cần thiết.
Trả lời:
Quy tắc:
- Nếu là toán hạng: cho ra output
- Nếu là dấu ( : cho vào stack
- Nếu là dấu ) : lấy các toán tử trong stack ra và cho vào output cho đến khi gặp
dấu (. Dấu ( cũng được đưa ra khỏi stack

- Nếu là toán tử:
+ Chừng nào ở đỉnh stack là tốn tử và tốn tử đó có độ ưu tiên lớn hơn hoặc
bằng tốn tử hiện tại thì lấy tốn tử đó ra khỏi stack và cho ra output
+ Đưa toán tử hiện tại vào stack
- Sau khi duyệt hết biểu thức, nếu trong stack cịn phần tử thì lấy hết ra output.

P = (a+b^2)*c - (d+e)
Bước
1
2
3
4
5
6

Token
(
a
+
b
^
2

Stack
(
(
(+
(+
(+^
(+^


Output

7

)

8
9

*
c

*
*

ab2^+
ab2^+c

10

-

-

ab2^+c*

11
12


(
d

-(
-(

ab2^+c*
ab2^+c*d

a
a
ab
ab
ab2
ab2^+

Giải thích
Đẩy dấu ( vào stack
Đưa toán hạng a ra xâu ra
Đẩy toán tử + vào stack
Đưa toán hạng b ra xâu ra
Đẩy toán tử ^ vào stack
Đưa hằng số 2 ra xâu ra
- Phần tử đỉnh S là ^ có ưu tiên cao hơn dấu +.
Đưa toán tử ^ đưa ra xâu ra
- Đưa tốn tử + đưa ra xâu ra
- Hủy ln dấu (
Đẩy toán tử * vào stack
Đưa toán hạng c ra xâu ra
- Phần tử đỉnh stack là * có ưu tiên cao hơn dấu -,

lấy * ghi ra xâu ra.
- Đẩy dấu - vào stack
Đẩy dấu ( vào stack
Đưa toán hạng d ra xâu ra


13
14

+
e

-(+
-(+

15

)

-

16

Hết xâu

ab2^+c*d
ab2^+c*de
ab2^+c*de+
ab2^+c*de+-


Đẩy toán tử + vào stack
Đưa toán hạng e ra xâu ra
Lấy phần tử ở đỉnh Stack là toán tử + ghi ra xâu ra,
đến khi gặp dấu ( thì hủy ln dấu (
Lấy các phần tử từ stack ra xâu ra

Xâu hậu tố nhận được: P = a b 2 ^ + c * d e + Bài 5: Cho biểu thức hậu tố P = a b 2 ^ + c * d e + Áp dụng giải thuật EVAL để tính giá trị của biểu thức hậu tố P theo các giá trị của
biến: a=2, b=5, c=10, d=8, e=12
Trả lời:
Quy tắc:
- Nếu là toán hạng: push vào stack
- Nếu là toán tử: pop 2 toán hạng trong stack ra và tính giá trị của chúng dựa
vào tốn tử này. Sau đó push kết quả đó lại vào stack.
- Phần tử cịn sót lại trong stack sau vịng lặp chính là kết quả của biểu thức.
Với các giá trị biến đã cho, biểu thức hậu tố P có thể viết lại là:

P = 2 5 2 ^ + 10 * 8 12 + Bước
1
2
3

Ký tự đọc được
2
5
2

Stack S

4


^

2 25

5

+

27

6

10

27 10

7

*

270

8
9

8
12

270 8
270 8 12


10

+

270 20

11

-

250

12

Hết xâu

2
2 5
2 5 2

Giải thích
2 là tốn hạng, đẩy 2 vào S
5 là toán hạng, đẩy 5 vào S
2 là hằng số, đẩy 2 vào S
- Lấy các phần tử ra khỏi S (lấy 2, rồi lấy 5)
- Thực hiện phép toán: 5 ^ 2
- Đẩy kết quả 25 vào S
- Lấy các phần tử ra khỏi S (lấy 25, rồi lấy 2)
- Thực hiện phép toán: 2 + 25

- Đẩy kết quả 27 vào S
10 là toán hạng, đẩy 10 vào S
- Lấy 2 phần tử ra khỏi S (lấy 10, rồi lấy 27)
- Thực hiện phép toán: 27 * 10
- Đẩy kết quả 270 vào S
8 là toán hạng, đẩy 8 vào S
12 là toán hạng, đẩy 12 vào S
- Lấy 2 phần tử ra khỏi S (lấy 12, rồi lấy 8)
- Thực hiện phép toán: 8 + 12
- Đẩy kết quả 20 vào S
- Lấy 2 phần tử ra khỏi S (lấy 20, rồi lấy 270)
- Thực hiện phép toán: 270 - 20
- Đẩy kết quả 250 vào S

Kết quả của biểu thức hậu tố tính theo giải thuật
EVAL là 250
Phần 4. (2 điểm) – Cấu trúc cây


Bài 1: Phép duyệt theo thứ tự trước của một cây nhị phân tạo ra: A B D C E G F và
phép duyệt thứ tự giữa tạo ra: D B A E G C F.
a) Hãy dựng cây nhị phân này và nêu phương pháp dựng.
b) Hãy duyệt cây nhị phân dựng được ở câu a) theo thứ tự sau
Trả lời:
a) Dựng cây nhị phân

* Nguyên tắc:
+ Đối với phép duyệt theo thứ tự trước (NLR: Node Left Right)
• Thăm gốc.
• Thăm các nút của cây con trái theo thứ tự trước.

• Thăm các nút của cây con phải theo thứ tự trước.
+ Đối với phép duyệt theo thứ tự giữa (LNR: Left Node Right)
• Thăm các nút của cây con trái theo thứ tự giữa.
• Thăm gốc.
• Thăm các nút của cây con phải theo thứ tự giữa.
+ Đối với phép duyệt theo thứ tự sau (LRN: Left Right Node)
• Thăm các nút của cây con trái theo thứ tự sau
• Thăm các nút của cây con phải theo thứ tự sau
• Thăm gốc
- Theo phép duyệt trước, ta xác định được gốc là A.
- Theo phép duyệt giữa, ta xác định được cây có 2 nhánh lớn, nhánh bên trái có D, B
và nhánh bên phải có E, G, C và F.
+ Đối với nhánh bên trái, theo phép duyệt trước, ta xác định được nút nhánh là B và
nút lá là D.
+ Đối với nhánh bên phải, theo phép duyệt trước, ta xác định được 2 nhánh con có
gốc là C, nhánh bên trái nhánh con là E, G (nút nhánh là G và nút lá là E) và nhánh
bên phải nhánh con có nút lá là F.
b) Hãy duyệt cây nhị phân dựng được ở câu a) theo thứ tự sau (LRN: Left Right
Node)
• Thăm các nút của cây con trái theo thứ tự sau
• Thăm các nút của cây con phải theo thứ tự sau
• Thăm gốc
D BGE FCA


Bài 2: a) Phép duyệt theo thứ tự sau của một cây nhị phân tạo ra: P S Q N T R O M và
phép duyệt thứ tự giữa tạo ra: P N S Q M R T O. Hãy dựng cây nhị phân này và nêu
phương pháp dựng.
b) Hãy duyệt cây nhị phân dựng được ở câu a) theo thứ tự trước
Trả lời:

a) Dựng cây nhị phân
- Theo phép duyệt sau, ta xác định được gốc là M.
- Theo phép duyệt giữa, ta xác định được cây có 2 nhánh lớn, nhánh bên trái có P, N,
S, Q và nhánh bên phải có R, T, và O.
+ Đối với nhánh bên trái, theo phép duyệt sau, ta xác định được 2 nhánh con có gốc
là Q, nhánh bên trái nhánh con có nút lá P và nhánh bên phải là N, S (nút nhánh là N
và nút lá là S).
+ Đối với nhánh bên phải, theo phép duyệt giữa, ta xác định được 1 nhánh con O, R
và T.

b) Hãy duyệt cây nhị phân dựng được ở câu a) theo thứ tự trước (NLR: Node
Left Right)
MQPNSORT

Bài 3: a) Viết khai báo biểu diễn một cây nhị phân bằng phương pháp lưu trữ móc nối,
trong đó mỗi nút lưu trữ một số nguyên.
b) Viết hàm đệ quy đếm số nút lá của một cây nhị phân với khai báo ở câu a).
c) Viết hàm đệ quy đếm số nút của một cây nhị phân với khai báo ở câu a).
d) Viết hàm đệ quy tổng giá trị của các nút có trên cây được khai báo ở câu a).
e) Viết hàm đệ quy tổng giá trị của các nút có giá trị dương trên cây nhị phân được
khai báo ở câu a).
f) ….
Trả lời:
a) Viết khai báo biểu diễn một cây nhị phân bằng phương pháp lưu trữ móc nối, trong
đó mỗi nút lưu trữ một số nguyên.
Class BSTNode {
int Data;
BSTNode pLeft; //con trỏ đến nút con trái
BSTNode pRight; //con trỏ đến nút con phải



};
BSTNode root = NULL; //gốc của cây

Bài 4: a) Minh họa giải thuật dựng cây nhị phân tìm kiếm với dãy khóa nhập vào theo
thứ tự như sau:
18

13

15

12

20

11

30

19

28

14

b) Sau đó, nếu lần lượt thực hiện các thao tác sau trên cây dựng được ở câu a)
- Thêm vào nút có giá trị 50
- Hủy nút có giá trị 20
thì cây sẽ thay đổi như thế nào trong từng bước? Vẽ câyminh họa (nêu rõ phương

pháp hủy khi nút có cả 2 cây con trái và phải).
Trả lời:
a) Minh họa giải thuật dựng cây nhị phân tìm kiếm
Định nghĩa: Cây nhị phân tìm kiếm là cây nhị phân, sao cho
- Mỗi nút có một khóa duy nhất.
- Mọi nút p của cây đều thỏa mãn tính chất:
- Tất cả các nút thuộc cây con trái (p->pLeft) đều có giá trị khóa nhỏ hơn giá trị khóa
của p
- Tất cả các nút thuộc cây con phải (p->pRight) đều có giá trị khóa lớn hơn giá trị khóa
của p
- Tức là: mọi cây con trái, phải của mỗi nút đều là BST
Minh họa giải thuật:
1. Khởi tạo cây (init)


Khởi tạo node: cấp phát bộ nhớ cho 1 node, truyền data cần lưu trữ, gán pLeft
= pRight = NULL.



Khởi tạo cây: khởi tạo cây và gán root = NULL.

struct NODE
{
int data;
NODE* pLeft;


NODE* pRight;
};


NODE* CreateNode(int x)
{
NODE* p = new NODE();
p->data = x;
p->pLeft = p->pRight = NULL;
return p;
}
2. Chèn (insertion)
Chèn node chứa dữ liệu vào cây có gốc là root và trả về địa chỉ node mới chèn, việc
chèn dữ liệu phải dựa trên đặc điểm của cây nhị phân tìm kiếm.
1. Tìm vị trí node cần chèn
NODE* FindInsert(NODE* root, int x)
{
if (root == NULL)
{
return NULL;
}
NODE* p = root;
NODE* f = p;
while (p != NULL)
{
f = p;
if (p->data > x)


{
p = p->pLeft;
}
else

{
p = p->pRight;
}
}
return f;
}
2. Chèn node
void InsertNode(NODE* &root, int x)
{
NODE* n = CreateNode(x);
if (root == NULL)
{
root = n;
return;
}
else
{
NODE* f = FindInsert(root, x);
if (f != NULL)
{
if (f->data > x)


{
f->pLeft = n;
}
else
{
f->pRight = n;
}

}
}
}
3. Tạo cây nhị phân tìm kiếm
void CreateTree(NODE* &root, int a[], int n)
{
for (int i = 0; i < n; i++)
{
InsertNode(root, a[i]);
}
}

b) Sau đó, nếu lần lượt thực hiện các thao tác sau trên cây dựng được ở câu a)
- Thêm vào nút có giá trị 50
- Hủy nút có giá trị 20
thì cây sẽ thay đổi như thế nào trong từng bước?


- Thêm vào nút có giá trị 50

- Hủy nút có giá trị 20 (nêu rõ phương pháp hủy khi nút có cả 2 cây con trái và phải)





Khơng thể hủy trực tiếp do X có đủ 2 con mà phải Hủy gián tiếp:
Thay vì hủy X = 20, ta sẽ tìm một phần tử thế mạng Y. Phần tử này có tối đa một con
(Y = 28 thỏa mãn điều kiện).
Thông tin lưu tại Y sẽ được chuyển lên lưu tại X.

Sau đó, nút bị hủy thật sự sẽ là Y.

Bài 5: a) Dựng cây biểu diễn biểu thức:a*(b-c) + (d+e)/f
b) Hãy duyệt cây trên theo thứ tự trước, giữa, sau. Nhận xét về thứ tự duyệt này.


Bài 6: a) Viết khai báo biểu diễn một cây nhị phân tìm kiếm bằng phương pháp lưu trữ
móc nối, trong đó mỗi nút lưu trữ một số nguyên.
b) Viết thủ tục bổ sung giá trị x vào cây nhị phân tìm kiếm có gốc được trỏ bởi con trỏ
T.
c) …..

Phần 5. (2 điểm) –Bài tốn sắp xếp và tìm kiếm


Bài 1: a) Mơ tả thuật tốn sắp xếp chọn (Selection Sort)(/Sắp xếp chèn/sắp xếp nổi
bọt) để sắp một dãy theo thứ tự tăng dần. b) Trình bày các bước của thuật toán với dãy
số sau: 5, 15, 12, 2, 10, 12, 9, 1, 9, 3, 2, 3.
Trả lời:
a) Sắp xếp chọn (Selection Sort)
Chọn phần tử nhỏ nhất trong n phần tử ban đầu, đưa phần tử này về vị trí đúng là
đầu tiên của dãy hiện hành. Sau đó, khơng quan tâm đến nó nữa, xem dãy hiện hành
chỉ là n-1 phần tử của dãy ban đầu, bắt đầu từ vị trí thứ 2.
Lặp lại q trình trên cho dãy hiện hành đến khi chỉ còn 1 phần tử.
Dãy ban đầu có n phần tử, vậy tóm tắt ý tưởng thuật toán là thực hiện n-1 lượt việc
đưa phần tử nhỏ nhất trong dãy hiện hành về vị trí đúng ở đầu dãy.
Các bước tiến hành:
B1: i=1
B2: Tìm phần tử a[min] nhỏ nhất trong dãy hiện hành từ a[i] đến a[n]
B3: Hốn vị a[min] và a[i]

B4: Nếu i<=n-1 thì i=i+1; Lặp lại bước 2. Ngược lại: Dừng. n-1 phần tử đã nằm
đúng vị trí.
Khó
a
Bước
Ban đầu
Bước 1
Bước 2
Bước 3
Bước 4
Bước 5
Bước 6
Bước 7
Bước 8
Bước 9
Bước 10
Bước 11
Kết quả

a[
1]

a[
2]

a[
3]

a[
4]


a[
5]

a[
6]

a[
7]

a[
8]

a[
9]

a[1
0]

a[1
1]

a[1
2]

5
1

15
15

2

12
12
12
2

2
2
15
15
3

10
10
10
10
10
3

12
12
12
12
12
12
5

9
9

9
9
9
9
9
9

1
5
5
5
5
5
12
12
9

9
9
9
9
9
9
9
9
12
10

3
3

3
3
15
15
15
15
15
15
12

1

2

2

3

3

5

9

9

10

12


2
2
2
12
12
12
12
12
12
12
15
12
12

3
3
3
3
3
10
10
10
10
12
12
15
15

b) Sắp xếp chèn (Insertion Sort)


Giả sử có 1 dãy a1, a2… an, trong đó i phần tử đầu tiên a 1, a2, …. ai-1 đã có thứ tự.
Thuật tốn chèn tìm cách chèn phần tử ai vào vị trí thích hợp của đoạn đã được sắp xếp
để có dãy mới a1, a2, …. ai trở nên có thứ tự. Vị trí này chính là vị trí giữa 2 phần tử a k-1
và ak thỏa mãn ak-1 ai < ak (1 k i)
Các bước tiến hành:
B1: i=2 (giả sử có đoạn a[1] đã được sắp xếp)
B2: x = a[i]. Tìm vị trí pos thích hợp trong đoạn a[1] đến a[i-1] để chèn a[i] vào
B3: Dời chỗ các phần tử từ a[pos] đến a[i-1] sang phải 1 vị trí để dành chỗ cho
a[i]
B4: a[pos] = x. Có đoạn a[1]…a[i] đã được sắp
B5: i=i+1. Nếu i=n: Lặp lại bước 2, Ngược lại: Dừng.


×