Cấu trúc dữ liệu và giải thuật ĐH saigon

128 774 9
Cấu trúc dữ liệu và giải thuật ĐH saigon

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Bài tập cấu trúc dữ liệu giải thuật–SGU2010 Trang 0 TRƯỜNG ĐẠI HỌC SÀI GÒN KHOA CÔNG NGHỆ THÔNG TIN BỘ MÔN KHOA HỌC MÁY TÍNH o0o BÀI TẬP CẤU TRÚC DỮ LIỆU GIẢI THUẬT (lưu hành nội bộ) Năm 2010 Bài tập cấu trúc dữ liệu giải thuật–SGU2010 Trang 1 Lời giới thiệu Cấu trúc dữ liệu giải thuật là học phần bắt buộc thuộc khối kiến thức cơ sở ngành của sinh viên các chuyên ngành công nghệ thông tin cũng là nội dung quan trọng ở các kỳ thi tốt nghiệp, thi hoàn chỉnh đại học các chuyên ngành công nghệ thông tin. Giáo trình này trình bày các chủ đề bài tập về:Tổng quan về cấu trúc dữ liệugiải thuật, tìm kiếm, sắp xếp, cấu trúc danh sách liên kết cấu trúc cây theo ngôn ngữ C/C++. Mỗi chủ đề được thiết kế gồm các phần: Tóm tắt lý thuyết, một số dạng bài tập điển hình một số đề bài tập chọn lọc. Phần cuối của giáo trình có hướng dẫn giải cho một số bài tập tiêu biểu, đồng thời bổ sung một số đề thi mẫu để sinh viên tự rèn luyện kỹ năng phân tích vấn đề bài toán. Giáo trình chỉ trình bày vấn đề bài tập, còn các vấn đề lý thuyết liên quan thì bạn đọc có thể tham khảo chi tiết ở các quyển sách đã được chỉ ra ở phần tài liệu tham khảo. Quyển giáo trình này được biên soạn để làm tài liệu tham khảo khi giảng các học phần cấu trúc dữ liệu giải thuật ở hệ đại học cao đẳng. Chúng tôi xin trân trọng giới thiệu với bạn đọc quyển giáo trình này hy vọng rằng nó sẽ giúp cho việc giảng dạy học tập học phần cấu trúc dữ liệu giải thuật được thuận lợi hơn. Thành phố Hồ Chí Minh, ngày 06 tháng 09 năm 2010 CÁC TÁC GIẢ Bài tập cấu trúc dữ liệu giải thuật–SGU2010 Trang 2 Chương 1 TỔNG QUAN VỀ CẤU TRÚC DỮ LIỆU GIẢI THUẬT A.Tóm tắt lý thuyết 1.Cấu trúc dữ liệu giải thuật Xuyên suốt trong giáo trình này, chúng tôi muốn đề cập đến hai mặt quan trọng của một vấn đề bài toán là cách thức tổ chức dữ liệu của bài toán các phép xử lý trên các dữ liệu đó. 1.1.Cấu trúc dữ liệu Cấu trúc dữ liệu của bài toán là cách thức tổ chức dữ liệu sao cho phản ánh chính xác dữ liệu của bài toán có thể dùng máy tính để xử lý các dữ liệu đó một cách hiệu quả. Một cấu trúc dữ liệu được đánh giá là tốt nếu nó thỏa mãn được các yêu cầu như: Phản ánh đúng thực tế bài toán, phù hợp với các thao tác xử lý trên đó, tiết kiệm được tài nguyên hệ thống,… 1.2.Giải thuật (trong giáo trình này chúng tôi đồng nhất khái niệm thuật toán và giải thuật) Giải thuật là một bảng liệt kê các chỉ dẫn (hay các qui tắc) cần thực hiện theo từng bước xác định nhằm giải quyết một vấn đề bài toán. Các đặc trưng của giải thuật Tính xác định: Ở mỗi bước các chỉ dẫn phải rõ ràng. Tính kết thúc: Giải thuật phải dừng sau một số hữu hạn bước. Tính đúng đắn: Giải thuật phải cho ra kết quả đúng theo yêu cầu của bài toán. Tính tổng quát: Giải thuật phải áp dụng được cho các bài toán cùng loại. 1.3.Sự liên hệ giữa giải thuật cấu trúc dữ liệu Giải thuật cấu trúc dữ liệu có mối liên hệ chặt chẽ với nhau. Giải thuật phản ánh các phép xử lý, còn đối tượng xử lý của giải thuật là các dữ liệu; dữ liệu chứa đựng các thông tin cần thiết để thực hiện giải thuật. Để xác định được giải thuật Bài tập cấu trúc dữ liệu giải thuật–SGU2010 Trang 3 phù hợp cần phải biết nó tác động đến những loại dữ liệu nào khi chọn lựa một cấu trúc dữ liệu cũng cần phải hiểu rõ những thao tác nào sẽ được tác động lên nó. 2.Độ phức tạp của một giải thuật 2.1.Phân tích thời gian thực hiện giải thuật Với một bài toán chỉ có một giải thuật. Việc chọn lựa giải thuật đưa đến kết quả nhanh là một đòi hỏi quan trọng. Vấn đề là căn cứ vào những yêu tố nào để biết giải thuật này nhanh hơn giải thuật kia? Rõ ràng thời gian thực hiện một giải thuật (hay chương trình để thực hiện giải thuật đó) phụ thuộc vào nhiều yếu tố. Một yếu tố cần chú ý đầu tiên tiên chính là kích thước của dữ liệu đưa vào. Chẳng hạn thời gian để sắp xếp một dãy số chịu ảnh hưởng bởi số lượng số của dãy số đó. Nếu gọi n là số lượng này, thì thời gian thực hiện T của một giải thuật được biểu diễn như một hàm của n: T(n). Các kiểu lệnh tốc độ xử lý của máy tính, ngôn ngữ viết chương trình chương trình dịch ngôn ngữ ấy đều ảnh hưởng đến thời gian thực hiện chương trình; nhưng những yếu tố này không đồng đều với mỗi loại máy tính. Vì vậy không thể dựa vào chúng khi xác lập T(n). Điều đó cũng có nghĩa là T(n) không thể được biểu diễn thành đơn vị thời gian bằng giây, bằng phút được. Tuy nhiên không phải vì thế mà không thể so sánh được các giải thuật về mặt tốc độ. Nếu như thời gian thực hiện của một giải thuật là T 1 (n)=Cn 2 thời gian thực hiện giải thuật khác là T 2 (n)= kn (C, n, k là các hằng số nào đó), thì khi n khá lớn, thời gian thực hiện giải thuật t 2 ít hơn so với giải thuật T 1 , như vậy nếu nói thời gian thực hiện giải thuật T(n) tỉ lệ với với n 2 hay tỉ lệ với n cũng cho ta ý niệm về tốc độ thực hiện giải thuật đó khi n khá lớn (với n nhỏ thì việc xét T(n) không có ý nghĩa). Cách đánh giá thời gian thực hiện giải thuật độc lập với máy tính các yếu tố liên quan tới máy như vậy sẽ dẫn tới khái niệm về “cấp độ lớn của thời gian thực hiện giải thuật” hay còn gọi là “độ phức tạp tính toán của giải thuật”. 2.2.Thời gian chạy của các lệnh Lệnh gán Lệnh gán có dạng X = <biểu thức> Bài tập cấu trúc dữ liệu giải thuật–SGU2010 Trang 4 Thời gian chạy của lệnh gán là thời gian thực hiện biểu thức. Trường hợp hay gặp nhất là biểu thức chỉ chứa các phép toán sơ cấp, thời gian thực hiện nó là O(1). Nếu biểu thức chứa các lời gọi hàm thì ta phải tính đến thời gian thực hiện hàm, do đó trong trường hợp này thời gian thực hiện biểu thức có thể không còn phải O(1). Lệnh lựa chọn if (<điều kiện>) <lệnh 1>; else <lệnh 2>; Giả sử thời gian đánh giá điều kiện là T 0 (n), thời gian thực hiện <lệnh 1> là T 1 (n), thời gian thực hiện <lệnh 2> là T 2 (n). Thời gian thực hiện lệnh lựa chọn if-else sẽ là thời gian lớn nhất trong các thời gian T 0 (n) + T 1 (n) T 0 (n) + T 1 (n). Trường hợp hay gặp là kiểm tra điều kiện chỉ cần O(1). Khi đó nếu T 1 (n) = O(f(n)), T 2 (n) = O(g(n)) f(n) tăng nhanh hơn g(n) thì thời gian chạy của lệnh if- else là O(f(n)); còn nếu g(n) tăng nhanh hơn f(n) thì lệnh if-else cần thời gian O(g(n)). Thời gian chạy của lệnh lựa chọn switch được đánh giá tương tự như lệnh if- else, chỉ cần lưu ý rằng, lệnh if-else có hai khả năng lựa chọn, còn lệnh switch có thể có nhiều hơn hai khả năng lựa chọn. Các lệnh lặp for, while, do-while Để đánh giá thời gian thực hiện một lệnh lặp, trước hết ta cần đánh giá số tối đa các lần lặp, giả sử đó là L(n). Sau đó đánh giá thời gian chạy của mỗi lần lặp, chú ý rằng thời gian thực hiện thân của một lệnh lặp ở các lần lặp khác nhau có thể khác nhau, giả sử thời gian thực hiện thân lệnh lặp ở lần thứ i (i=1,2, , L(n)) là T i (n). Mỗi lần lặp, chúng ta cần kiểm tra điều kiện lặp, giả sử thời gian kiểm tra là T 0 (n). Như vậy thời gian chạy của lệnh lặp là: () ()() ∑ = + )( 1 0 nL i i nTnT Bài tập cấu trúc dữ liệu giải thuật–SGU2010 Trang 5 Công đoạn khó nhất trong đánh giá thời gian chạy của một lệnh lặp là đánh giá số lần lặp. Trong nhiều lệnh lặp, đặc biệt là trong các lệnh lặp for, ta có thể thấy ngay số lần lặp tối đa là bao nhiêu. Nhưng cũng không ít các lệnh lặp, từ điều kiện lặp để suy ra số tối đa các lần lặp, cần phải tiến hành các suy diễn không đơn giản. Trường hợp hay gặp là: kiểm tra điều kiện lặp (thông thường là đánh giá một biểu thức) chỉ cần thời gian O(1), thời gian thực hiện các lần lặp là như nhau giả sử ta đánh giá được là O(f(n)); khi đó, nếu đánh giá được số lần lặp là O(g(n)), thì thời gian chạy của lệnh lặp là O(g(n)f(n)). 2.3.Độ phức tạp tính toán của giải thuật Nếu thời gian thực hiện một giải thuật là T(n)=Cn 2 (với C là hằng số) thì ta nói: độ phức tạp tính toán của giải thuật này có cấp là n 2 (hay cấp độ lớn của thời gian thực hiện giải thuật là n 2 ) ta ký hiệu T(n) = O(n 2 ) - ký hiệu chữ O lớn. Một cách tổng quát ta có thể định nghĩa như sau: Một hàm f(n) được xác định là O(g(n)) f(n)=O(g(n)) được gọi là có cấp g(n) nếu tồn tại một hằng số C n o sao cho f(n) ≤ C.g(n) khi n ≥ n o Nghĩa là f(n) bị chặn trên bởi một hằng số nhân với g(n), với mọi giá trị của n từ một điểm nào đó. Chú ý rằng O(C(f(n))=O(f(n)) Để xác định độ phức tạp tính toán của một giải thuật bất kỳ có thể dẫn tới những bài toán phức tạp. Tuy nhiên trong thực tế, đối với một số giải thuật ta cũng có thể phân tích được bằng một số quy tắc đơn giản. Quy tắc cộng Giả sử T 1 (n) T 2 (n) là thời gian thực hiện của hai đoạn chương trình P 1 P 2 mà T 1 (n) = O(f(n)) T 2 (n)=O(g(n)), thì thời gian thực hiện P 1 rồi P 2 tiếp theo sẽ là T 1 (n)+ T 2 (n) = O( max(f(n), g(n)) Chẳng hạn đoạn lệnh for (int i=1;i<=n;i++) x=x+1; có thời gian thực hiện là O(n.1) = O(n) Quy tắc nhân Bài tập cấu trúc dữ liệu giải thuật–SGU2010 Trang 6 Nếu tương ứng với P 1 P 2 là T 1 (n) T 2 (n), T 1 (n) = O(f(n)) T 2 (n)=O(g(n)), thì thời gian thực hiện P 1 P 2 lồng nhau là T 1 (n) * T 2 (n) = O(f(n).g(n)) Chẳng hạn đoạn lệnh for (int i=1;i<=n;i++) for (int j=1;j<=n;j++ ) x=x+1; có thời gian thực hiện là O(n.n)=O(n 2 ). Chú ý rằng có những trường hợp giải thuật không phải chỉ thuộc vào kích thước của dữ liệu vào mà còn phụ thuộc vào chính tính trạng của dữ liệu đó nữa. Chẳng hạn việc sắp xếp một dãy số theo thứ tự tăng dần nếu gặp dãy số đưa vào đã có đúng thứ tự thì sẽ khác với trường hợp dãy số đưa vào chưa có thứ tự hoặc có thứ tự ngược lại, lúc đó khi phân tích thời gian thực hiện giải thuật ta sẽ phải xét tới: đối với mọi dữ liệu vào có kích thước n thì T(n) trong trường hợp thuật lợi nhất là thế nào? rồi T(n) trong trường hợp xấu nhất T(n) trung bình ? Việc xác định T(n) trung bình thường khó vì sẽ phải dùng tới những công cụ toán phức tạp. Trong các trường hợp mà T(n) trung bình khó xác định người ta thường đánh giá giải thuật qua giá trị xấu nhất của T(n). 2.4.Sự phân lớp các giải thuật Thông thường các hàm thể hiện độ phức tạp tính toán của giải thuật có dạng hằng số, log 2 n, n, nlogn, n 2 , n 3 , 2 n , n!, n n ,… Hằng số:Hầu hết các chỉ thị của các chương trình đều được thực hiện một lần hay một số số lần nhất định không phụ thuộc vào n Các hàm như 2 n , n!, n n được gọi là hàm mũ. Một giải thuật mà thời gian thực hiện của nó có cấp là các hàm loại mũ thì tốc độ rất chậm. Các hàm log 2 n, n, nlogn, n 2 , n 3 được gọi là các hàm loại đa thức. Giải thuật với thời gian thực hiện có cấp hàm đa thức thì thường là chấp nhận được. Các cấp độ thời gian chạy của giải thuật tên gọi của chúng được liệt kê trong bảng sau: Ký hiệu ô lớn Tên gọi O(1) hằng Bài tập cấu trúc dữ liệu giải thuật–SGU2010 Trang 7 O(logn) O(n) O(nlogn) O(n 2 ) O(n 3 ) O(2 n ) logarit tuyến tính nlogn bình phương lập phương Mũ B.Các dạng bài tập Dạng 1: Bài toán với cấu trúc dữ liệu là mảng một chiều Ví dụ 1.1: Cộng hai số nguyên lớn Cho hai số nguyên lớn a b; a có m chữ số b có n chữ số. Hãy viết chương trình tính tổng a+b. Giải thuật Số nguyên lớn ở đây là số có thể có đến vài nghìn chữ số. Để lưu trữ các số nguyên lớn này ta có thể dùng chuỗi (mỗi ký tự của chuỗi là một chữ số) hoặc dùng mảng một chiều (mỗi phần tử của mảng một chiều là một chữ số). Tuy nhiên trong hai phương án này thì phương án dùng mảng một chiều để lưu trữ sẽ có giải thuật tốt hơn. Giải thuật này có thể trình bày ngắn gọn như sau: Bước 1:Nhập hai số nguyên lớn a,b. Để có thể thực hiện được phép a+b một cách tự nhiên thì khi nhập a,b thì a b phải được giống hàng bên phải. Ví dụ: Giả sử a có m=5 chữ số, b có n=4 chữ số như sau: a = 97895 b = 6478 Thì việc lưu trữ hai số này là như sau: a[1] = 9, a[2]=7, a[3]=8, a[4]=9, a[5]=5 b[2] = 6, b[3]=4, b[4]=7, b[5]=8 Việc giống hàng bên phải cho a b có thể tiến hành bằng cách đặt max là số lớn nhất trong hai số m n. for i=max-m+1 to max cin>>a[i]; for i=max-n+1 to max Bài tập cấu trúc dữ liệu giải thuật–SGU2010 Trang 8 cin>>b[i]; Bước 2: Thực hiện phép hai số a,b theo cách thông thường: Nghĩa là cộng từng cặp chữ số a[i], b[i] bắt đầu từ phía bên phải lưu kết quả cuối cùng lưu vào mảng c. Lưu ý các mảng a,b bắt đầu từ chỉ số 1, còn mảng c bắt đầu từ chỉ số 0 c[0] có thể bằng 0 (khi phép cộng hai chữ số cuối cùng không có nhớ) cũng có thể khác 0 (khi phép cộng hai chữ số cuối cùng có nhớ). sonho=0; for (i=max;i >0;i ) { c[i]=(a[i]+b[i]+ sonho)%10; sonho =(a[i]+b[i]+ sonho)/10; } c[0]= sonho; Bước 3: Xuất mảng c kết quả ra màn hình. Lưu ý là chỉ nên xuất c[0] khi c[0] khác 0. Chương trình 1-1 Dạng 2: Bài toán với cấu trúc dữ liệu là mảng hai chiều Ví dụ 1.2.Ma trận phân số Cho ma trận hai chiều m dòng, n cột; trong đó mỗi phần tử là một phân số (giả sử tử số mẫu số của các phân số này là các số nguyên dương). Hãy thực hiện các yêu cầu sau: a.Tìm ma trận phân số tối giản b.Tìm phân số có giá trị lớn nhất. Giải thuật Một cấu trúc dữ liệu tốt cho bài toán này là định nghĩa một kiểu dữ liệu mới kiểu bản ghi để lưu trữ dữ liệu là các phân số như sau: struct phanso { int tuso; Bài tập cấu trúc dữ liệu giải thuật–SGU2010 Trang 9 int mauso; }; -Phân số tối giản là phân số mà ước số chung lớn nhất của tử số mẫu số bằng 1. Để tìm bảng phân số tối giản ta chỉ cần tối giản từng phân số. Lưu ý là để so sánh phân số 1 có lớn phân số 2 hay không ta dùng điều kiện: ps1.tu*ps2.mau>ps2.tu*ps1.mau Chương trình 1-2 #include <conio.h> #include <math.h> #include <iostream.h> #include <stdio.h> #define maxm 50 #define maxn 50 struct phanso { int tu; int mau; }; void nhapmangps(phanso ps[maxm][maxn], int &m, int &n); void xuatmangps(phanso ps[maxm][maxn], int m, int n); int sosanhps(phanso ps1, phanso ps2); void bangphansotoigian(phanso ps[maxm][maxn], int m, int n); void timpslonnhat(phanso ps[maxm][maxn], int m, int n); void main() { clrscr(); phanso ps[maxm][maxn]; int m,n; nhapmangps(ps,m,n); bangphansotoigian(ps,m,n); xuatmangps(ps,m,n); [...]... nhiên giải thuật này có độ phức tạp là O(n3) Giải thuật 2: Bài tập cấu trúc dữ liệu giải thuật SGU2010 Trang 17 Ta có thể cải tiến giải thuật trên để có giải thuật với độ phức tạp là O(n2) bằng cách sử dụng hệ thức : Tổng a[L U]= Tổng a[L U-1]+a[U] maxsofar=0; for (L=1;L

Ngày đăng: 27/03/2014, 12:51

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan