1. Trang chủ
  2. » Trung học cơ sở - phổ thông

Giáo trình Giải thuật

20 7 0

Đ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

1.3 THỜI GIAN THỰC HIỆN CỦA CHƯƠNG TRÌNH Một phương pháp để xác định hiệu quả thời gian thực hiện của một giải thuật là lập trình nó và đo lường thời gian thực hiện của hoạt động trên mộ[r]

(1)Th.s NGUYỄN VĂN LINH GIẢI THUẬT Được biên soạn khuôn khổ dự án ASVIET002CNTT ”Tăng cường hiệu đào tạo và lực tự đào tạo sinh viên khoa Công nghệ Thông tin - Đại học Cần thơ” ĐẠI HỌC CẦN THƠ - 12/2003 Lop12.net (2) LỜI NÓI ÐẦU N Wirth, nhà khoa học máy tính tiếng, tác giả ngôn ngữ lập trình Pascal, đã đặt tên cho sách ông là “Cấu trúc liệu + Giải thuật = Chương trình” Ðiều đó nói lên tầm quan trọng giải thuật lập trình nói riêng và khoa học máy tính nói chung Vì lẽ đó giải thuật, với tư cách là môn học, cần phải sinh viên chuyên ngành tin học nghiên cứu cách có hệ thống Môn học “Giải thuật” bố trí sau môn “Cấu trúc liệu” chương trình đào tạo kỹ sư tin học nhằm giới thiệu cho sinh viên kiến thức nhất, kỹ thuật chủ yếu việc PHÂN TÍCH và THIẾT KẾ giải thuật Các kỹ thuật trình bày đây đã các nhà khoa học tin học tổng kết và vận dụng cài đặt các chương trình Việc nắm vững các kỹ thuật đó bổ ích cho sinh viên phải giải vấn đề thực tế Giáo trình này hình thành trên sở tham khảo sách “Data Structure and Algorithms” A.V Aho, kinh nghiệm giảng dạy thân và các bạn đồng nghiệp Mặc dù đã có nhiều cố gắng quá trình biên soạn chắn còn nhiều thiếu sót, mong nhận đóng góp quý bạn đọc Cần thơ, ngày tháng 12 năm 2003 Nguyễn Văn Linh Lop12.net (3) Giải thuật Mục lục MỤC LỤC PHẦN TỔNG QUAN i Chương 1: KĨ THUẬT PHÂN TÍCH GIẢI THUẬT 1.1 TỔNG QUAN 1.2 SỰ CẦN THIẾT PHẢI PHÂN TÍCH GIẢI THUẬT 1.3 THỜI GIAN THỰC HIỆN CỦA GIẢI THUẬT 1.4 TỶ SUẤT TĂNG VÀ ÐỘ PHỨC TẠP CỦA GIẢI THUẬT 1.5 CÁCH TÍNH ÐỘ PHỨC TẠP 1.6 PHÂN TÍCH CÁC CHƯƠNG TRÌNH ÐỆ QUY 1.7 TỔNG KẾT CHƯƠNG 16 BÀI TẬP CHƯƠNG 16 Chương 2: SẮP XẾP 18 2.1 TỔNG QUAN 18 2.2 BÀI TOÁN SẮP XẾP 19 2.3 CÁC PHƯƠNG PHÁP SẮP XẾP ÐƠN GIẢN 20 2.4 QUICKSORT 25 2.5 HEAPSORT 31 2.6 BINSORT 39 2.7 TỔNG KẾT CHƯƠNG 44 BÀI TẬP CHƯƠNG 44 Chương 3: KĨ THUẬT THIẾT KẾ GIẢI THUẬT 45 3.1 TỔNG QUAN 45 3.2 KĨ THUẬT CHIA ÐỂ TRỊ 45 3.3 KĨ THUẬT “THAM ĂN” 50 3.4 QUY HOẠCH ÐỘNG 56 3.5 KĨ THUẬT QUAY LUI 63 3.6 KĨ THUẬT TÌM KIẾM ÐỊA PHƯƠNG 78 3.7 TỔNG KẾT CHƯƠNG 82 BÀI TẬP CHƯƠNG 82 Chương 4: CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT LƯU TRỮ NGOÀI 85 4.1 TỔNG QUAN 85 4.2 MÔ HÌNH XỬ LÝ NGOÀI 85 4.3 ÐÁNH GIÁ CÁC GIẢI THUẬT XỬ LÝ NGOÀI 86 4.4 SẮP XẾP NGOÀI 87 4.5 LƯU TRỮ THÔNG TIN TRONG TẬP TIN 93 4.6 TỔNG KẾT CHƯƠNG 103 BÀI TẬP CHƯƠNG 104 Lop12.net (4) Giải thuật Tổng quan PHẦN TỔNG QUAN Mục đích yêu cầu Môn học giải thuật cung cấp cho sinh viên khối lượng kiến thức tương đối hoàn chỉnh phân tích và thiết kế các giải thuật lập trình cho máy tính Sau học xong môn học này, sinh viên cần: - Nắm khái niệm thời gian thực chương trình, độ phức tạp giải thuật Biết cách phân tích, đánh giá giải thuật thông qua việc tính độ phức tạp - Nắm các giải thuật xếp và phân tích đánh giá các giải thuật xếp - Nắm các kĩ thuật thiết kế giải thuật, vận dụng vào việc giải số bài toán thực tế - Nắm các phương pháp tổ chức lưu trữ thông tin tập tin và các giải thuật tìm, xen, xoá thông tin tập tin Đối tượng sử dụng Môn học giải thuật dùng để giảng dạy cho các sinh viên sau: - Sinh viên năm thứ chuyên ngành Tin học - Sinh viên năm thứ chuyên ngành Điện tử (Viễn thông, Tự động hoá…) - Sinh viên Toán-Tin Nội dung cốt lõi Trong khuôn khổ 45 tiết, giáo trình cấu trúc thành chương - Chương 1: Kĩ thuật phân tích đánh giá giải thuật Chương này đặt vấn đề cần phải phân tích, đánh giá giải thuật và phân tích đánh giá theo phương pháp nào Nội dung chương tập trung vào khái niệm độ phức tạp thời gian giải thuật và phương pháp tính độ phức tạp giải thuật chương trình bình thường, chương trình có gọi các chương trình và các chương trình đệ quy - Chương 2: Sắp xếp Chương này trình bày các giải thuật xếp, thao tác thường sử dụng việc giải các bài toán máy tính Sẽ có nhiều giải thuật xếp từ đơn giản đến nâng cao giới thiệu đây Với giải thuật, trình bày ý tưởng giải thuật, ví dụ minh hoạ, cài đặt chương trình và phân tích đánh giá - Chương 3: Kĩ thuật thiết kế giải thuật Chương này trình bày các kĩ thuật phổ biến để thiết kế các giải thuật Các kĩ thuật này gồm: Chia để trị, Quy hoạch động, Tham ăn, Quay lui và Tìm kiếm địa phương Với kĩ thuật trình bày nội dung kĩ thuật và vận dung vào giải các bài toán khá tiếng bài toán người giao hàng, bài toán cái ba lô, bài toán cây phủ tối thiểu - Chương 4: Cấu trúc liệu và giải thuật lưu trữ ngoài Chương này trình bày các cấu trúc liệu dùng để tổ chức lưu trữ tập tin trên nhớ ngoài và các giải thuật tìm kiếm, xen xoá thông tin trên các tập tin đó Kiến thức tiên Để học tốt môn học giải thuật cần phải có các kiến thức sau: - Kiến thức toán học - Kiến thức và kĩ lập trình Lop12.net (5) Giải thuật Tổng quan - Kiến thức cấu trúc liệu và các giải thuật thao tác trên các cấu trúc liệu Trong chương trình đào tạo, Cấu trúc liệu là môn học tiên môn Giải thuật Danh mục tài liệu tham khảo [1] A.V Aho, J.E Hopcroft, J.D Ullman; Data Structures and Algorithms; Addison-Wesley; 1983 [2] Jeffrey H Kingston; Algorithms and Data Structures; Addison-Wesley; 1998 [3] Đinh Mạnh Tường; Cấu trúc liệu & Thuật toán; Nhà xuất khoa học và kĩ thuật; Hà nội-2001 [4] Đỗ Xuân Lôi; Cấu trúc liệu & Giải thuật; 1995 [5] Nguyễn Đức Nghĩa, Tô Văn Thành; Toán rời rạc; 1997 [6] Trang web phân tích giải thuật: http://pauillac.inria.fr/algo/AofA/ [7] Trang web bài giảng giải thuật: http://www.cs.pitt.edu/~kirk/algorithmcourses/ [8] Trang tìm kiếm các giải thuật: http://oopweb.com/Algorithms/Files/Algorithms.html Lop12.net (6) Giải thuật Kĩ thuật phân tích giải thuật CHƯƠNG 1: KĨ THUẬT PHÂN TÍCH GIẢI THUẬT 1.1 TỔNG QUAN 1.1.1 Mục tiêu Sau học chương này, sinh viên cần phải trả lời các câu hỏi sau: - Tại cần phân tích đánh giá giải thuật? - Tiêu chuẩn nào để đánh giá giải thuật là tốt? - Phương pháp đánh giá nào? (đánh giá chương trình không gọi chương trình con, đánh giá chương trình có gọi các chương trình không đệ quy và đánh giá chương trình đệ quy) 1.1.2 Kiến thức cần thiết Các kiến thức cần thiết để học chương này bao gồm: - Kiến thức toán học: Công thức tính tổng n số tự nhiên đầu tiên, công thức tính tổng n số hạng đầu tiên cấp số nhân, phương pháp chứng minh quy nạp và các kiến thức liên quan đến logarit (biến đổi logarit, tính chất đồng biến hàm số logarit) - Kĩ thuật lập trình và lập trình đệ quy 1.1.3 Tài liệu tham khảo A.V Aho, J.E Hopcroft, J.D Ullman Data Structures and Algorithms AddisonWesley 1983 (Chapters 1, 9) Jeffrey H Kingston; Algorithms and Data Structures; Addison-Wesley; 1998 (Chapter 2) Đinh Mạnh Tường Cấu trúc liệu & Thuật toán Nhà xuất khoa học và kĩ thuật Hà nội-2001 (Chương 1) Trang web phân tích giải thuật: http://pauillac.inria.fr/algo/AofA/ 1.1.4 Nội dung cốt lõi Trong chương này chúng ta nghiên cứu các vấn đề sau: • Sự cần thiết phải phân tích các giải thuật • Thời gian thực chương trình • Tỷ suất tăng và độ phức tạp giải thuật • Tính thời gian thực chương trình • Phân tích các chương trình đệ quy Nguyễn Văn Linh Trang Lop12.net (7) Giải thuật Kĩ thuật phân tích giải thuật 1.2 SỰ CẦN THIẾT PHẢI PHÂN TÍCH GIẢI THUẬT Trong giải bài toán chúng ta có thể có số giải thuật khác nhau, vấn đề là cần phải đánh giá các giải thuật đó để lựa chọn giải thuật tốt (nhất) Thông thường thì ta vào các tiêu chuẩn sau: 1.- Giải thuật đúng đắn 2.- Giải thuật đơn giản 3.- Giải thuật thực nhanh Với yêu cầu (1), để kiểm tra tính đúng đắn giải thuật chúng ta có thể cài đặt giải thuật đó và cho thực trên máy với số liệu mẫu lấy kết thu so sánh với kết đã biết Thực thì cách làm này không chắn vì có thể giải thuật đúng với tất các liệu chúng ta đã thử lại sai với liệu nào đó Vả lại cách làm này phát giải thuật sai chưa chứng minh là nó đúng Tính đúng đắn giải thuật cần phải chứng minh toán học Tất nhiên điều này không đơn giản và chúng ta không đề cập đến đây Khi chúng ta viết chương trình để sử dụng vài lần thì yêu cầu (2) là quan trọng Chúng ta cần giải thuật dễ viết chương trình để nhanh chóng có kết , thời gian thực chương trình không đề cao vì dù thì chương trình đó sử dụng vài lần mà thôi Tuy nhiên chương trình sử dụng nhiều lần thì thì yêu cầu tiết kiệm thời gian thực chương trình lại quan trọng đặc biệt chương trình mà thực cần liệu nhập lớn đó yêu cầu (3) xem xét cách kĩ càng Ta gọi nó là hiệu thời gian thực giải thuật 1.3 THỜI GIAN THỰC HIỆN CỦA CHƯƠNG TRÌNH Một phương pháp để xác định hiệu thời gian thực giải thuật là lập trình nó và đo lường thời gian thực hoạt động trên máy tính xác định tập hợp chọn lọc các liệu vào Thời gian thực không phụ thuộc vào giải thuật mà còn phụ thuộc vào tập các thị máy tính, chất lượng máy tính và kĩ xảo người lập trình Sự thi hành có thể điều chỉnh để thực tốt trên tập đặc biệt các liệu vào chọn Ðể vượt qua các trở ngại này, các nhà khoa học máy tính đã chấp nhận tính phức tạp thời gian tiếp cận đo lường thực thi giải thuật Thuật ngữ tính hiệu đề cập đến đo lường này và đặc biệt phức tạp thời gian trường hợp xấu 1.3.1 Thời gian thực chương trình Thời gian thực chương trình là hàm kích thước liệu vào, ký hiệu T(n) đó n là kích thước (độ lớn) liệu vào Ví dụ 1-1: Chương trình tính tổng n số có thời gian thực là T(n) = cn đó c là số Nguyễn Văn Linh Trang Lop12.net (8) Giải thuật Kĩ thuật phân tích giải thuật Thời gian thực chương trình là hàm không âm, tức là T(n) ≥ ∀ n ≥ 1.3.2 Ðơn vị đo thời gian thực Ðơn vị T(n) không phải là đơn vị đo thời gian bình thường giờ, phút giây mà thường xác định số các lệnh thực máy tính lý tưởng Ví dụ 1-2: Khi ta nói thời gian thực chương trình là T(n) = Cn thì có nghĩa là chương trình cần Cn thị thực thi 1.3.3 Thời gian thực trường hợp xấu Nói chung thì thời gian thực chương trình không phụ thuộc vào kích thước mà còn phụ thuộc vào tính chất liệu vào Nghĩa là liệu vào có cùng kích thước thời gian thực chương trình có thể khác Chẳng hạn chương trình xếp dãy số nguyên tăng dần, ta cho vào dãy có thứ tự thì thời gian thực khác với ta cho vào dãy chưa có thứ tự, ta cho vào dãy đã có thứ tự tăng thì thời gian thực khác so với ta cho vào dãy đã có thứ tự giảm Vì thường ta coi T(n) là thời gian thực chương trình trường hợp xấu trên liệu vào có kích thước n, tức là: T(n) là thời gian lớn để thực chương trình liệu vào có cùng kích thước n 1.4 TỶ SUẤT TĂNG VÀ ÐỘ PHỨC TẠP CỦA GIẢI THUẬT 1.4.1 Tỷ suất tăng Ta nói hàm không âm T(n) có tỷ suất tăng (growth rate) f(n) tồn các số C và N0 cho T(n) ≤ Cf(n) với n ≥ N0 Ta có thể chứng minh “Cho hàm không âm T(n) bất kỳ, ta luôn tìm tỷ suất tăng f(n) nó” Ví dụ 1-3: Giả sử T(0) = 1, T(1) = và tổng quát T(n) = (n+1)2 Ðặt N0 = và C = thì với n ≥1 chúng ta dễ dàng chứng minh T(n) = (n+1)2 ≤ 4n2 với n ≥ 1, tức là tỷ suất tăng T(n) là n2 Ví dụ 1-4: Tỷ suất tăng hàm T(n) = 3n3 + 2n2 là n3 Thực vậy, cho N0 = và C = ta dễ dàng chứng minh với n ≥ thì 3n3 + 2n2 ≤ 5n3 1.4.2 Khái niệm độ phức tạp giải thuật Giả sử ta có hai giải thuật P1 và P2 với thời gian thực tương ứng là T1(n) = 100n2 (với tỷ suất tăng là n2) và T2(n) = 5n3 (với tỷ suất tăng là n3) Giải thuật nào thực nhanh hơn? Câu trả lời phụ thuộc vào kích thước liệu vào Với n < 20 thì P2 nhanh P1 (T2<T1), hệ số 5n3 nhỏ hệ số 100n2 (5<100) Nhưng n > 20 thì ngươc lại số mũ 100n2 nhỏ số mũ 5n3 (2<3) Ở đây chúng ta nên quan tâm đến trường hợp n>20 vì n<20 thì thời gian thực P1 và P2 không lớn và khác biệt T1 và T2 là không đáng kể Nguyễn Văn Linh Trang Lop12.net (9) Giải thuật Kĩ thuật phân tích giải thuật Như cách hợp lý là ta xét tỷ suất tăng hàm thời gian thực chương trình thay vì xét chính thân thời gian thực Cho hàm T(n), T(n) gọi là có độ phức tạp f(n) tồn các C, N0 cho T(n) ≤ Cf(n) với n ≥ N0 (tức là T(n) có tỷ suất tăng là f(n)) và kí hiệu T(n) là O(f(n)) (đọc là “ô f(n)”) Ví dụ 1-5: T(n)= (n+1)2 có tỷ suất tăng là n2 nên T(n)= (n+1)2 là O(n2) Chú ý: O(C.f(n))=O(f(n)) với C là số Ðặc biệt O(C)=O(1) Nói cách khác độ phức tạp tính toán giải thuật là hàm chặn trên hàm thời gian Vì nhân tử C hàm chặn trên không có ý nghĩa nên ta có thể bỏ qua vì hàm thể độ phức tạp có các dạng thường gặp sau: log2n, n, nlog2n, n2, n3, 2n, n!, nn Ba hàm cuối cùng ta gọi là dạng hàm mũ, các hàm khác gọi là hàm đa thức Một giải thuật mà thời gian thực có độ phức tạp là hàm đa thức thì chấp nhận tức là có thể cài đặt để thực hiện, còn các giải thuật có độ phức tạp hàm mũ thì phải tìm cách cải tiến giải thuật Vì ký hiệu log2n thường có mặt độ phức tạp nên khôn khổ tài liệu này, ta dùng logn thay cho log2n với mục đích là gọn cách viết Khi nói đến độ phức tạp giải thuật là ta muốn nói đến hiệu thời gian thực chương trình nên ta có thể xem việc xác định thời gian thực hiên chương trình chính là xác định độ phức tạp giải thuật 1.5 CÁCH TÍNH ÐỘ PHỨC TẠP Cách tính độ phức tạp giải thuật là vấn đề không đơn giản Tuy nhiên ta có thể tuân theo số nguyên tắc sau: 1.5.1 Qui tắc cộng Nếu T1(n) và T2(n) là thời gian thực hai đoạn chương trình P1 và P2; và T1(n)=O(f(n)), T2(n)=O(g(n)) thì thời gian thực đoạn hai chương trình đó nối tiếp là T(n)=O(max(f(n),g(n))) Ví dụ 1-6: Lệnh gán x:=15 tốn thời gian hay O(1), Lệnh đọc liệu READ(x) tốn thời gian hay O(1).Vậy thời gian thực hai lệnh trên nối tiếp là O(max(1,1))=O(1) 1.5.2 Qui tắc nhân Nếu T1(n) và T2(n) là thời gian thực hai đoạn chương trình P1và P2 và T1(n) = O(f(n)), T2(n) = O(g(n)) thì thời gian thực đoạn hai đoạn chương trình đó lồng là T(n) = O(f(n).g(n)) 1.5.3 Qui tắc tổng quát để phân tích chương trình: - Thời gian thực lệnh gán, READ, WRITE là O(1) Nguyễn Văn Linh Trang Lop12.net (10) Giải thuật Kĩ thuật phân tích giải thuật - Thời gian thực chuỗi các lệnh xác định qui tắc cộng Như thời gian này là thời gian thi hành lệnh nào đó lâu chuỗi lệnh - Thời gian thực cấu trúc IF là thời gian lớn thực lệnh sau THEN sau ELSE và thời gian kiểm tra điều kiện Thường thời gian kiểm tra điều kiện là O(1) - Thời gian thực vòng lặp là tổng (trên tất các lần lặp) thời gian thực thân vòng lặp Nếu thời gian thực thân vòng lặp không đổi thì thời gian thực vòng lặp là tích số lần lặp với thời gian thực thân vòng lặp Ví dụ 1-7: Tính thời gian thực thủ tục xếp “nổi bọt” PROCEDURE Bubble(VAR a: ARRAY[1 n] OF integer); VAR i,j,temp: Integer; BEGIN {1} FOR i:=1 TO n-1 DO {2} FOR j:=n DOWNTO i+1 DO {3} IF a[j-1]>a[j]THEN BEGIN{hoán vị a[i], a[j]} {4} temp := a[j-1]; {5} a[j-1] := a[j]; {6} a[j] := temp; END; END; Về giải thuật xếp bọt, chúng ta bàn kĩ chương Ở đây, chúng ta quan tâm đến độ phức tạp giải thuật Ta thấy toàn chương trình gồm lệnh lặp {1}, lồng lệnh {1} là lệnh {2}, lồng lệnh {2} là lệnh {3} và lồng lệnh {3} là lệnh nối tiếp {4}, {5} và {6} Chúng ta tiến hành tính độ phức tạp theo thứ tự từ Trước hết, ba lệnh gán {4}, {5} và {6} tốn O(1) thời gian, việc so sánh a[j-1] > a[j] tốn O(1) thời gian, đó lệnh {3} tốn O(1) thời gian Vòng lặp {2} thực (n-i) lần, lần O(1) đó vòng lặp {2} tốn O((n-i).1) = O(n-i) Vòng lặp {1} lặp có I chạy từ đến n-1nên thời gian thực vòng lặp {1} và là độ phức tạp giải thuật là n −1 T(n) = ∑ (n − i) = i =1 n(n − 1) = O(n2) Chú ý: Trong trường hợp vòng lặp không xác định số lần lặp thì chúng ta phải lấy số lần lặp trường hợp xấu Ví dụ 1-8: Tìm kiếm Hàm tìm kiếm Search nhận vào mảng a có n số nguyên và số nguyên x, hàm trả giá trị logic TRUE tồn phần tử a[i] = x, ngược lại hàm trả FALSE Nguyễn Văn Linh Trang Lop12.net (11) Giải thuật Kĩ thuật phân tích giải thuật Giải thuật tìm kiếm là so sánh x với các phần tử mảng a, a[1], tồn a[i] = x thì dừng và trả TRUE, ngược lại tất các phần tử a khác X thì trả FALSE FUNCTION Search(a:ARRAY[1 n] OF Integer;x:Integer):Boolean; VAR i:Integer; Found:Boolean; BEGIN {1} i:=1; {2} Found:=FALSE; {3} WHILE(i<=n)AND (not Found) DO {4} IF A[i]=X THEN Found:=TRUE ELSE i:=i+1; {5} Search:=Found; END; Ta thấy các lệnh {1}, {2}, {3} và {5} nối tiếp nhau, đó độ phức tạp hàm Search chính là độ phức tạp lớn lệnh này Dễ dàng thấy ba lệnh {1}, {2} và {5} có độ phức tạp O(1) đó độ phức tạp hàm Search chính là độ phức tạp lệnh {3} Lồng lệnh {3} là lệnh {4} Lệnh {4} có độ phức tạp O(1) Trong trường hợp xấu (tất các phần tử mảng a khác x) thì vòng lặp {3} thực n lần, ta có T(n) = O(n) 1.5.4 Ðộ phức tạp chương trình có gọi chương trình không đệ qui Nếu chúng ta có chương trình với các chương trình không đệ quy, để tính thời gian thực chương trình, trước hết chúng ta tính thời gian thực các chương trình không gọi các chương trình khác Sau đó chúng ta tính thời gian thực các chương trình gọi các chương trình mà thời gian thực chúng đã tính Chúng ta tiếp tục quá trình đánh giá thời gian thực chương trình sau thời gian thực tất các chương trình mà nó gọi đã đánh giá Cuối cùng ta tính thời gian cho chương trình chính Giả sử ta có hệ thống các chương trình gọi theo sơ đồ sau: A B B1 C B2 B12 B11 Hình 1-1: Sơ đồ gọi thực các chương trình không đệ quy Chương trình A gọi hai chương trình là B và C, chương trình B gọi hai chương trình là B1 và B2, chương trình B1 gọi hai chương trình là B11 và B12 Ðể tính thời gian thực A, ta tính theo các bước sau: Nguyễn Văn Linh Trang Lop12.net (12) Giải thuật Kĩ thuật phân tích giải thuật Tính thời gian thực C, B2, B11 và B12 Vì các chương trình này không gọi chương trình nào Tính thời gian thực B1 Vì B1 gọi B11 và B12 mà thời gian thực B11 và B12 đã tính bước Tính thời gian thực B Vì B gọi B1 và B2 mà thời gian thực B1 đã tính bước và thời gian thực B2 đã tính bước Tính thời gian thực A Vì A gọi B và C mà thời gian thực B đã tính bước và thời gian thực C đã tính bước Ví dụ 1-9: Ta có thể viết lại chương trình xếp bubble sau: Trước hết chúng ta viết thủ tục Swap để thực việc hoàn đổi hai phần tử cho nhau, sau đso thủ tục Bubble, cần ta gọi đến thủ tục Swap này PROCEDURE Swap (VAR x, y: Integer); VAR temp: Integer; BEGIN temp := x; x := y; y := temp; END; PROCEDURE Bubble (VAR a: ARRAY[1 n] OF integer); VAR i,j :Integer; BEGIN {1} FOR i:=1 TO n-1 DO {2} FOR j:=n DOWNTO i+1 DO {3} IF a[j-1]>a[j] THEN Swap(a[j-1], a[j]); END; Trong cách viết trên, chương trình Bubble gọi chương trình Swap, đó để tính thời gian thực Bubble, trước hết ta cần tính thời gian thực Swap Dễ thấy thời gian thực Swap là O(1) vì nó bao gồm lệnh gán Trong Bubble, lệnh {3} gọi Swap nên tốn O(1), lệnh {2} thực n-i lần, lần tốn O(1) nên tốn O(n-i) Lệnh {1} thực n-1 lần nên n −1 T(n) = ∑ (n − i) = i =1 n(n − 1) = O(n2) 1.6 PHÂN TÍCH CÁC CHƯƠNG TRÌNH ÐỆ QUY Với các chương trình có gọi các chương trình đệ quy, ta không thể áp dụng cách tính vừa trình bày mục 1.5.4 vì chương trình đệ quy gọi chính thân nó Có thể thấy hình ảnh chương trình đệ quy A sau: A Hình 1-2: Sơ đồ chương trình A đệ quy Nguyễn Văn Linh Trang Lop12.net (13) Giải thuật Kĩ thuật phân tích giải thuật Với phương pháp tính độ phức tạp đã trình bày mục 1.5.4 thì không thể thực Bởi vì theo phương pháp đó thì, để tính thời gian thực hiên chương trình A, ta phải tính thời gian thực chương trình A và cái vòng luẩn quẩn không thể kết thúc Với các chương trình đệ quy, trước hết ta cần thành lập các phương trình đệ quy, sau đó giải phương trình đệ quy, nghiệm phương trình đệ quy là thời gian thực chương trình đệ quy 1.6.1 Thành lập phương trình đệ quy Phương trình đệ quy là phương trình biểu diễn mối liên hệ T(n) và T(k), đó T(n) là thời gian thực chương trình với kích thước liệu nhập là n, T(k) thời gian thực chương trình với kích thước liệu nhập là k, với k < n Ðể thành lập phương trình đệ quy, ta phải vào chương trình đệ quy Thông thường chương trình đệ quy để giải bài toán kích thước n, phải có ít trường hợp dừng ứng với n cụ thể và lời gọi đệ quy để giải bài toán kích thước k (k<n) Để thành lập phương trình đệ quy, ta gọi T(n) là thời gian để giải bài toán kích thước n, ta có T(k) là thời gian để giải bài toán kích thước k Khi đệ quy dừng, ta phải xem xét đó chương trình làm gì và tốn hết bao nhiêu thời gian, chẳng hạn thời gian này là c(n) Khi đệ quy chưa dừng thì phải xét xem có bao nhiêu lời gọi đệ quy với kích thước k ta có nhiêu T(k) Ngoài ta còn phải xem xét đến thời gian để phân chia bài toán và tổng hợp các lời giải, chẳng hạn thời gian này là d(n) Dạng tổng quát phương trình đệ quy là: T(n) = C(n) F(T(k)) + d(n) Trong đó C(n) là thời gian thực chương trình ứng với trường hợp đệ quy dừng F(T(k)) là đa thức các T(k) d(n) là thời gian để phân chia bài toán và tổng hợp các kết Ví dụ 1-10: Xét hàm tính giai thừa viết giải thuật đệ quy sau: FUNCTION Giai_thua(n:Integer): Integer; BEGIN IF n=0 then Giai_thua :=1 ELSE Giai_thua := n* Giai_thua(n-1); END; Gọi T(n) là thời gian thực việc tính n giai thừa, thì T(n-1) là thời gian thực việc tính n-1 giai thừa Trong trường hợp n = thì chương trình thực lệnh gán Giai_thua:=1, nên tốn O(1), đó ta có T(0) = C1 Trong trường hợp n>0 chương trình phải gọi đệ quy Giai_thua(n-1), việc gọi đệ quy này tốn T(n-1), sau có kết việc gọi đệ quy, chương trình phải nhân kết đó với n và gán cho Giai_thua Thời gian để thực phép nhân và phép gán là C2 Vậy ta có Nguyễn Văn Linh Trang Lop12.net (14) Giải thuật T(n) = Kĩ thuật phân tích giải thuật C1 nêu n = T(n - 1) + C nêu n > Ðây là phương trình đệ quy để tính thời gian thực chương trình đệ quy Giai_thua Ví du 1-11: Chúng ta xét thủ tục MergeSort cách phác thảo sau: FUNCTION MergeSort (L:List; n:Integer):List; VAR L1,L2:List; BEGIN IF n=1 THEN RETURN(L) ELSE BEGIN Chia đôi L thành L1 và L2, với độ dài n/2; RETURN(Merge(MergeSort(L1,n/2),MergeSort(L2,n/2))); END; END; Chẳng hạn để xếp danh sách L gồm phần tử 7, 4, 8, 9, 3, 1, 6, ta có mô hình minh họa MergeSort sau: 9 7 9 6 2 6 Hình 1-3: Minh hoạ xếp trộn Hàm MergeSort nhận danh sách có độ dài n và trả danh sách đã xếp Thủ tục Merge nhận hai danh sách đã L1 và L2 danh sách có độ dài n , trộn chúng lại với để danh sách gồm n phần tử có thứ tự Nguyễn Văn Linh Trang Lop12.net (15) Giải thuật Kĩ thuật phân tích giải thuật Giải thuật chi tiết Merge ta bàn sau, chúng ta để ý thời gian để Merge các danh sách có độ dài n là O(n) n Gọi T(n) là thời gian thực MergeSort danh sách n phần tử thì T( ) là thời gian thực MergeSort danh sách n phần tử Khi L có độ dài (n = 1) thì chương trình làm việc là return(L), việc này tốn O(1) = C1 thời gian Trong trường hợp n > 1, chương trình phải thực gọi đệ quy MergeSort hai lần cho L1 và L2 với độ dài n đó thời gian để gọi n hai lần đệ quy này là 2T( ) Ngoài còn phải tốn thời gian cho việc chia danh sách L thành hai nửa và trộn hai danh sách kết (Merge) Người ta xác đinh thời gian để chia danh sách và Merge là O(n) = C2n Vậy ta có phương trình đệ quy sau: T(n) = C1 nêu n = n 2T( ) + C n nêu n > 1.6.2 Giải phương trình đệ quy Có ba phương pháp giải phương trình đệ quy: 1.- Phương pháp truy hồi 2.- Phương pháp đoán nghiệm 3.- Lời giải tổng quát lớp các phương trình đệ quy 1.6.2.1 Phương pháp truy hồi Dùng đệ quy để thay T(m) với m < n vào phía phải phương trình tất T(m) với m > thay biểu thức các T(1) T(0) Vì T(1) và T(0) luôn là số nên chúng ta có công thức T(n) chứa các số hạng liên quan đến n và các số Từ công thức đó ta suy T(n) Ví dụ 1-12: Giải phương trình T(n) = C1 nêu n = T(n - 1) + C nêu n > Ta có T(n) = T(n-1) + C2 T(n) = [T(n-2) + C2] + C2 = T(n-2) + 2C2 T(n) = [T(n-3) + C2] + 2C2 = T(n-3) + 3C2 …… T(n) = T(n-i) + iC2 Quá trình trên kết thúc n - i = hay i = n Khi đó ta có T(n) = T(0) + nC2 = C1 + n C2 = O(n) Nguyễn Văn Linh Trang 10 Lop12.net (16) Giải thuật Kĩ thuật phân tích giải thuật Ví dụ 1-13: Giải phương trình T(n) = C1 nêu n = n 2T( ) + C n nêu n > n Ta có T(n) = 2T( ) + 2C n n n n T(n) = [ 2T( ) + C ] + C n = 4T( ) + 2C n 4 n n n T(n) = [ 2T( ) + C ] + 2C n = 8T( ) + 3C n 8 ……… T(n) = i T( n ) + iC n 2i Quá trình suy rộng kết thúc n i i = hay = n và đó i = logn Khi đó ta có: T(n) = nT(1) + lognC2n = C1n + C2nlogn = O(nlogn) 1.6.2.2 Phương pháp đoán nghiệm Ta đoán nghiệm f(n) và dùng chứng minh quy nạp để chứng tỏ T(n) ≤ f(n) với n Thông thường f(n) là các hàm quen thuộc logn, n, nlogn, n2, n3, 2n, n!, nn Ðôi chúng ta đoán dạng f(n) đó có vài tham số chưa xác định (chẳng hạn f(n) = an2 với a chưa xác định) và quá trình chứng minh quy nạp ta suy diễn giá trị thích hợp các tham số C1 nêu n = n 2T( ) + C n nêu n > Ví dụ 1-12: Giải phương trình đệ quy T(n) = Giả sử chúng ta đoán f(n) = anlogn Với n = ta thấy cách đoán không vì anlogn có giá trị không phụ thuộc vào giá trị a Vì ta thử f(n) = anlogn + b Với n = ta có, T(1) = C1 và f(1) = b, muốn T(1) ≤ f(1) thì b ≥ C1 (*) Giả sử T(k) ≤ f(k), tức là T(k) ≤ aklogk + b với k < n (giả thiết quy nạp) Ta phải chứng minh T(n) ≤ anlogn + b với n n Giả sử n ≥ 2, từ phương trình đã cho ta có T(n) = 2T( ) + C2n Áp dụng giả thiết quy nạp với k = n T(n) = 2T( ) + C2n n < n ta có: n ≤ 2[a log Nguyễn Văn Linh n + b] + C2n Trang 11 Lop12.net (17) Giải thuật Kĩ thuật phân tích giải thuật T(n) ≤ (anlogn - an + 2b) + C2n T(n) ≤ (anlogn + b) + [b + (C2 - a)n] Nếu lấy a ≥ C2 + b (**) ta T(n) ≤ (anlogn + b) + [b +(C2 - C2 - b )n ] T(n) ≤ (anlogn + b) + (1-n) b T(n) ≤ anlogn + b = f(n) (do b>0 và 1-n<0) Nếu ta lấy a và b cho (*) và (**) thoả mãn thì T(n) ≤ an logn + b với n Ta phải giải hệ ⎧ b ≥ C1 ⎨ ⎩a ≥ C + b Ðể đơn giản, ta giải hệ b = C1 a = C2 + b Dễ dàng ta có b = C1 và a = C1 +C2 ta T(n) ≤ (C1 + C2)nlogn +C1 với n Hay nói cách khác T(n) là O(nlogn) 1.6.2.3 Lời giải tổng quát cho lớp các phương trình đệ quy Khi thiết kế các giải thuật, người ta thường vận dụng phương pháp chia để trị mà ta bàn chi tiết chương Ở đây chi trình bày tóm tắt phương pháp sau: Ðể giải bài toán kích thước n, ta chia bài toán đã cho thành a bài toán con, bài toán có kích thước n Giải các bài toán này và tổng hợp kết lại để b kết bài toán đã cho Với các bài toán chúng ta áp dụng phương pháp đó để tiếp tục chia nhỏ các bài toán kích thước Kĩ thuật này dẫn chúng ta đến giải thuật đệ quy Giả thiết bài toán kích thước lấy đơn vị thời gian và thời gian để chia bài toán kích thước n thành các bài toán kích thước n và tổng hợp kết b từ các bài toán để lời giải bài toán ban đầu là d(n) (Chẳng hạn ví dụ MergeSort, chúng ta có a = b = 2, và d(n) = C2n Xem C1 là đơn vị) Tất các giải thuật đệ quy trên có thể thành lập phương trinh đệ quy tổng quát, chung cho lớp các bài toán n b Nếu gọi T(n) là thời gian để giải bài toán kích thước n thì T( ) là thời gian để giải bài toán kích thước n Khi n = theo giả thiết trên thì thời gian giải bài toán b kích thước là đơn vị, tức là T(1) = Khi n lớn 1, ta phải giải đệ quy a bài toán kích thước n n , bài toán tốn T( ) nên thời gian cho a lời giải đệ b b n b quy này là aT( ) Ngoài ta còn phải tốn thời gian để phân chia bài toán và tổng hợp các kết quả, thời gian này theo giả thiết trên là d(n) Vậy ta có phương trình đệ quy: Nguyễn Văn Linh Trang 12 Lop12.net (18) Giải thuật Kĩ thuật phân tích giải thuật neu n = n aT( ) + d(n) neu n > b T(n) = (I.1) Ta sử dụng phương pháp truy hồi để giải phương trình này Khi n > ta có n b T(n) = aT( ) + d(n) T(n)= a[aT( n n n n ) + d(n) ) + d( ) ] + d(n) = a T( ) + ad( b b b b T(n)= a [a T( = n n n n n n 3 ) + d ( ) ] + ad ( ) + d(n) = a T ( ) + a d ( ) + ad ( ) + d(n) b b b b b b i -1 n a = a T( i ) + ‡”a j d( j ) b b j= i Giả sử n = bk, quá trình suy rộng trên kết thúc i = k Khi đó ta T( n ) = T(1) = Thay vào trên ta có: bk k -1 T(n) = a + ‡”a j d (b k - j ) (I.2) k j= 1.6.2.3.1 Hàm tiến triển, nghiệm và nghiệm riêng Trong phương trình đệ quy (I.1) hàm thời gian d(n) gọi là hàm tiến triển (driving function) Trong công thức (I.2), ak = nlogba gọi là nghiệm (homogeneous solutions) Nghiệm là nghiệm chính xác d(n) = với n Nói cách khác, nghiệm biểu diễn thời gian để giải tất các bài toán k -1 Trong công thức (I.2), ‡”a d (b ) gọi là nghiệm riêng (particular solutions) j k- j j= Nghiệm riêng biểu diễn thời gian phải tốn để tạo các bài toán và tổng hợp các kết chúng Nhìn vào công thức ta thấy nghiệm riêng phụ thuộc vào hàm tiến triển, số lượng và kích thước các bài toán Khi tìm nghiệm phương trình (I.1), chúng ta phải tìm nghiệm riêng và so sánh với nghiệm Nếu nghiệm nào lớn hơn, ta lấy nghiệm đó làm nghiệm phương trình (I.1) Việc xác định nghiệm riêng không đơn giản chút nào, vậy, chúng ta tìm lớp các hàm tiến triển có thể dễ dàng xác định nghiệm riêng Nguyễn Văn Linh Trang 13 Lop12.net (19) Giải thuật Kĩ thuật phân tích giải thuật 1.6.2.3.2 Hàm nhân Một hàm f(n) gọi là hàm nhân (multiplicative function) f(m.n) = f(m).f(n) với số nguyên dương m và n Ví dụ 1-13: Hàm f(n) = nk là hàm nhân, vì f(m.n) = (m.n)k = mk.nk = f(m) f(n) Tính nghiệm phương trình tổng quát trường hợp d(n) là hàm nhân: Nếu d(n) (I.1) là hàm nhân thì theo tính chất hàm nhân ta có d(bk-j) = [d(b)]k-j và nghiệm riêng (I.2) là k -1 k -1 ‡”a d(b ) = ‡”a [d(b)] j j= j k- j k- j = [d(b)]k j= a ] ‡”[ d(b) j= a k - [d(b)]k Hay nghiệm riêng = a -1 d(b) [ k -1 j = [d(b)]k a k ] -1 d(b) a -1 d(b) (I.3) Xét ba trường hợp sau: 1.- Trường hợp 1: a > d(b) thì công thức (I.3) ta có ak > [d(b)]k, theo quy tắc lấy độ phức tạp ta có nghiệm riêng là O(ak) = O(nlogba) Như nghiệm riêng và nghiệm đó T(n) là O(nlogba) Trong trương hợp này ta thấy thời gian thực phụ thuộc vào a, b mà không phụ thuộc vào hàm tiến triển d(n) Vì để cải tiến giải thuật ta cần giảm a tăng b 2.- Trường hợp 2: a < d(b) thì công thức (I.3) ta có [d(b)]k > ak, theo quy tắc lấy độ phức tạp ta cónghiệm riêng là O([d(b)]k) = O(nlogbd(b)) Trong trường hợp này nghiệm riêng lớn nghiệm nên T(n) là O(nlogbd(b)) Ðể cải tiến giải thuật chúng ta cần giảm d(b) tăng b Trường hợp đặc biệt quan trọng d(n) = n Khi đó d(b) = b và logbb = Vì nghiệm riêng là O(n) và T(n) là O(n) 3.- Trường hợp 3: a = d(b) thì công thức (I.3) không xác đinh nên ta phải tính trực tiếp nghiệm riêng: Nghiệm riêng = [d(b)]k k -1 ‡”[ j= a j k ] =a d(b) k -1 ‡”1 = akk (do a = d(b)) j= Do n = bk nên k = logbn và ak = nlogba Vậy nghiệm riêng là nlogbalogbn và nghiệm này lớn gấp logbn lần nghiệm Do đó T(n) là O(nlogbalogbn) Chú ý giải phương trình đệ quy cụ thể, ta phải xem phương trình đó có thuộc dạng phương trình tổng quát hay không Nếu có thì phải xét xem hàm tiến triển có phải là hàm nhân không Nếu có thì ta xác định a, d(b) và dựa vào so sánh a và d(b) mà vận dụng ba trường hợp nói trên Nguyễn Văn Linh Trang 14 Lop12.net (20) Giải thuật Kĩ thuật phân tích giải thuật Ví dụ 1-14: Giải các phương trình đệ quy sau với T(1) = và n 1/- T(n) = 4T( ) + n n 2/- T(n) = 4T( ) + n2 n 3/- T(n) = 4T( ) + n3 Các phương trình đã cho có dạng phương trình tổng quát, các hàm tiến triển d(n) là các hàm nhân và a = 4, b = Với phương trình thứ nhất, ta có d(n) = n => d(b) = b = < a, áp dụng trường hợp ta có T(n) = O(nlogba) = O(nlog4) = O(n2) Với phương trình thứ hai, d(n) = n2 => d(b) = b2 = = a, áp dụng trường hợp ta có T(n) = O(nlogbalogbn) = O(nlog4logn) = O(n2logn) Với phương trình thứ 3, ta có d(n) = n3 => d(b) = b3 = > a, áp dụng trường hợp 2, ta có T(n) = O(nlogbd(b)) = O(nlog8) = O(n3) 1.6.2.3.3 Các hàm tiến triển khác Trong trường hợp hàm tiến triển không phải là hàm nhân thì chúng ta không thể áp dụng các công thức ứng với ba trường hợp nói trên mà chúng ta phải tính trực tiếp nghiệm riêng, sau đó so sánh với nghiệm để lấy nghiệm lớn hai nghiệm đó làm nghiệm phương trình Ví dụ 1-15: Giải phương trình đệ quy sau : T(1) = n T(n) = 2T( ) + nlogn Phương trình đã cho thuộc dạng phương trình tổng quát d(n) = nlogn không phải là hàm nhân Ta có nghiệm = nlogba = nlog2 = n Do d(n) = nlogn không phải là hàm nhân nên ta phải tính nghiệm riêng cách xét trực tiếp k -1 Nghiệm riêng = j j= k -1 k -1 ‡”a d (b ) = ‡”2 k- j j k- j log2 k - j = 2k ‡”(k - j) = k j= j= k ( k + 1) = O(2kk2) Theo giả thiết phương trình tổng quát thì n = bk nên k = logbn, đây b = nên 2k = n và k = logn, chúng ta có nghiệm riêng là O(nlog2n), nghiệm này lớn nghiệm đó T(n) = O(nlog2n) Nguyễn Văn Linh Trang 15 Lop12.net (21)

Ngày đăng: 09/06/2021, 05:47

Xem thêm:

TỪ KHÓA LIÊN QUAN

TÀI LIỆU CÙNG NGƯỜI DÙNG

  • Đang cập nhật ...

TÀI LIỆU LIÊN QUAN