BÀI TẬP THỰC HÀNH MÔN CẤU TRÚC DỮ LIỆU & GIẢI THUẬT
Khái niệm câu lệnh đặc trưng
Câu lệnh đặc trưng là câu lệnh được thực hiện thường xuyên ít nhất là cũng
như bất kỳ câu lệnh nào trong thuật toán.
Nếu giả thiết thời gian thực hiện mỗi câu lệnh là bị chặn bởi hằng số thì thời
gian tính của thuật toán sẽ cùng cỡ với số lần thực hiện câu lệnh đặc trưng. Do đó
để đánh giá thời gian tính có thể đếm số lần thực hiện câu lệnh đặc trưng.
I. Độ phức tạp của giải thuật:
Bài 1: Sắp xếp nổi bọt
1 // bubble sort
2
int bubbleSort(int a[], int n)
{
3
int i, j,
temp;
4
for (i = (n - 1); i > 0; i )
{
5
for (j = 1; j <= i; j++)
{
6
if (a[j-1] > a[j])
{
7 temp = a[j-1];
8 a[j-1] = a[j];
9 a[j] = temp;
10 }
11 }
12 }
13 }
Ta chọn phép so sánh hai phần tử làm câu lệnh đặc trưng. Tại mỗi vòng lặp
for thứ i, ta phải thực hiện phép so sánh i lần. Do đó tổng các phép so sánh là:
(n – 1) + (n – 2) + … + 2 + 1 = n(n-1)/2
Như vậy độ phức tạp của thuật toán là O( )
Bài 2: Tìm kiếm nhị phân
Ý tưởng của thuật toán: Trong mỗi bước, so sánh phần tử cần tìm với phần tử
nằm ở chính giữa danh sách. Nếu hai phần tử bằng nhau thì phép tìm kiếm thành
công và thuật toán kết thúc. Nếu chúng không bằng nhau thì tùy vào phần tử nào
lớn hơn, thuật toán lặp lại bước so sánh trên với nửa đầu hoặc nửa sau của danh
sách.
Mã giả:
1 // Tim nhi phan
2
Dữ liệu vào: danh sách tăng dần lưu trong mảng A từ phần tử thứ min đến phần tử
thứ max, phần tử cần tìm x
3 Kết quả: thứ tự của x trong A nếu tìm thấy, nếu không trả về NOT_FOUND
4
5
while (min <
max)
6 mid ← ⌊(min+max)/2⌋
7
if x >
A[mid]
8 min ← mid + 1
9 else
10 max ← mid
11
12 if (min ≤ max) and (A[min] = x)
13 return min
14 else
15 return NOT_FOUND
Ta chọn phép so sánh phần tử ở giữa danh sách với x làm câu lệnh đặc trưng.
Dễ thấy sau mỗi bước số phần tử của danh sách giảm đi một nữa nên số lần thực
hiện câu lệnh này sẽ là log(n) trong trường hợp tồi nhất.
Từ đó ta có thể kết luận độ phức tạp của thuật toán này là O(log(n))
Bài 3: Giải thuật Fibonacci
Giải thuật này trả về số thứ n trong dãy số Fibonacci
1
int Fibo(int
n)
{
2 if (n <= 1) return n;
3 else
4 return Fibo(n - 1) + Fibo(n - 2); (*)
5 }
Chọn phép cộng (*) làm câu lệnh đặc trưng. T(n) là số lần thực hiện câu lệnh này.
Dễ thấy:
T(n) = 0 với n <= 1
T(n) = T(n-1) + T(n-2) + 1 với n > 1
Nhận xét: T(n) là hàm tăng theo số mũ. T(n) = O( )
Suy ra: O( ) = O( ) + O( ) + O(1)
Bỏ qua O(1): = + ⇒ = a + 1 ⇒ a = 1.618
Vậy T(n) =
Định lý thợ rút gọn – Áp dụng với một số thuật toán đệ quy
Đối với các thuật toán đệ quy mà công thức đánh giá thuật toán có dạng:
với a >= 1, b > 1, c > 0 là các hằng số thì
• Nếu thì
• Nếu thì
• Nếu a > thì
Ví dụ: Đánh giá độ phức tạp của thuật toán đệ quy sau:
1
int
f(int n)
{
2 if (n > 1)
3 return 8*f(n/2) + 2012; (*)
4 return 0;
5 }
Chọn (*) là câu lệnh đặc trưng. Dễ thấy
T(n) = 0 với n <= 1
T(n) = T(n/2) + 1 với n > 1
Ở đây: a = 1, b = 2, c = 1, k = 0 ⇒ a = b^k ⇒ T(n) = O(logn)
II Giải thuật đệ quy:
Bài 1. Viết chương trình con bằng giải thuật đệ qui để thực hiện các công việc sau:
- Tính n!
- Tính S=1+2+3+…+n
- Tính s=1+3+5+…+(2k+1) với 2k+1<=n
- Đổi số nguyên n hệ 10 sang hệ 2
- Đảo ngược
II. Danh sách
Bài 1. Viết hàm khai báo cac chương trình con cài đặt danh sách mảng. Dùng các
chương trình con này để:
- Chương trình con nhận một dãy các số nguyên nhập từ bàn phím, lưu trữ nó
trong danh sách theo thứ tự nhập vào.
- Viết chương trình con in ra màn hình các phần tử trong danh sách theo thứ tự
của nó trong danh sách.
Bài 2. Viết chương trình con sắp xếp một danh sách chứa các số nguyên, trong các
trường hợp:
- Danh sách được cài đặt bằng mảng(DS đặc)
- Danh sách được cài đặt bằng con trỏ(DS liên kết)
Bài 3. Viết chương trình con tìm kiếm và xóa 1 phần tử trong danh sách liên kết có thứ
tự.
Bài 4. Viết chương trình con đếm số lần xuất hiện của mỗi ký tự trong 1 chuỗi ký tự.
Bài 5. Viết chương trình con đảo ngược 1 danh sách trong cả 2 trường hợp là lưu bằng
mảng và lưu bằng con trỏ.
Bài 6. Viết chương trình con trộn 2 danh sách liên kết chứa các số nguyên theo thứ tự
tăng để được 1 danh sách cũng có thứ tự
Bài 7.Viết chương trình con tách 1 danh sách chứa các số nguyên các phần tử thành 2
danh sách : 1 danh sách gồm các số chẵn còn danh sách kia gồm các số lẻ.
Bài 8. Hãy cài đặt 1 ngăn xếp theo cách dùng con trỏ.
Bài 9. Dùng ngăn xếp để viết chương trình con đổi 1 số thập phân sang số nhị phân.
Bài 10. Cho 1 Queue Q . Hãy viết chương trình con thực hiện các công việc sau:
- Đếm số phần tử của Queue Q
- Xuất nội dung của Queue Q
IV Sắp xếp và tìm kiếm
Bài 1. Viết chương trình nhập vào một danh sách(đặc) có n phần tử, sắp xếp danh
sách đó theo thứ tự tăng dần(sử dụng selection sort)
Bài 2. Viết chương trình nhập vào một danh sách(đặc) có n phần tử, sắp xếp danh
sách đó theo thứ tự tăng dần(sử dụng Insertion sort)
Bài 3. Viết chương trình nhập vào một danh sách(đặc) có n phần tử, sắp xếp danh
sách đó theo thứ tự tăng dần(sử dụng Bubble sort)
Bài 4. Viết chương trình nhập vào một danh sách(đặc) có n phần tử, sắp xếp danh
sách đó theo thứ tự tăng dần(sử dụng Quick sort)
Bài 5. Viết chương trình nhập vào một danh sách(đặc) có n phần tử, nhập vào 1
phần tử có giá trị x. Tìm vị trí xuất hiện đầu tiên của x trong danh sách. Xuất kết
quả nếu tìm thấy, nếu không xuất Not Found.(sử dụng tìm nhị phân)
Bài 6. Viết chương trình nhập vào một danh sách(đặc) có n phần tử, nhập vào 1
phần tử có giá trị x. Tìm vị trí xuất hiện đầu tiên của x trong danh sách. Xuất kết
quả nếu tìm thấy, nếu không xuất Not Found. (sử dụng tìm tuần tự)
Bài 7. Viết chương trình nhập vào một danh sách(đặc) có n phần tử, nhập vào 1
phần tử có giá trị x. Đếm số lần xuất hiện của x trong danh sách. Xuất kết quả.