Giải thuật tương ứng với lời giải đệ quy gọi là giải thuật đệ quy.Cấu trúc của giải thuật đệ quyMột giải thuật đệ quy bao giờ cũng gồm 2 phần Phần neo: Xác định điểm kết thúc của một giả
Trang 1TRƯỜNG ĐẠI HỌC DUY TÂNKHOA CÔNG NGHỆ THÔNG TIN
Khoa: Công nghệ thông tin
Bậc đào tạo: Đại học – Cao đẳng
Đà Nẵng, tháng 8 năm 2017
Trang 2Cấu trúc của giải thuật đệ quy
Một giải thuật đệ quy bao giờ cũng gồm 2 phần
Phần neo: Xác định điểm kết thúc của một giải thuật đệ quy Trường hợp nàycòn được gọi là trường hợp suy biến Nếu một giải thuật đệ quy không cótrường hợp suy biến thì sẽ dẫn đến lặp vô hạn và sinh lỗi khi thi hành.Phần đệ quy: Phân tích và xây dựng trường hợp chung của bài toán (có nghĩa
là đưa bài toán về bài toán cùng loại nhưng với dữ liệu nhỏ hơn)
Xây dựng giải thuật đệ quy
Khi cài đặt thuật toán đệ quy ta tiến hành những bước sau:
Bước 1: Xác định mục đích, đầu vào và đầu ra để từ đó xác định têntiêu đề hàm (tên hàm và tham số hình thức của nó)
Bước 2: Xác định trường hợp suy biến (neo)
Nguyễễn Minh Nh tậ Trang 1
Trang 3Bước 3: Phân tích và xây dựng trường hợp chung của bài toán (phần
đệ quy) Có nghĩa là đưa bài toán về bài toán cùng loại nhưng với dữ liệu nhỏhơn
Từ 3 bước trên, áp dụng nguyên tắc viết ngôn ngữ ta xây dựng được hàm đệ qui(thông thường sử dụng toán tử điều kiện (if…else) để viết hàm đệ quy
Ví dụ 1: Tính x với x được định nghĩa như sau:y y
01
0
ykhiykhix
x
y
y
xBước 1: Xác định tham số đầu vào là x và y, tham số đầu ra là x Ta luônynhận được giá trị x duy nhất, do đó ta sử dụng hàm có kiểu trả về.y
Bước 2: Phần neo: y=0 thì tổng x = 10
Bước 3: Phần đệ quy: là trường hợp thực hiện lại bài toán với giá trị nhỏ hơn
y = y - 1 Tức là ứng với trường hợp thực hiện lại lời gọi cũng đều có chungtham số đầu vào là y nhưng với giá trị nhỏ hơn y = y – 1 và đều có khuynhhướng đến trường hợp suy biến y = 0
Trang 4Hàm đệ quy như sau:
int dem(long n)
{
if(n==0) return 0;
else return (1+ dem(n/10));
1 Ví dụ 3: Xuất đảo ngược một số nguyên dương ra màn hình
Trang 51 (0.2 point)
Theo cách tiếp cận của lập trình có cấu trúc, NiklausWirth đưa ra công thức thể hiện được mối liên hệ giữa cấu trúc dữ liệu và giải thuật như sau:
*A Thuật toán + cấu trúc dữ liệu = chương trình
B Thuật toán + dữ liệu đầu vào = chương trình
C Kỹ thuật lập trình + cấu trúc dữ liệu = Kết quả đầu ra
C Một chương trình đệ quy là chương trình lặp đi lặp lại với số lần lặp không biết trước
D Một chương trình đề quy là chương trình có chưa hàm main
3 (0.2 point)
Chọn phát biểu đúng nhất
D Nếu một lời giải của bài toán P được thực hiện bằng lời giải của bài toán P’, có dạng giống như P thì đó là một lời giải đệ quy
B Giải thuật tương ứng với lời giải đệ quy gọi là giải thuật đệ quy
C Nếu giải thuật đệ quy được viết dưới dạng một thủ tục thì thủ tục ấy được gọi là thủ tục đệ quy
*D Tất cả đều đúng
4 (0.2 point)
Trong giải thuật đệ quy thành phần dừng là:
A Thành phần neo của thuật toán
B Xác định điểm dừng của thuật toán
C Thành phần không chứa khái niệm trong định nghĩa
*D Tất cả đều đúng
5 (0.2 point)
Nguyễễn Minh Nh tậ Trang 4
Trang 6Giải thuật là … câu lênh chặt chẽ, rõ ràng và xác định các thao tác trên các đối tượng dữ liệu
Đánh giá độ phức tạp của giải thuật là việc xác định ……và…… mà giải thuật cần
để thưc hiện giải một bài toán
A, Khoảng thời gian, độ khó
B Khoảng thời gian, độ phức tạp
*C Khoảng thời gian, dung lượng bộ nhớ máy tính
D Độ khó, dung lượng bộ nhớ máy tính
8 (0.2 point)
Các kiểu dữ liệu cơ bản là……
A Các kiểu dữ liệu mà người lập trình được cung cấp sẵn từ máy tính
B Các kiểu dữ liệu mà người lập trình được cung cấp sẵn từ ngôn ngữ tự nhiên
*C Các kiểu dữ liệu mà người lập trình được cung cấp sẵn từ ngôn ngữ lập trình
D Các kiểu dữ liệu mà người lập trìn được cung cấp sẵn từ ngôn ngữ này
Trang 7Kiểu dữ liệu trừu tượng là….
A Kiểu dữ liệu mà người lập trình tự xây dựng không dựa trên kiểu dữ liệu cơ bản được cung cấp từ ngôn ngữ lập trình
B Kiểu dữ liệu mà người lập trình phải tự xây dựng dựa trên kiểu dữ liệu không cơ bản được cung cấp từ ngôn ngữ lập trình
C Kiểu dữ liệu mà người lập trình phải tự xây dựng dựa trên các kiểu dữ liệu cơ bản được cung cấp từ ngôn ngữ này
*D Kiểu dữ liệu mà người lập trình phải tự xây dựng trên các kiểu dữ liệu cơ bản đượccung cấp từ ngôn ngữ lập trình
Trang 8Cho hàm sau: int A(int n){if(n==0) return 0; return n+A(n-1);} Với n=3 hàm trả
về giá trị nào sau đây:
Cho hàm sau: int A(int n){if(n==0) return 0; return n*A(n-1);} Với n=3 hàm trả
về giá trị nào sau đây:
Cho hàm sau: int A(int n,int m=0){if(n==0) return m; return A(n/10,m*10+n
%10);} Với lời gọi cout<<A(1200) nhận được kết quả nào sau đây:
*A 21
B 0021
Nguyễễn Minh Nh tậ Trang 7
Trang 9C 1200
D Lỗi cú pháp
18 (0.2 point)
Cho hàm sau: int A(int n,int m=0){if(n==0) return m; return A(n/10,m*10+n
%10)} Với lời gọi cout<<A(1200) nhận được kết quả nào sau đây:
Trang 11D 12
TRẢ LỜI NGẮN
1: Cấu trúc dữ liệu là gì? Cấu trúc dữ liệu khác cấu trúc lưu trữ ở những điểm nào?2: Nêu khái niệm giải thuật là gì? Mối quan hệ giữa giải thuật và cấu trúc dữ liệu là gì? Nêu các tính chất của giải thuật
3: Một ngôn ngữ lập trình có nên cho phép người sử dụng tự định nghĩa thêm các kiểu dữ liệu có cấu trúc? Giải thích và cho ví dụ
B2 BÀI TẬP THỰC HÀNH
1: Hãy viết mỗi yêu cầu sau bằng giải thuật đệ qui:
a Tính tổng S = 1 – 1/2 + 1/3 -1/4 + +(-1) 1/nn+1
b Tính S= 1 + 3 + 5 + + (2k+1) với (2k+1) ≤ n
c Đổi số n hệ 10 sang hệ nhị phân (chỉ sử dụng đệ qui)
d Tìm số đảo ngược 1 số nguyên dương
e Tìm ước số chung lớn nhất và bội số chung nhỏ nhất của 2 số nguyên A và B
f Tính tổng S= 1/2 +2/3+ 3/4 + + n/ n+1
g Tính tổng S= 1/2+ 1/2.3 +1/3.4 + + 1/n(n+1)
h Tìm chữ số lớn nhất của số nguyên dương n
2: Tính tổng các ước số của số nguyên dương n
3: Viết giải thuật đệ quy cho bài toán tìm số Fibonaci F(n)=F(n-1)+ F(n-2)
4: Viết giải thuật đệ quy cho Bài toán tháp Hà Nội chuyển n đĩa từ cột A sang cột C vớicột B làm trung gian
5: Dãy số Fibonacci được định nghĩa như sau:
Trang 12A(0) = A(1) =1
A(n) = A(n-2) + A(n-1) với n >1
a Nhập một số n và in ra n số Fibonacci đầu tiên
b Nhập một số n và in ra các số Fibonacci <=n
c Nhập một số m, kiểm tra xem m có phải số Fibonacci?
Hướng dẫn: Không dùng mảng mà dùng 3 biến để tính các số
Các phần tử của mảng nằm trong các ô nhớ liên tục nhau, địa chỉ thấp nhất của ô nhớ tương ứng với phần tử thứ nhất và địa chỉ cao nhất của ô nhớ tương ứng với phần tử cuối cùng Số phần tử của mảng sau khi được cấp phát là cố định Mỗi phần tử của mảng được truy nhập trực tiếp thông qua tên mảng cùng với chỉ số của nó
Đối với mảng thường có các phép toán:
+ Tạo lập một mảng
Nguyễễn Minh Nh tậ Trang 11
Trang 13+ Duyệt qua các phần tử của mảng.
+ Tìm kiếm một phần tử trong mảng
+ Sắp xếp các phần tử trong mảng theo thứ tự ấn định trước, v.v…
Vì số phần tử của mảng là cố định nên phép bổ sung phần tử mới vào mảng hoặc loại
bỏ một phần tử ra khỏi mảng thực hiện phải mất nhiều thao tác
Mảng một chiều hay còn gọi là vectơ là mảng mà mỗi phần tử của nó ứng với một chỉ số
Ví dụ như mảng a chứa n phần tử, phần tử thứ i của mảng a kí hiệu là a[i] trong đó i được gọi là chỉ số của mảng a
Ta có thể hình dung mảng một chiều a như hình vẽ sau:
Hình 2.1 Biểu diễn mảng một chiều
Ma trận là mảng hai chiều, mỗi phần tử của nó ứng với hai chỉ số hàng và cột
Ví dụ mảng B là mảng hai chiều hay còn gọi là ma trận B ký hiệu là B[i,j] với i là chỉ số hàng, j gọi là chỉ số cột
4 Cấu trúc lưu trữ trên mảng một chiều
Thông thường một số từ máy kế tiếp sẽ được giành ra để lưu trữ các phần tử của mảng (vìvậy người ta gọi là cách lưu trữ kế tiếp – sequential storage allocation)
Nếu mỗi phần tử của vector V[i] chiếm m từ máy mới đủ bộ nhớ để chứa phần tử a[i] thì lúc đó vector V chiếm n*m từ máy kế tiếp (hay nói là vector V được lưu trữ trong n*m từ máy kế tiếp) Địa chỉ của mỗi ô nhớ tức là địa chỉ của mỗi phần tử V[i] chính là địa chỉ của từ máy đầu tiên của ô nhớ đó
Hình 2.2 Mô tả Vector lưu trữĐịa chỉ V[1] được gọi là địa chỉ gốc(base address) ký hiệu là L0
Như vậy việc xác định địa chỉ của V[i] hay nói cách khác là địa chỉ của a[i] sẽ được tính theo công thức sau:
Nguyễễn Minh Nh tậ Trang 12
Trang 14LOC(a[i]) = L0 + m * (i-1)Trong đó LOC là từ viết tắt của chữ LOCATION (vị trí)
Hàm f(i) = m* (i-1) được gọi là hàm địa chỉ
5 Một số thuật toán trên danh sách đặc
5.1 Duyệt mảng
Khai báo mảng một chiều trong C:
Kiểu_dữ _liệu Tên_mảng[số phần tử của mảng];
Truy cập vào một phần tử của mảng: Tên_mảng[chỉ số];
Duyệt mảng là việc mà chúng ta cần phải thăm tất cả các phần tử của mảng và duyệt qua tất cả các phần tử mà không bỏ sót phần tử nào của mảng Thông thường dùng vòng lặp
để duyệt qua tất cả các phần tử của mảng
for (int i=1; i<n; i++)
cout << ” ”<<a[ i];
Tập dữ liệu được lưu trữ là dãy số a , a , ,a 1 2 n
Giả sử chọn cấu trúc dữ liệu mảng để lưu trữ dãy số này trong bộ nhớ chính, có khai báo:
int a[n];
Lưu ý các bản cài đặt trong tập bài giảng này sử dụng ngôn ngữ C, do đó chỉ số của mảng mặc định bắt đầu từ 0, nên các giá trị của các chỉ số có chênh lệch so với thuật toán, nhưng ý nghĩa không đổi
Nguyễễn Minh Nh tậ Trang 13
Trang 82{
int A[N];
int f,r;
};
Khởi tạo hàng đợi
Việc khởi tạo tức là cho f và r nhận giá trị 0, cho toàn bộ các phần tử của mảng A nhận giá trị NULLDATA:
// Khoi tao hang doi
Kiểm tra xem hàng đợi có rỗng không
Để kiểm tra hàng đợi có rỗng hay không ta chỉ cần kiểm tra giá trị r của hàng đợi Q
là biết được Bởi vì khi thêm một phần tử vào thì giá trị r tăng lên 1, nếu r =0 chứng tỏ hàng đợi này rỗng:
// Kiem tra hang doi rong
bool IsEmpty_Queue(Queue Q)
{
if (Q.r==0) return true;
else return false;
Nguyễễn Minh Nh tậ Trang 81
Trang 83Kiểm tra hàng đợi đã đầy chưa
Để kiểm tra hàng đợi đã đầy ta chỉ cần kiểm tra giá trị r –f của hàng đợi Q là biết được Bởi vì khi thêm một phần tử vào thì giá trị r tăng lên 1, khi loại bỏ một phần tử ra khỏi hàng thì f tăng lên 1, như vậy nếu số phần tử có chứa dữ liệu là r-f=N (là số phần tử cực đại của mảng) thì chứng tỏ mảng bị đầy Ngược lại thì còn các phần tử mảng chưa có chứa giá trị(là các phần tử đứng trước f: có thể đã bị loại bỏ đi) Hàm kiểm tra được mô tảnhư sau:
// Kiem tra hang da day chua
Thêm một phần tử vào cuối hàng đợi
Khi thêm một phần tử vào hàng đợi ta xem xét các trường hợp sau:
Kiểm tra hàng có rỗng hay không: Nếu hàng rỗng ta thêm giá trị X vào phần tử có chỉ số r, tăng r lên một đơn vị
Ngược lại hàng đã có dữ liệu thì tiến hành kiểm tra xem hàng có bị tràn hay không,nếu bị tràn nhưng dữ liệu chưa đầy thì tiến hành giải quyết hàng tràn theo một trong hai cách:
Cách 1: Tịnh tiến hàng lên f-1 phần tử(được sử dụng trong bài giảng này)Cách 2: Xem như hàng là vòng tròn, thêm dữ liệu vào phần tử đầu tiên của mảng, trước f, nếu r = N thì cho r= 0 ngược lại tăng r lên 1 đơn vị.(sinh viên tự cài đặt tại nhà theo cách này)
Nếu hàng đã đầy thì thông báo hàng đầy không thể thêm dữ liệu
Hàm mô tả bằng ngôn ngữ C như sau:
Nguyễễn Minh Nh tậ Trang 82
Trang 84// Them mot phan tu vao hang
Queue AddEndQueue(Queue Q, int X){
bool hangday, rong;
Trang 85b Cài đặt hàng đợi bằng danh sách liên kết
Ta có thể tạo hàng đợi bằng cách sử dụng một danh sách liên kết đơn
Hình 4.5 Cài đặt hàng đợi bằng DSLKPhần tử đầu DSKL (Dau) sẽ là phần tử đầu hàng đợi, phần tử cuối DSKL (Cuoi) sẽ là phần tử cuối hàng đợi
Khởi tạo hàng đợi:
Ta cho hai biến con trỏ Dau và Cuoi trỏ vào giá trị NULL Trả về giá trị là con trỏ Dau trỏ đến đầu hàng đợi:
// Khoi tao hang doi
Trang 86return Dau;
}
Kiểm tra xem hàng đợi có rỗng không
Hàng đợi rỗng khi phần tử Dau chỉ vào đầu hàng đợi có giá trị NULL
// Kiem tra hang doi rong
bool IsEmpty_Queue(Queue Q)
{
Dau = Q;
if (Dau == NULL) return true;
else return false;
}
Thêm một phần tử vào hàng đợi
Khi thêm một phần tử mới vào hàng ta thêm nó vào cuối hàng đợi Thủ tục thêm vào cuối được mô tả bằng ngôn ngữ C như sau:
Queue AddEndQueue(Queue Q, int x)
Loại một phần tử ra khỏi hàng đợi
Khi muốn loại một phần tử ra khỏi hàng ta loại phần tử đầu tiên của hàng đợi Thuật toán tương tự thuật toán loại Node đầu tiên của danh sách liên kết đơn đã trình bày
ở chương 3.Thủ tục loại phần tử ra khỏi hàng đợi được mô tả bằng ngôn ngữ C như sau://Xoa node dau tien cau hang doi
Trang 87Hàng đợi có thể được sử dụng trong một số bài toán:
Bài toán sản xuất và tiêu thụ (ứng dụng trong các hệ điều hành song song)
3:Ta có thể sử dụng mảng hoặc danh sách liên kết đơn để cài đặt cho các phép toán trên ngăn xếp và hàng đợi đúng hay sai? Nêu một số phép toán cơ bản trên ngăn xếp và hàng đợi thường dùng
4:Hãy nêu các bước cơ bản để định giá một biểu thức toán học Từ đó hãy định giá các biểu thức toán học sau theo các bước đó:
a P1= (a-b+c) d + h-t
b P2= (a+(b+c)-d*h)/t
c P3= (a/b)-c*d+h-t
Cho giá trị a=4, b=5, c=3, d=6, h=9, t=2
Nguyễễn Minh Nh tậ Trang 86
Trang 88Cho giá trị a=4, b=5, c=3, d=6, h=9, t=2.
Lưu ý: Xuất kết quả cuối cùng ra màn hình, và sau đó ghi kết quả của từng bước tính lên màn hình
2:Sử dụng ngăn xếp viết chương trình chuyển đổi từ dạng thập phân sang nhị phân của một số x bất kỳ được nhập vào từ bàn phím
3:Ứng dụng ngăn xếp viết chương trình cho phép nhập vào một xâu và in xâu đảo ngược của xâu đó ra màn hình
4:Hoàn thiện chương trình cài đặt ngăn xếp bằng mảng và bằng danh sách liên kết với cáckhai báo và các thao tác thực hiện được trên ngăn xếp đã học
BÀI 5: Hoàn thiện chương trình cài đặt hàng đợi bằng mảng và bằng danh sách liên kết với các khai báo và các thao tác thực hiện được trên ngăn xếp đã học
5
A LÝ THUYẾT
5.1 NGHĨA VÀ MỘT SỐ KHÁI NIỆM
5.1.1 Định nghĩa
Trong đời sống ta thấy có rất nhiều dữ liệu được biểu diễn thông qua dạng cây: ví
dụ như sơ đồ gia phả của một dòng họ, sơ đồ tổ chức chức của một công ty, Ta có thể cóđịnh nghĩa cây như sau:
Cây là một cấu trúc dữ liệu gồm một tập hữu hạn các nút, giữa các nút có một quan
hệ phân cấp gọi là quan hệ “cha-con” Có một nút đặc biệt gọi là nút gốc (root)
Nguyễễn Minh Nh tậ Trang 87
Trang 895.1.2 Biểu diễn cây
Để biểu diễn cây có rất nhiều cách, dùng đồ thị là một cách biểu diễn cơ bản nhất
mà chúng ta sẽ tìm hiểu trong bài giảng này:
Hình 5.1 Giới thiệu về Cây
5.1.3 Các khái niệm
Nút gốc
Nút gốc là nút duy nhất không có nút cha
Nút trước và nút sau
Nút T được gọi là nút trước của nút S nếu cây con có gốc là T chứa cây con có gốc là
S Khi đó nút S được gọi là nút sau của T
Cấp của nút
Số các con của một nút được gọi là cấp của nút đó
Ví dụ: Cho cây như hình sau:
Hình 5.2 Mô hình câyTrong cây trên ta có:
Trang 91Hình 5.3 Mức của câyNút cha và nút con
Nút P được gọi là nút cha của nút C nếu nút P là nút trước của nút C và mức của nút C lớn hơn mức của nút P là 1 mức Khi đó nút C được gọi là nút con của nút P
Nút lá và nút nhánh
Nút lá: Nút có cấp bằng 0 được gọi là nút lá (leaf) hay là nút tận cùng
Nút nhánh: Những nút không phải là nút lá (có bậc khác 0) và không phải là nút gốc thì được gọi là nút nhánh(branch)
Trang 92Trong cây trên thì các nút B, C, I, E, F, M, S,T được gọi là các nút lá(leaf) hay còn gọi
là nút tận cùng
Cấp của cây
Cấp cao nhất của một nút trên cây được gọi là cấp của cây đó
Trong cây trên thì cấp của cây là cấp 4 vì nút G có cấp 4 là cấp cao nhất của cây.Chiều cao(height) hay chiều sâu(depth)
Chiều cao(height) hay chiều sâu(depth) của một cây là số mức lớn nhất của nút có trên cây đó
Nguyễễn Minh Nh tậ Trang 91