Tất cả các dạng bài tập môn Cấu trúc dữ liệu và giải thuật được biên soạn chi tiết theo từng phần một cách khoa học và dễ hiểu nhất;Đề cương ôn thi cao học công nghệ thông tin tại MTA chi tiết và đầy đủ nhất
Trang 1B ổ sung phần tử vào Stack
Trang 2if F=R then begin
write(‘TRÀN’);
returnend
4. {Chỉnh lại con trỏ F sau phép loại bỏ}
Trang 3Cho trước hai ma trận thưa A và B theo cấu trúc Matrix Viết thủ tục tính T = A+B
Procedure TongMatran(A: Matrix; B: Matrix; Var T: Matrix);
T.C[T.spt]:=A.C[ka];
T.D[T.spt]:=A.D[ka] + B.D[kb];
end;
endelse if (B.C[kb] <> A.C[ka]) begin
Trang 4}
Trang 5Đầu vào: số nguyên không âm n hệ cơ số 10, hệ cơ số a
Đầu ra: in ra số nguyên n ở hệ cơ số a
void Chuyen(int n, int a)
while (Pop(s,val))//Hàm pop lấy ra phần tử trên đỉnh của stack s và gán giá trị vào val Giá trị trả về
của hàm là true nếu còn phần tử để lấy ra trái lại là false
Chuy ển biểu thức trung tố không đầy đủ dấu ngoặc về dạng hậu tố
Đầu vào: H là biểu thức trung tố không đầy đủ dấu ngoặc
Đầu ra: N biểu thức ở dạng hậu tố của H
1 Input H; Khởi tạo ngăn xếp S
2 Priority[‘('] < Priority['+'] = Priority['-'] < Priority['*']= Priority['/']
Trang 6Pop( S, a );
Thêm a vào sau N;
}Push(S, x); break;
5 While not Empty(S) Do {
Dùng ngăn xếp tính giá trị biểu thức số học dạng hậu tố
Đầu vào: Chuỗi H là biểu thức số học ở dạng hậu tố
Đầu ra: Kết quả của biểu thức
1 Input H; Khởi tạo ngăn xếp S
2 For each x in H
Case x of
case toán hạng:
Trang 73 pop(S, Ketqua); Output Ketqua;
Áp dụng tính giá trị biểu thức (Dùng ngăn xếp tính giá trị biểu thức số học dạng hậu tố)
6 10 8 / 24 10 6 / 2 /
- 6 2 Đọc -; lấy 8 và 10 ra khỏi ngăn xếp; tính 10 – 8 =2; đẩy 2 vào ngăn xếp/ 3 Đọc /; lấy 6 và 2 ra khỏi ngăn xếp; Tính 6/2=3; Đẩy 3 vào ngăn xếp
- 3 24 4 Đọc -; Lấy 10 và 6 ra khỏi ngăn xếp; Tính 10-6=4; Đẩy 4 vào ngăn xếp./ 3 8 Đọc /; Lấy 24 và 4 ra khỏi ngăn xếp; Tính 24/4=8; Đẩy 8 vào ngăn xếp
/ 3 4 Đọc /; Lấy 8 và 2 ra khỏi ngăn xếp; Tính 8/2=4; Đẩy 4 vào ngăn xếp;
- -1 Đọc -; Lấy 3 và 4 ra khỏi ngăn xếp; Tính 3-4=-1; Đẩy -1 vào ngăn xếp
Bài t ập 5
Tính giá trị biểu thức trung tố không đầy đủ dấu ngoặc
Đầu vào: Chuỗi H là biểu thức trung tố không đầy đủ dấu ngoặc
Đầu ra: Kết quả của biểu thức
1 Input H; Khởi tạo ngăn xếp toán tử St := ∅; ngăn xếp toán hạng Sh := ∅;
Trang 8case Ngoặc mở ‘(‘: Push (St, x); break;
case Toán tử { +,- ,*, / }:
While (St≠∅ & Pr[x]≤ Pr[Top(S)])Do {
Pop( St, t ); Pop(Sh, b); Pop(Sh, a);
Trang 9Bài t ập 6
Tính giá trị biểu thức trung tố không có dấu ngoặc
Đầu vào: H là biểu thức trung tố không có dấu ngoặc
Đầu ra: Kết quả của biểu thức H
1 Input H; Khởi tạo ngăn xếp toán tử St := ∅; ngăn xếp toán hạng Sh := ∅;
While (St≠∅ & Pr[x]≤ Pr[Top(S]) Do {
Pop( St, t ); Pop(Sh, b); Pop(Sh, a);
Trang 10Bài T ập 7
Chuyển biểu thức trung tố không có dấu ngoặc sang dạng hậu tố
Đầu vào: H là biểu thức trung tố không có dấu ngoặc
Đầu ra: Biểu thức N ở dạng hậu tố của H
1 Input H; Khởi tạo ngăn xếp S
2 Priority['+'] = Priority['-'] < Priority['*']= Priority['/']
5 While not Empty(S) Do {
Trang 11Đầu vào: H là biểu thức trung tố đầy đủ dấu ngoặc
Đầu ra: Kết quả của H
1 Input H; Khởi tạo ngăn xếp S
3 pop(S, Ketqua); Output Ketqua;
Áp dụng tính giá trị của biểu thức
((3 + ((2 + 4)/2))*(8 + ((3 - 1)*2))) Dùng ngăn x ếp tính giá trị của biểu thức ở dạng trung tố đầy đủ dấu ngoặc
Trang 12Bổ sung một nút vào danh sách nối đơn
Cấu trúc dữ liệu mã Pascal:
typedef struct node node;
typedef node *list;
typedef struct node
{L là danh sách cần thêm Thủ tục bổ sung vào sau nút trỏ bởi M một nút mới mà trường info của nó sẽ
có giá trị lấy từ ô nhớ có địa chỉ X}
1 {Tạo nút mới}
NutMoi <=AVAIL;
NutMoi->info = X;
Trang 132 {Thực hiện bổ sung, nếu danh sách rỗng thì bổ sung nút mới vào thành nút đầu tiên, nếu danh sách không rỗng thì nắm lấy M và bổ sung nút mới vào sau nút đó}
Trang 14While (P->next!=M) P=P->next;
4 {Loại bỏ nút trỏ bởi M}
Trang 16Xóa tất cả các phần tử có giá trị C trong danh sách liên kết đơn
Cấu trúc dữ liệu mã Pascal:
list = ^node;
node = record
Trang 17val: DataType;
next: list;
End;
Đầu vào: Danh sách L, giá trị C
Đầu ra: Hàm Xoa xóa tất cả các phần tử trong danh sách L có giá trị C
void Xoa(list *L, int C)
P1->next = P2->next;
P2 = P2->next;
}free(temp);
}else {
P1=P2;
P2 = P2->next;
}}
}
Bài t ập 2
Thêm vào sau mỗi phần tử có giá trị A một phần tử có giá trị B (A≠B, A=B)
Đầu vào: Danh sách L, các giá trị A và B
Đầu ra: Danh sách L sau khi đã chèn các phần tử có giá trị B vào sau các phần tử có giá trị A
void Them(list L, DataType A, DataType B)
Trang 18P->next = nutmoi;
P = nutmoi->next; cho P b ằng node mới next để tránh vòng lặp vô hạn kiểm tra giá trị P
}else {
P = P->next;
}}
}
Bài T ập 3
Tìm kiếm phần tử trong danh sách liên kết đơn
Đầu vào: Danh sách liên kết đơn L, giá trị C
Đầu ra: Hàm Tim trả về phần tử có giá trị C nếu L tồn tại phần tử có giá trị C và trả về NULL nếu L không
tồn tại phần tử nào có giá trị C
node * Tim(list L, DataType C)
Vi ết giải thuật xóa phần tử cuối cùng trong danh sách liên kết đơn.
Đầu vào: Danh sách L
Đầu ra: Danh sách L sau khi loại bỏ nút cuối cùng nếu có
Trang 19Xóa nút đ ầu tiên trong danh sách liên kết đơn
Đầu vào: Danh sách liên kết đơn L
Đầu ra: Danh sách L sau khi xóa nút đầu nếu có
Cho hai tập hợp được lưu trong 2 danh sách liên kết đơn Viết thuật toán xác định giao của hai tập hợp
Đầu vào: Danh sách L1 và L2 lưu 2 tập hợp
Đầu ra: hàm Giao trả về danh sách lưu giao của 2 tập hợp
list * Giao(list L1, list L2)
Trang 20p3->next = nutmoi;
p3 = nutmoi;
}}
Cho hai đa thức lưu ở dạng danh sách liên kết đơn, biết rằng các nút lưu các đơn thức (hạng tử)
c ủa đa thức được lưu trữ trong danh sách theo thứ tự giảm dần của số mũ Viết thuật toán cộng hai đa thức.
Đầu vào: Danh sách A, B lưu đa thức thứ nhất và hai Cấu trúc của danh sách và mỗi nút như trên
Đầu ra: Hàm trả về danh sách lưu đa thức là tổng của hai đa thức
list Add(list A, list B)
Trang 21node *nutmoi =
makenode(heso, p->sm);
//bổ sung nutmoi vào cuối danh sách
enqueue(&C, nutmoi); b ổ sung node mới vào cuối danh sách
}//Ket thuc While
//Danh sách ứng với đa thức A chua hết
Trang 22temp = temp->next;
}temp->next = nutmoi;
}
}
node *makenode(float heso, int sm)
{
struct node *temp;
temp= (struct node*)malloc(sizeof(struct node));
Trang 23{Thủ tục này thực hiện tìm kiếm trên cây nhị phân tìm kiếm, có gốc được trỏ bởi T, nút có giá trị khóa bằng X Nếu tìm kiếm được thỏa thì đưa ra con trỏ q trỏ tới nút đó, nếu tìm kiếm không thỏa thì bổ sung nút mới có khóa là X vào T và đưa ra con trỏ q trỏ tới nút mới đó kèm theo thông báo}
1 {Khởi tạo con trỏ}
Loại bỏ nút trong cây NPTK
Đầu vào: T là địa chỉ của con trỏ trỏ tới nút gốc của cây NPTK và giá trị x của khóa cần xóa
Đầu ra: Nội dung của cây NPTK sau khi đã xóa nút, địa chỉ của con trỏ trỏ tới nút gốc
Trang 26Bài tập 1
Duy ệt cây tiền thứ tự (thứ tự trước)
Cấu trúc một nút biểu diễn bằng Pascal
Trang 29Duyệt cây in ra các nút của cây theo từng mức.
Đầu vào: Con trỏ T trỏ tới nút gốc của cây
Đầu ra: In ra các nút theo từng mức
Trang 30if (T==NULL) {
printf("Cay rong");
}
else {
+ Khởi tạo ngăn xếp s1 lưu các con trỏ của các nút ở một mức lẻ nào đó
+ Khởi tạo ngăn xếp s2 lưu các con trỏ của các nút ở một mức chẵn nào đó
while (vẫn còn lấy được (pop) con trỏ x ra khỏi s1) {
+ In ra thông tin của nút trỏ bởi x
}
else {
while (vẫn còn lấy được con trỏ x ra khỏi s2){
+ In ra các thông tin của nút trỏ bởi x
printf("\n");
}muc++;
}}
}
Bài tập 7
Vi ết thuật toán xác định chiều cao của cây
Trang 31Đầu vào: Con trỏ T trỏ tới nút gốc của cây
Đầu ra: Trả về chiều cao của cây
if (T==NULL) {
return 0;
}
else {
+ Khởi tạo ngăn xếp s1 lưu các con trỏ của các nút ở một mức lẻ nào đó
+ Khởi tạo ngăn xếp s2 lưu các con trỏ của các nút ở một mức chẵn nào đó
}muc++;
}return (muc-1);
Trang 32Đầu ra: Trả về một nút ở mức cao nhất
if (T==NULL) {
return NULL;
}
else {
+ Khởi tạo ngăn xếp s1 lưu các con trỏ của các nút ở một mức lẻ nào đó
+ Khởi tạo ngăn xếp s2 lưu các con trỏ của các nút ở một mức chẵn nào đó
}muc++;
}//trả về con trỏ trỏ tới nút được lấy ra cuối cùng trong s1 hoặc s2return x;
Trang 33+ Khởi tạo ngăn xếp s1 lưu các con trỏ của các nút ở một mức lẻ nào đó
+ Khởi tạo ngăn xếp s2 lưu các con trỏ của các nút ở một mức chẵn nào đó
while (vẫn còn lấy được (pop) con trỏ x ra khỏi s1) {
if (x->left ==NULL && x->right==NULL)
}}
else {
while (vẫn còn lấy được con trỏ x ra khỏi s2) {
if (x->left ==NULL && x->right==NULL)
}}
muc++;
Trang 34}
Bài 10
Thu ật toán chuyển một biểu thức số học gồm các phép toán +, -, *, / được cho ở dạng trung tố có đầy đủ dấu ngoặc vào cây nhị phân
Đầu vào: Biểu thức số học H
Đầu ra: con trỏ root trỏ tới gốc của cây nhị phân
+ Khởi tạo ngăn xếp S các con trỏ kiểu node
+ node * root = NULL;//Con trỏ trỏ tối nút gốc của cây nhị phân
for (int i=0;i<|H|;i++)
Viết thuật toán chuyển biểu thức hậu tố vào cây nhị phân
Đầu vào: Chuỗi H là biểu thức số học ở dạng hậu tố
Đầu ra: Con trỏ root trỏ tới gốc của cây nhị phân biểu diễn H
1 Khởi tạo ngăn xếp S các con trỏ kiểu node
2 for (int i=0;i<|H|;i++)
{
switch (Hi)
Trang 35pop(S, a); pop(S, b);
node *c = new node;
Các bước của Huffman Tĩnh
[b1] Duyệt file => Lập bảng thống kê số lần xuất hiện của mỗi loại ký tự
[b2] Phát sinh cây Huffman dựa vào bảng thống kê
[b3] Từ cây Huffman phát sinh bảng mã bit cho các ký tự
[b4] Duyệt file => Thay thế các ký tự bằng mã bit tương ứng
[b5] Lưu lại thông tin của cây Huffman dùng để giải nén
Trang 36Tạo cây Huffman
Mô tả cây Huffman: mã Huffman được biểu diễn bằng 1 cây nhị phân
Tính chất của cây Huffman
Nhánh trái tương ứng với mã hoá bit ‘0’; nhánh phải tương ứng với mã hoá bit ‘1’
Các nút có tần số thấp nằm ở xa gốc mã bit dài
Các nút có tần số cao nằm ở gần gốc mã bit ngắn
Số nút của cây: (2n-1)
Cấu trúc nút của cây Huffman
Cấu trúc nút của cây nhị phân Huffman – Pascal
Trang 37Bài t ập 1
Cho tập n ký tự được lưu trữ trong mảng ký tự X và số lần xuất hiện của chúng được lưu trữ trong m ảng S Viết thuật toán xây dựng cây nhị phân Huffman
Đầu vào: Mảng ký tự X[0 n-1], mảng số lần xuất hiện của các ký tự S[0…n-1]
Đầu ra: Trả về con trỏ trỏ tới nút gốc của cây Huffman
node** C = new node* [n];
1 for (int i=0;i<n;i++) {
C[i]= new node;
b) node* M = new node;
c) M->ch = NULL; //Chú ý nếu khai là: char ch thì bỏ qua lệnh này
Trang 40Bài tập 2
Cho cây nhị phân Huffman,viết thủ tục in ra bộ mã của các ký tự dựa vào cây nhị phân Huffman.
void HCode(tree T, string code)
Trang 41f, 11
b, 10 e, 12 s, 14
NULL,26 NULL,21
1 0
1 0
Đầu ra: Chuỗi ký tự giải mã str ứng với chuỗi bits
1 Khởi tạo chuỗi ký tự str trống;
temp = temp->left;
}else{
temp = temp->right;
}i++;
}
+ Bổ sung ký tự trỏ bởi temp->ch vào cuối str;
}
4 Output(str);
Trang 42f, 11
b, 10 e, 12 s, 14
NULL,26 NULL,21
1 0
1 0
Áp d ụng cho một cây Huffman cho trước và chuỗi bits: 000100100111011010
Chu ỗi ký tự giải mã là:bccuse
Đ TH Ồ Ị THU ẬT TOÁN TÌM KIẾM THEO CHIỀU SÂU (DEPTH FIRST SEARCH)
Trang 43THU ẬT TOÁN TÌM KIẾM THEO CHIỀU RỘNG (BREADTH FIRST SEARCH)
Trang 44Xây d ựng cây khung bằng các thuật toán tìm kiếm trên đồ thị
Thuật toán 1 – Duyệt sâu
Thuật toán 2 – Duyệt rộng
Trang 45CÂY KHUNG NH Ỏ NHẤT
Cho G = (V, E) là đồ thị vô hướng liên thông có trọng số, với một cây khung T của G, ta gọi trọng số của cây T là tổng trọng số các cạnh trong T Bài toán đặt ra là trong số các cây khung của G, chỉ ra cây khung
có trọng số nhỏ nhất, cây khung như vậy được gọi là cây khung (hay cây bao trùm) nhỏ nhất của đồ thị,
và bài toán đó gọi là bài toán cây khung nhỏ nhất
BÀI TOÁN CÂY KHUNG NHỎ NHẤT THUẬT TOÁN PRIM
Ví d ụ
Ví dụ: Đồ thị G vô hướng được cho bởi danh sách cạnh:
(A, B, 7), (A, D, 5), (B, C, 8), (B, D, 9), (B, E, 7), (C, E, 5), (D, E, 15), (D, F, 6), (E, F, 8), (E, G, 9), (F, G, 11)Xây dựng cây khung nhỏ nhất theo thuật toán Prim;
Trang 46Vậy cây khung nhỏ nhất bao gồm các cạnh (D,A, 5), (D, F, 6), (A, B, 7), (B,E, 7), (E,C, 5), (E,G, 9), Tổng trọng số của cây là 39
Thu ật toán Kruskal
Mô tả Thuật toán Kruskal
Trang 48Tìm đường đi qua ít cung nhất từ a tới z
K ết quả chạy thuật toán
Trang 50Các bước chạy thuật toán
Đường đi từ a->d là: d <- b <- c <- a; độ dài là 8
Bài toán 3 Cho đồ thị vô hướng, liên thông, có trọng số G = {V, E} và hai đỉnh Hãy tìm đường đi ngắn nhất từ
u tới tất cả các đỉnh còn lại.
Cho đồ thị với danh sách cạnh sau, tìm đường đi ngắn nhất từ a tới z
Trang 51a, b, 5 c, d, 9 d, z, 8
Các bước chạy thuật toán
Đường đi từ a->b là: b <- c <- a; độ dài là 3
Đường đi từ a->c là: c <- a ; độ dài là 2
Đường đi từ a->d là: d <- b <- c <- a; độ dài là 8
Đường đi từ a->e là: e <-d <- b <- c <- a; độ dài là 10
Đường đi từ a->z là: z<-e <-d <- b <- c <- a; độ dài là 13
CÁC THUẬ T TOÁN SẮP XẾP
S ắp xếp chọn
Mô tả thuật toán:
Input: Dãy X(1), X(2), , X(n) các số nguyên và số các phần tử n
Output: Dãy X(1), X(2), , X(n) không giảm;
Tiếp tục thủ tục trên để chọn phần tử X(3), X(4), , X(n-1) thích hợp cho dãy
Mô tả chi tiết:
Đầu vào: Dãy X(1),X(2),…,X(n)
Đầu ra: Dãy X(1),X(2),…,X(n) không giảm
Trang 52Sắp xếp chèn
Bài toán: Sắp xếp mảng số nguyên X(1), X(n) theo thứ tự không giảm
Ý tưởng
Xuất phát từ mảng B(1) là mảng có một phần tử
Giả sử có phần đầu của mảng B(i-1) = <X(1), ,X(i-1)> không giảm (B(i-1) là mảng đã được sắp xếp);
Bước 1: Kiểm tra tới phần tử X(i); Tìm vị trí "thích hợp" của X(i) trong dãy B(i-1) và chèn nó vào đó
Sau bước này, dãy mới B(i) = <X'(1), ,X'(i-1),X'(i)> cũng không giảm;
Bước 2: Lặp lại thủ tục trên với X(i+1), cho đến khi nào i = n;
Input: Dãy X(1), X(2), , X(n)
Output: Dãy X(1), X(2), , X(n) không giảm;
Chi ti ết: Bắt đầu với B(1) = < X(1) >;
Trang 53Thuật toán
Đầu vào: Dãy X(1), X(2),…,X(n)
Đầu ra: Dãy X(1), X(2),…,X(n) đã được sắp xếp không giảm
For i=1 to n -1
for j=n down to i+1
if X(j) < X(j-1) then Đổi chỗ ( X(j), X(j-1) )
Trang 54S ắp xếp phân đoạn/sắp xếp nhanh
Thuật phân đoạn
Sau khi phần tử chốt được chọn giải thuật phân đoạn nên tiến hành như thế nào?
Một giải pháp đơn giản nhất cho vấn đề này là duyệt từ đầu đến cuối lần lượt so sánh các phần tử của danh sách với phần tử chốt Theo cách này, ta phải tiến hành n phép so sánh, ngoài ra còn phải dành n đơn vị bộ nhớ để lưu giữ các giá trị trung gian
Một giải pháp khác được đề nghị là duyệt theo hai đường Một đường từ đầu danh sách, một đường từ cuối danh sách Theo cách này, ta tìm phần tử đầu tiên tính từ trái lớn hơn phần tử chốt và phần tử đầu
Trang 55tiên phía phải nhỏ hơn hoặc bằng phần tử chốt rồi đổi chỗ cho nhau Tiếp tục như vậy cho đến khi hai đường gặp nhau.
Để có thể gọi đệ quy ta xét bài toán phân chia một danh sách con của a: thành hai danh sách
Đầu vào: Mảng X[1 n] số nguyên
Đầu ra: Mảng X sau khi đã sắp xếp không giảm
while (x[i]<=key) do {i:=i+1; if (i=R+1) break;}
while (x[j]>key and j>L) do j:=j-1;
Trang 56Ứng dụng thuật toán sắp xếp dãy:
Trang 57So sánh hai phần tử nhỏ nhất của hai mảng; Đưa phần tử nhỏ hơn ra mảng đích Loại phần tử được chọn này ra khỏi mảng đang chứa nó.
Lặp lại thủ tục này cho đến khi vét hết một trong hai mảng
Chuyển toàn bộ phần đuôi của mảng còn lại ra mảng đích
Chi tiết:
i:=1; j:=1; k:=1;
While (i ≤ m) & (j ≤ n)
a) If X[i] < Y[j] then { Z[k]:=X[i]; inc(i) };
else { Z[k]:=Y[j]; inc(j) };
b) Inc(k);
If i > m then
for t:=j to n do Z[k + t - j] := Y[t];//{Z[k]:=Y[t]; inc(k);}
else for t:=i to m do Z[k+ t - i] := X[t];
So sánh hai phần tử nhỏ nhất của hai phần mảng X và đưa phần tử nhỏ hơn ra mảng đích Z Lướt qua
phần tử được chọn này trong phần mảng đang chứa nó
Lặp lại thủ tục này cho đến khi vét hết một trong hai phần của mảng
Chuyển toàn bộ phần cuối của phần mảng còn lại ra mảng đích
Chi tiết HN2P(X:mảng vào;p,m,n:integer):
else for t:=i to m do {Z[k] := X[t]; inc(k);}
For i:= p to n do X(i) := Z(i);
Thủ tục sắp xếp mảng dựa vào thủ tục hoà nhập
Bài toán: Cho hai mảng X = <X(1), , X(n)>
Cho phép sử dụng thêm mảng Y =<Y(1), , Y(n)> để sắp xếp X
Mô tả thuật toán
ý tưởng: