1. Trang chủ
  2. » Công Nghệ Thông Tin

Giáo trình Cấu trúc dữ liệu và giải thuật: Phần 1 - ĐH Sư phạm kỹ thuật Nam Định

102 11 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

Thông tin cơ bản

Tiêu đề Giáo trình Cấu trúc dữ liệu và giải thuật: Phần 1
Trường học Đại Học Sư Phạm Kỹ Thuật Nam Định
Chuyên ngành Cấu trúc dữ liệu và giải thuật
Thể loại Giáo trình
Thành phố Nam Định
Định dạng
Số trang 102
Dung lượng 831,44 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Cấu trúc

  • CHƯƠNG 1: MỞ ĐẦU (4)
    • 1.1. Giải thuật (4)
      • 1.1.1 Khái niệm giải thuật (4)
      • 1.1.2. Các đặc trưng của giải thuật (0)
    • 1.2. Cấu trúc dữ liệu và các vấn đề liên quan (0)
      • 1.2.1. Cấu trúc dữ liệu và giải thuật (5)
      • 1.2.2. Cấu trúc dữ liệu và ngôn ngữ lập trình (5)
    • 1.3. Ngôn ngữ diễn đạt giải thuật (6)
      • 1.3.1. Đặt vấn đề (6)
      • 1.3.2. Quy cách về cấu trúc chương trình (7)
      • 1.3.3. Ký tự và biểu thức (7)
      • 1.3.4. Các câu lệnh (7)
  • CHƯƠNG 2 THIẾT KẾ VÀ PHÂN TÍCH GIẢI THUẬT (11)
    • 2.1. Từ bài toán đến chương trình (11)
      • 2.1.1 Mô - đun hoá và việc giải quyết bài toán (11)
      • 2.1.2. Phương pháp tinh chỉnh từng bước (13)
    • 2.2. Phân tích giải thuật (24)
      • 2.2.1. Đặt vấn đề (24)
      • 2.2.2. Phân tích thời gian thực hiện giải thuật (24)
    • 2.3. Bài tập (32)
  • CHƯƠNG 3 ĐỆ QUY VÀ GIẢI THUẬT ĐỆ QUY (35)
    • 3.1. Khái niệm về đệ quy (35)
    • 3.2. Giải thuật đệ quy và chương trình con đệ quy (35)
    • 3.3. Thiết kế giải thuật đệ quy (37)
      • 3.3.1. Hàm N ! (37)
      • 3.3.2. Bài toán Tháp Hà Nội (38)
      • 3.3.3. Bài toán 8 quân hậu và giải thuật quay lui (40)
    • 3.4. Hiệu lực của đệ quy (44)
    • 3.5. Đệ quy và quy nạp toán học (45)
    • 3.6. Bài tập (48)
  • CHƯƠNG 4: MẢNG VÀ DANH SÁCH (50)
    • 4.1. Các khái niệm (50)
    • 4.2. Cấu trúc lưu trữ của mảng (0)
    • 4.3. Lưu trữ kế tiếp của danh sách tuyến tính (54)
    • 4.4. Ngăn xếp (Stack) (55)
      • 4.4.1. Định nghĩa (55)
      • 4.4.2. Lưu trữ Stack kế tiếp (55)
      • 4.4.3. Các giải thuật PUSH, POP (56)
      • 4.4.4. Ứng dụng của Stack (58)
      • 4.4.5. Stack và việc cài đặt thủ tục đệ quy (63)
    • 4.5. Hàng đợi (Queue) (66)
      • 4.5.1. Định nghĩa (66)
      • 4.5.2. Lưu trữ Queue kế tiếp (66)
      • 4.5.3. Các giải thuật chèn (INSERT), xoá (DELETE) (67)
    • 4.6. Bài tập (69)
  • CHƯƠNG 5: DANH SÁCH MÓC NỐI (73)
    • 5.1. Danh sách nối đơn (73)
      • 5.1.1. Nguyên tắc (73)
      • 5.1.2. Một số giải thuật (74)
    • 5.2. Danh sách nối vòng (76)
      • 5.2.1. Nguyên tắc (76)
      • 5.2.2. Một số giải thuật (77)
    • 5.3. Danh sách nối kép (78)
      • 5.3.1. Nguyên tắc (78)
      • 5.3.2. Một số giải thuật (79)
    • 5.4. Ví dụ áp dụng (81)
      • 5.4.1. Biểu diễn đa thức (81)
      • 5.4.2. Giải thuật cộng hai đa thức (82)
      • 5.4.3. Biểu diễn tập hợp (84)
      • 5.4.3. Các phép toán (84)
    • 5.5. Ngăn xếp và Hàng đợi móc nối (88)
    • 5.6. Cấu trúc đa danh sách (0)
      • 5.6.1. Biểu diễn ma trận thưa (91)
      • 5.6.2. Một số giải thuật (92)
    • 5.7. Danh sách tổng quát (96)
      • 5.7.1. Định nghĩa (96)
      • 5.7.2. Biểu diễn danh sách tổng quát (96)
      • 5.7.3. Một số giải thuật xử lý danh sách tổng quát (97)
    • 5.8. Bài tập (101)
    • 5.9. Kiểm tra (102)
  • CHƯƠNG 6 CÂY (0)
    • 6.1. Định nghĩa và khái niệm (0)
    • 6.2. Cây nhị phân (0)
      • 6.2.1. Định nghĩa và tính chất (0)
      • 6.2.2. Biểu diễn cây nhị phân (0)
      • 6.2.3. Phép duyệt cây nhị phân (0)
    • 6.3. Cây nhị phân nối vòng (0)
      • 6.3.1. Khái niệm và lưu trữ (0)
      • 6.3.2. Các giải thuật (0)
    • 6.4. Cây tổng quát (0)
      • 6.4.1. Biểu diễn cây tổng quát (0)
      • 6.4.2. Giải thuật duyệt cây tổng quát (0)
      • 6.4.3. Áp dụng (0)
    • 6.5. Bài tập (0)
    • 6.6. Kiểm tra (0)
  • CHƯƠNG 7 SẮP XẾP (0)
    • 7.1. Đặt vấn đề (0)
    • 7.2. Một số phương pháp sắp xếp (0)
      • 7.2.1. Sắp xếp lựa chọn (selection - Sort) (0)
      • 7.2.2. Sắp xếp thêm dần (Insert - Sort) (0)
      • 7.2.3. Sắp xếp nổi bọt (Bubble - Sort) (0)
      • 7.2.4. Sắp xếp nhanh (Quick- Sort) (0)
      • 7.2.5. Sắp xếp vun đống (Heap –Sort) (0)
      • 7.2.6. Sắp xếp hoà nhập (Merge – Sort) (0)
    • 7.3. Phân tích đánh giá các thuật toán (0)
    • 7.4. Bài tập (0)
  • CHƯƠNG 8: TÌM KIẾM (0)
    • 8.1. Bài toán tìm kiếm (0)
    • 8.2. Tìm kiếm tuần tự (0)
    • 8.3. Tìm kiếm nhị phân (0)
    • 8.4. Cây nhị phân tìm kiếm (0)
      • 8.4.1. Định nghĩa (0)
      • 8.4.2. Các giải thuật (0)
    • 8.5. Bài tập – Tổng kết và ôn tập (0)
  • TÀI LIỆU THAM KHẢO (0)

Nội dung

Giáo trình Cấu trúc dữ liệu và giải thuật: Phần 1 cung cấp cho người học những kiến thức như: Cấu trúc dữ liệu và các vấn đề liên quan; Ngôn ngữ diễn đạt giải thuật. Mời các bạn cùng tham khảo để nắm chi tiết nội dung giáo trình!

THIẾT KẾ VÀ PHÂN TÍCH GIẢI THUẬT

Từ bài toán đến chương trình

2.1.1 Mô - đun hoá và việc giải quyết bài toán

Các bài toán trên máy tính điện tử ngày càng đa dạng và phức tạp, đòi hỏi các giải thuật và chương trình ngày càng lớn và khó khăn trong việc thiết lập cũng như tìm hiểu.

Việc phân chia bài toán lớn thành các bài toán nhỏ giúp đơn giản hóa quá trình giải quyết Bằng cách xem bài toán chính như một mô-đun, ta có thể chia nó thành các mô-đun con, và tiếp tục phân chia cho đến khi đạt được những phần việc cơ bản mà ta đã biết cách giải quyết Như vậy, cấu trúc tổ chức lời giải sẽ được thể hiện dưới dạng phân cấp.

Chiến thuật giải quyết bài toán theo tinh thần như vậy chính là chiến thuật

Chiến thuật "chia để trị" (divide and conquer) được thể hiện qua phương pháp thiết kế "đỉnh- xuống" (top-down design) Phương pháp này bắt đầu bằng việc phân tích tổng quát vấn đề, dựa trên dữ kiện và mục tiêu đã đặt ra, để xác định những công việc chính Sau đó, quy trình sẽ tiến dần vào việc giải quyết các phần cụ thể một cách chi tiết hơn, do đó được gọi là thiết kế từ khái quát đến chi tiết Ví dụ, khi nhận được yêu cầu từ chủ tịch hội đồng xét cấp học bổng của trường, chúng ta sẽ áp dụng phương pháp này để xử lý thông tin hiệu quả.

Sử dụng máy tính điện tử để quản lý và duy trì hồ sơ học bổng cho sinh viên được tài trợ, đồng thời cần lập báo cáo tổng kết định kỳ để trình lên bộ.

Để giải quyết bài toán, trước tiên cần hình dung rõ ràng về đầu vào và đầu ra Chúng ta có một tập hồ sơ, hay còn gọi là tệp file, chứa các bản ghi thông tin liên quan đến học bổng của sinh viên.

Hệ thống quản lý học bổng cần xử lý thông tin bao gồm số hiệu sinh viên, điểm trung bình theo học kỳ, điểm đạo đức và khoản tiền tài trợ Chương trình phải hỗ trợ người dùng trong việc đáp ứng các yêu cầu liên quan đến quản lý học bổng hiệu quả.

1 Tìm lại và hiển thị được bản ghi của bất kỳ sinh viên nào tại thiết bị cuối (terminal) của người dùng

2 Cập nhập (update) được bản ghi của một sinh viên cho trước bằng cách thay đổi điểm trung bình, điểm đạo đức, khoản tiền tài trợ, nếu cần

3 In bản tổng kết chứa những thông tin hiện thời ( đã được cập nhập mỗi khi có thay đổi) gồm số liệu, điểm trung bình, điểm đạo đức, khoản tiền tài trợ

Xuất phát từ những nhận định nêu trên, giải thuật xử lý sẽ phải giải quyết ba nhiệm vụ chính như sau:

1 Những thông tin về sinh viên được học bổng, lưu trữ trên đĩa phải được đọc vào bộ nhớ trong để có thể xử lý ( ta gọi là nhiệm vụ “đọc tệp”)

2 Xử lý các thông tin này để tạo ra kết quả mong muốn (nhiệm vụ ”xử lý tệp”)

3 Sao chép những thông tin đã được cập nhập vào tệp trên đĩa để lưu trữ cho việc xử lý sau này (nhiệm vụ ”ghi tệp”)

Có thể hình dung, cách thiết kế này theo sơ đồ cấu trúc ở hình 2.2

Các nhiệm vụ ở mức đầu thường phức tạp và cần được chia thành các nhiệm vụ con Ví dụ, nhiệm vụ “xử lý tệp” có thể được phân thành ba phần, tương ứng với ba yêu cầu chính đã được đề cập.

1) Tìm lại bản ghi của một sinh viên cho trước

2) Cập nhập thông tin trong bản ghi sinh viên

3) In bản tổng kết những thông tin về các sinh viên được học bổng Những nhiệm vụ con này cũng có thể được chia thành những nhiệm vụ nhỏ hơn Có thể hình dung theo sơ đồ cấu trúc như sau:

Tìm bản ghi Cập nhật bản ghi In bản tổng

Tìm kiếm Hiển thị bản ghi Tìm kiếm Cập nhật

Thiết kế giải thuật theo phương pháp top-down giúp định hướng rõ ràng trong việc giải quyết bài toán, ngăn chặn việc sa đà vào các chi tiết không cần thiết Phương pháp này cũng là nền tảng cho lập trình có cấu trúc.

Đối với các bài toán lớn, việc giải quyết thường cần sự hợp tác của nhiều người Phương pháp mô-đun hóa giúp tách bài toán thành các phần độc lập, cho phép các nhóm làm việc mà không ảnh hưởng đến nhau Chương trình xây dựng dựa trên các giải thuật thiết kế theo cách này sẽ dễ dàng hơn trong việc tìm hiểu, sửa chữa và chỉnh lý.

Việc chia nhỏ bài toán thành các bài toán con không hề đơn giản Do đó, trong nhiều trường hợp, quá trình phân tích và thiết kế thuật toán để giải quyết bài toán có thể tốn nhiều thời gian và công sức hơn cả việc lập trình.

2.1.2 Phương pháp tinh chỉnh từng bước

Tinh chỉnh từng bước là phương pháp thiết kế giải thuật gắn liền với lập trình

Nó phản ánh tinh thần của quá trình mô-đun hoá bài toán thiết kế kiểu top-down

Chương trình bắt đầu bằng việc trình bày giải thuật qua ngôn ngữ tự nhiên, phản ánh rõ ràng ý chính của công việc cần thực hiện Qua từng bước, các ý tưởng sẽ được chi tiết hóa dần, tương ứng với những công việc nhỏ hơn.

Quá trình tinh chỉnh trong lập trình bao gồm nhiều bước, bắt đầu từ ngôn ngữ tự nhiên và dần chuyển sang ngôn ngữ lập trình cụ thể Ở các giai đoạn trung gian, người ta sử dụng giả ngôn ngữ (pseudo-language) hay giả mã (pseudo code) để kết hợp cả hai loại ngôn ngữ, giúp mô tả thuật toán và phát triển chương trình một cách rõ ràng hơn Quá trình này tiến từ việc xác định "là cái gì" đến "làm thế nào", ngày càng sát với các chức năng của ngôn ngữ lập trình đã chọn Đồng thời, dữ liệu cũng được tinh chế từ cấu trúc tổng quát đến dạng lưu trữ cụ thể.

Giả sử ta muốn lập một chương trình sắp xếp một dãy n số nguyên khác nhau theo thứ tự tăng dần

Phân tích giải thuật

Khi xây dựng giải thuật và chương trình, việc phân tích tính đúng đắn của giải thuật là rất quan trọng để xác định liệu nó có giải quyết chính xác bài toán hay không Thông thường, người ta thực hiện thử nghiệm trên máy với các bộ dữ liệu để so sánh kết quả, nhưng phương pháp này chỉ giúp phát hiện sai sót mà không đảm bảo tính đúng đắn Để chứng minh tính đúng đắn của giải thuật, có thể sử dụng các công cụ toán học, tuy nhiên, công việc này thường phức tạp và không dễ dàng.

Yêu cầu thứ hai liên quan đến tính đơn giản của giải thuật, thường được mong muốn vì dễ hiểu, dễ lập trình và dễ chỉnh sửa Tuy nhiên, giải pháp đơn giản không phải lúc nào cũng hiệu quả, có thể dẫn đến lãng phí thời gian và bộ nhớ Đối với chương trình sử dụng ít lần, tính đơn giản rất quan trọng do công sức và thời gian đầu tư lớn Ngược lại, nếu chương trình được sử dụng nhiều lần, đặc biệt với dữ liệu lớn, thì tốc độ thực hiện và tiết kiệm bộ nhớ trở nên quan trọng hơn Việc cân bằng giữa yêu cầu về thời gian và bộ nhớ thường không dễ dàng đạt được.

Trong bài viết này, chúng ta sẽ tập trung vào việc phân tích thời gian thực hiện của giải thuật, một tiêu chí quan trọng để đánh giá hiệu quả của nó.

2.2.2 Phân tích thời gian thực hiện giải thuật

Trong việc giải quyết một bài toán, không chỉ tồn tại một giải thuật duy nhất Việc lựa chọn một giải thuật hiệu quả và nhanh chóng là điều cần thiết Tuy nhiên, cần có tiêu chí rõ ràng để so sánh độ nhanh chóng của các giải thuật khác nhau.

Thời gian thực hiện một giải thuật phụ thuộc vào nhiều yếu tố, trong đó kích thước dữ liệu đầu vào là yếu tố quan trọng nhất Chẳng hạn, thời gian sắp xếp một dãy số sẽ bị ảnh hưởng bởi số lượng các số trong dãy đó Nếu ký hiệu n là số lượng này, thì thời gian thực hiện T của giải thuật cần được biểu diễn dưới dạng 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ữ lập trình và chương trình dịch đều ảnh hưởng đến thời gian thực hiện, nhưng không đồng đều giữa các loại máy khác nhau Do đó, không thể xác định T(n) dựa trên đơn vị thời gian cụ thể như giây hay phút Tuy nhiên, vẫn có thể so sánh tốc độ của các giải thuật Ví dụ, nếu T1(n) = cn² và T2(n) = kn (với c và k là hằng số), thì khi n lớn, T2(n) thực hiện nhanh hơn T1(n) Điều này cho thấy thời gian thực hiện T(n) tỷ lệ với n² hay n, từ đó cung cấp khái niệm về tốc độ thực hiện giải thuật khi n lớn Việc đánh giá thời gian thực hiện giải thuật độc lập với máy tính dẫn đến khái niệm “cấp độ lớn của thời gian thực hiện giải thuật” hay “độ phức tạp tính toán của giải thuật”.

1) Độ phức tạp tính toán của giải thuật

Nếu thời gian thực hiện của một thuật toán được biểu diễn bằng T(n) = cn² (với c là hằng số), thì độ phức tạp tính toán của thuật toán này có cấp độ n² Điều này có nghĩa là thời gian thực hiện của thuật toán tăng theo bình phương kích thước đầu vào n.

Hàm f(n) được xác định là O(g(n)) khi tồn tại các hằng số c và n0 sao cho f(n) ≤ cg(n) với mọi n ≥ n0, nghĩa là f(n) bị chặn trên bởi một hằng số nhân với g(n) từ một điểm nhất định Các hàm này thường biểu thị độ phức tạp tính toán của thuật toán, bao gồm các dạng như: log2n, n, nlog2, n², n³, 2ⁿ, n!, và nⁿ.

Sau đây là đồ thị và bảng giá trị của một số hàm đó

Các hàm như 2^n, n! và n^n được phân loại là hàm loại mũ, trong khi đó các hàm như n^3, n^2, n log₂ n, n và log₂ n thuộc loại hàm đa thức Thời gian thực hiện của các thuật toán có cấp độ hàm mũ thường rất chậm, trong khi thuật toán có cấp độ hàm đa thức thường được coi là chấp nhận được.

2) Các quy tắc xác định độ phức tạp tính toán của giải thuật

Xác định độ phức tạp tính toán của một thuật toán có thể dẫn đến những bài toán phức tạp Tuy nhiên, một số thuật toán có thể được phân tích dễ dàng bằng các quy tắc đơn giản.

* Quy tắc tổng : Giả sử T1(n) và T 2 (n) là thời gian thực hiện của hai đoạn chương trình P1 và 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 và P 2 tiếp theo sẽ là: T 1 (n) + T 2 (n) = O(max (f(n),g(n))

Trong một chương trình có ba bước thực hiện với thời gian lần lượt là O(n²), O(n³) và O(n log² n), thời gian thực hiện của hai bước đầu tiên sẽ là O(max(n², n³)) = O(n³) Do đó, thời gian thực hiện tổng thể của chương trình sẽ là O(max(n³, n log² n)) = O(n³).

Một vài ứng dụng khác của quy tắc này đó là nếu g(n) ≤ f(n) với mọi n ≥ n0 thì O(f(n)+g(n)) cũng là O(f(n)) Chẳng hạn: O(n 4 +n 2 ) = O(n 4 ) và O(n + log 2 n) O(n)

* Quy tắc nhân: Giả sử T 1 (n) và T 2 (n) là thời gian thực hiện của hai đoạn chương trình P1 và 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 và P 2 lồng nhau sẽ là: T 1 (n).T 2 (n) = O(f(n).g(n))

Ví dụ: Câu lệnh gán : x := x+1 có thời gian thực hiện bằng c (hằng số) nên được đánh giá là O(1)

Câu lệnh: for i:= 1 to n do x :=x+1;

Có thời gian thực hiện O(n.1) = O(n)

Câu lệnh : for i := 1 to n do for j := 1 to n do x :=x+1; có thời gian thực hiện được đánh giá là: O(n.n)=O(n 2 )

Cũng có thể thấy O(cf(n)) = O(f(n))

(phần chứng minh hai quy tắc trên xin dành cho độc giả)

Khi đánh giá thời gian thực hiện của thuật toán, cần chú ý đến các bước tương tự với phép toán tích cực, là phép toán có thời gian thực hiện không ít hơn các phép toán khác Điều này có nghĩa là số lần thực hiện phép toán tích cực không được ít hơn so với các phép toán khác trong thuật toán.

Bây giờ ta xét tới một giải thuật cụ thể:

Giải thuật tính giá trị của e x theo công thức gần đúng: e x = 1 + x/1! +x 2 /2! + …+ x n /n! với x và n cho trước

{tính từng số hạng rồi cộng lại}

2 for i:=1 to n do begin p : =1; for j:= 1 to n do p:=p*x/j;

Ta có thể coi phép toán tích cực ở đây là phép: p := p*x/j

Ta thấy nó được thực hiện:

1 +2+…+ n = n(n+1)/2 lần Vậy thời gian thực hiện giải thuật này được đánh giá là T(n) = O(n 2 )

Ta có thể viết giải thuật theo một cách khác

Bây giờ thời gian thực hiện lại là: T(n) = O(n) Vì phép gán p:=p*x/i chỉ thực hiện n lần

Thời gian thực hiện thuật toán không chỉ phụ thuộc vào kích thước dữ liệu đầu vào mà còn bị ảnh hưởng bởi tình trạng của dữ liệu đó.

Khi sắp xếp một dãy số theo thứ tự tăng dần, việc phân tích thời gian thực hiện thuật toán cần xem xét các trường hợp khác nhau: dãy đã được sắp xếp, dãy chưa có thứ tự hoặc có thứ tự ngược lại Đối với mỗi kích thước dữ liệu n, ta cần xác định T(n) trong trường hợp thuận lợi nhất, xấu nhất và trung bình Tuy nhiên, việc xác định T(n) trung bình thường gặp khó khăn do yêu cầu các công cụ toán học đặc biệt và nhiều cách quan niệm khác nhau Trong những trường hợp khó xác định T(n) trung bình, người ta thường đánh giá thuật toán dựa trên giá trị xấu nhất của T(n) Thuật toán sau đây sẽ giúp làm rõ hơn vấn đề này.

{cho vectơ V có n phần tử, giải thuật này thực hiện tìm trong V một phần tử có giá trị bằng X cho trước}

1 Found := false; {found là biến logic để báo hiệu việc ngừng tìm khi đã thấy} i :=1;

2 while i X[j+1] then begin temp := X[j];

Function Euclid (m, n : integer) :integer; var r : integer ; begin r := m mod n; (1) while r 0 do (2) begin m := n; (3) n :=r; (4) r := m mod n; (5) end;

10 Để tính giá trị của đa thức P n (x) khi cho x có hai thuật giải:

Cách 1 Tính từng số hạng của đa thức rồi cộng lại

Cách 2 Dùng phương pháp Horne

Để tính thời gian thực hiện của hai giải thuật trên, ta cần phân tích độ phức tạp của từng thuật toán Ngoài ra, để tìm đồng thời giá trị cực đại và cực tiểu của dãy n phần tử mà không sử dụng quá 3n/2 phép so sánh, cần xây dựng một giải thuật hiệu quả, tối ưu hóa số phép so sánh trong quá trình tìm kiếm.

11 Cho mảng A chứa n- 1 số nguyên khác nhau trong khoảng từ [0, n-1], nghĩa là có một số nguyên trong khoảng trên không nằm trong A Tìm thuật giải với thời gian O(n) để tìm ra số này mà chỉ dùng thêm O(1) không gian nhớ ngoài mảng A

12 Mảng 2 chiều A nxn mỗi phần tử là một bít 0 hoặc 1 Giả sử trong mọi dòng của A, tất cả các bít 1 đều đi trước tất cả các bít 0 trong hàng Viết giải thuật với thời gian O(n) để tìm ra dòng chứa nhiều bít 1 nhất.

ĐỆ QUY VÀ GIẢI THUẬT ĐỆ QUY

Khái niệm về đệ quy

Đệ quy là công cụ quan trọng trong khoa học máy tính và toán học, giúp giải quyết nhiều vấn đề phức tạp Trong khoa học máy tính, đệ quy được ứng dụng trong lý thuyết và giải thuật, cũng như trong việc định nghĩa cú pháp của các ngôn ngữ lập trình như Pascal và C Ngoài ra, đệ quy còn được sử dụng để giải quyết các vấn đề trong lý thuyết trò chơi và trên các cấu trúc dữ liệu Trong toán học, đệ quy đóng vai trò quan trọng trong các bài toán tổ hợp và xác suất.

Một đối tượng hoặc vấn đề được coi là đệ quy khi nó bao gồm chính nó như một phần trong cấu trúc của nó, hoặc khi nó được định nghĩa thông qua chính nó.

Trên truyền hình, đôi khi ta thấy hình ảnh đệ quy, như một phát thanh viên ngồi bên máy vô tuyến truyền hình và trên màn hình lại hiện hình ảnh của chính anh ta Tương tự, trong toán học, các định nghĩa đệ quy cũng thường xuất hiện.

1) Số tự nhiên: a) 1 là một số tự nhiên b) x là số tự nhiên nếu x-1 là số tự nhiên

2) Hàm n giai thừa: a) 0! =1 b) Nếu n > 0 thì n! = n(n-1)!

Giải thuật đệ quy và chương trình con đệ quy

Nếu một bài toán T được giải bằng cách áp dụng lời giải của một bài toán T' có cấu trúc tương tự, thì đó được gọi là lời giải đệ quy Thuật toán tương ứng với loại lời giải này được gọi là giải thuật đệ quy.

Thoạt nghe thì có vẻ hơi lạ, nhưng điểm mấu chốt cần lưu ý là: T‟ tuy có dạng giống như T, nhưng theo một nghĩa nào đó, nó phải “nhỏ” hơn T

Để một bài toán giải theo phương pháp đệ quy có tính chất đệ quy và tránh việc lặp vô hạn, cần phải thỏa mãn hai điều kiện cơ bản.

- Có thể biểu diễn bài toán cần giải thông qua bài toán cùng dạng, đơn giản hơn ( điều kiện tồn tại tính đệ quy)

- Có điều kiện dừng( để không bị gọi bất tận)

Tìm từ trong từ điển

Tìm từ trong từ điển nửa trước

Tìm từ trong từ điển nửa sau

Hãy xét bài toán tìm một từ trong một quyển từ điển Có thể nêu giải thuật như sau:

If từ điển là một trang Then tìm từ trong trang này

Mở từ điển vào trang “giữa”;

Xác định xem nửa nào của từ điển chứa từ cần tìm;

If từ đó nằm ở nửa trước của từ điển Then tìm từ đó trong nửa trước Else tìm từ đó trong nửa sau

Tất nhiên giải thuật trên mới chỉ được nêu dưới dạng thô, còn nhiều chỗ chưa cụ thể, chẳng hạn như:

- Tìm từ trong một trang thì làm thế nào?

- Thế nào là mở từ điển vào trang giữa?

- Làm thế nào để biết từ đó nằm ở nửa nào của từ điển? v.v

Trả lời rõ những câu hỏi trên không phải là khó, nhưng ta sẽ không sa vào các chi tiết này mà muốn tập trung vào việc xét

Hình 3.1 Chiến thuật của lời giải: Có thể hình dung chiến thuật của tìm kiếm này một cách khái quát như hình 3.1

Trong quá trình tách đôi từ điển, có hai điểm chính cần lưu ý: Thứ nhất, sau mỗi lần tách, một nửa thích hợp sẽ được tìm kiếm bằng chiến thuật đã sử dụng trước đó Thứ hai, có một trường hợp đặc biệt, gọi là trường hợp suy biến, xảy ra khi từ điển chỉ còn một trang Khi đó, việc tách đôi ngừng lại và bài toán trở nên đủ nhỏ để giải quyết trực tiếp bằng cách tìm tuần tự Đây là một ứng dụng của chiến thuật “chia để trị”, trong đó bài toán được phân chia thành các bài toán nhỏ hơn cho đến khi xuất hiện trường hợp suy biến.

Bây giờ ta hãy thể hiện chiến thuật tìm kiếm này dưới dạng một thủ tục Procedure SEARCH (dict, word)

{dict được coi là đầu mối để truy nhập được vào từ điển đang xét, word chỉ từ cần tìm}

1 if từ điển chỉ còn một trang then tìm từ word trong một trang này

2 Mở từ điển vào trang “giữa”

Xác định xem nửa nào của từ điển chứa từ trong word;

If word nằm ở nửa trước của từ điển Then call SEARCH (dict 1, word) Else call SEARCH (dict 2, word)

{dict 1, dict 2 là đầu mối để truy nhập được vào nửa trước và nửa sau của từ điển}

Thủ tục đệ quy là một phương pháp trong lập trình, trong đó một thủ tục gọi chính nó, như ví dụ trong thủ tục SEARCH Mỗi lần gọi lại thủ tục, kích thước bài toán giảm đi, ví dụ từ điển chỉ còn một nửa kích thước ban đầu Có trường hợp đặc biệt gọi là suy biến, khi từ điển chỉ còn một trang, lúc này bài toán sẽ được giải quyết theo cách khác và quá trình đệ quy kết thúc Một số ngôn ngữ lập trình cao cấp như ALGOL, PL/1, và PASCAL cho phép viết thủ tục đệ quy Nếu thủ tục gọi chính nó, đó là đệ quy trực tiếp; còn nếu nó gọi thủ tục khác mà trong đó lại gọi lại thủ tục ban đầu, thì gọi là đệ quy gián tiếp.

Thiết kế giải thuật đệ quy

3.3.1 Hàm N ! Định nghĩa đệ quy của n! như sau:

Giải thuật đệ quy được viết dưới dạng hàm:

1- if n=0 then FACTORIAL := 1 else FACTORIAL := n*FACTORIAL(n-1)

2- return Đối chiếu với 3 đặc điểm của thủ tục đệ quy ở trên ta thấy:

- Lời gọi tới chính nó ở đây nằm trong câu lệnh gán đứng sau else

- Ở mỗi lần gọi đệ quy đến FACTORIAL, thì giá trị của n giảm đi 1, Ví dụ FACTORIAL(4) FACTORIAL(3) FACTORIAL(2)

3.3.2 Bài toán Tháp Hà Nội Đây là một bài toán mang tính chất một trò chơi, nội dung như sau:

Có một bộ đĩa với kích thước nhỏ dần, mỗi đĩa có lỗ ở giữa giống như đĩa hát Các đĩa này có thể được xếp chồng lên nhau qua một cọc, với đĩa lớn ở dưới và đĩa nhỏ ở trên, tạo thành một hình tháp đẹp mắt.

Hình 3.2 Chuyển chồng đĩa từ cọc A sang cọc khác, chẳng hạn sang cọc C theo những điều kiện:

1- Mỗi lần chỉ được chuyển một đĩa

2- Không khi nào có tình huống đĩa to ở trên đĩa nhỏ (dù là tạm thời) 3- Được phép sử dụng một cọc trung gian, chẳng hạn cọc B dùng để đặt tạm đĩa Để đi tới cách giải tổng quát, trước hết xét vài trường hợp đơn giản

*Trường hợp một đĩa: Chuyển từ cọc A sang cọc C

*Trường hợp chuyển hai đĩa:

- Chuyển đĩa thứ nhất từ cọc A sang cọc B

- Chuyển đĩa thứ hai từ cọc A sang cọc C

- Chuyển đĩa thứ nhất từ cọc B sang cọc C

Trong trường hợp có n đĩa (n>2), nếu coi (n-1) đĩa ở trên như là đĩa thứ nhất, ta có thể xử lý bài toán tương tự như trường hợp có 2 đĩa.

- Chuyển (n-1) đĩa trên từ A sang B

- Chuyển đĩa thứ n từ A sang C

Lược đồ thể hiện 3 bước này như sau:

Bài toán "tháp Hà Nội" với n đĩa có thể được rút gọn thành bài toán tương tự với số lượng đĩa nhỏ hơn Cụ thể, để chuyển n đĩa từ cọc A sang cọc C, ta trước tiên chuyển (n-1) đĩa từ cọc A sang cọc B Giải thuật cho bước này sẽ được áp dụng để tiếp tục giải quyết bài toán.

- Chuyển (n-2) đĩa từ cọc A sang cọc C

- Chuyển 1 đĩa từ cọc A sang cọc B

- Chuyển (n-2) đĩa từ cọc C sang cọc B

Và cứ như thế cho tới khi trường hợp suy biến xảy ra, đó là trường hợp ứng với bài toán chuyển 1 đĩa thôi

Các đặc điểm của đệ quy trong giải thuật đã được xác định, và từ đó, chúng ta có thể xây dựng giải thuật đệ quy cho bài toán “Tháp Hà Nội” một cách rõ ràng và mạch lạc.

1- if n=1 then chuyển đĩa từ A sang C

2- else begin call HANOI (n-1, A, C, B); call HANOI (1, A, B, C); call HANOI (n-1, B, A, C); end

3- return 3.3.3 Bài toán 8 quân hậu và giải thuật quay lui

Bàn cờ quốc tế là một bảng hình vuông với 8 hàng và 8 cột Quân hậu có khả năng ăn bất kỳ quân cờ nào nằm trên cùng hàng, cột hoặc đường chéo Bài toán đặt ra là xếp 8 quân hậu trên bàn cờ sao cho không quân hậu nào có thể ăn được quân khác, tức là mỗi hàng, mỗi cột và mỗi đường chéo chỉ được phép có một quân hậu duy nhất.

Không nên tìm lời giải cho bài toán 8 quân hậu bằng cách kiểm tra từng trường hợp trên bàn cờ Thay vào đó, phương pháp “thử từng bước” là một giải pháp thực tiễn, giúp xác định tất cả các cách sắp xếp mà không có quân hậu nào có thể ăn nhau, với tổng số cách sắp xếp là 92.

Phương pháp giải quyết bài toán 8 quân hậu dựa trên nguyên tắc thử và sai, nơi mỗi bước đi tới lời giải được thực hiện thông qua việc thử nghiệm các lựa chọn Nếu một lựa chọn được chấp nhận, thông tin sẽ được ghi nhớ để tiếp tục thử nghiệm bước tiếp theo Ngược lại, nếu không có lựa chọn nào phù hợp, quá trình sẽ quay lại bước trước, xóa bỏ các ghi nhớ và tiếp tục với các lựa chọn còn lại Hành động này được gọi là quay lui, và các giải thuật liên quan được gọi là giải thuật quay lui Đối với bài toán 8 quân hậu, mỗi cột chỉ có thể chứa một quân hậu, vì vậy cần thử nghiệm vị trí an toàn cho quân hậu thứ j tại cột j, đảm bảo không trùng hàng hay đường chéo với các quân hậu đã được xếp trước đó Để tìm ra lời giải, cần thử tất cả các cách sắp xếp quân hậu ở cột 1, và với mỗi vị trí, bài toán 7 quân hậu sẽ được giải quyết cho phần còn lại của bàn cờ, thể hiện tính chất đệ quy của bài toán.

1 Khởi phát cho việc chọn vị trí cho quân hậu thứ j

2 repeat thực hiện phép chọn tiếp theo; if an toàn then begin đặt quân hậu; if j 0 chỉ thị đứng sau else

Sẽ được thực hiện Vậy với n = k+1 thì giá trị cho ra là

(k+1)* FACTORIAL(k) nghĩa là (k+1)*k(k-1)*…*2*1 và việc chứng minh đã hoàn tất

2 Đánh giá giải thuật tháp HANOI

Khi xét số lượng đĩa n trong bài toán Tháp Hà Nội, ta cần xác định số lần di chuyển đĩa Trong thuật toán này, mỗi phép di chuyển đĩa được coi là một phép toán tích cực.

Giả sử ta gọi Moves(n) là số đó, ta có Moves (1) = 1

Khi n >1 thì Moves (n) không thể tính trực tiếp như vậy nhưng ta biết rằng : nếu biết Moves (n-1) thì ta sẽ tính được Moves(n):

Moves(n) = Moves(n-1) + Moves(1) + Moves(n-1) (dựa vào giải thuật )

Vậy ta xác định được mối quan hệ truy hồi của cách tính:

Moves (n) = 2* Moves (n-1) +1 nếu n>1 ví dụ: Moves (3) =2* Moves(2) +1

Tuy nhiên công thức truy hồi này không cho ta tính trực tiếp theo n được Nếu để ý ta thấy: Moves(1) = 1= 2 1 -1

Vậy phải chăng: Moves (n) = 2 n -1 với n là số tự nhiên bất kỳ?

Ta sẽ chứng minh công thức tính này đúng bằng qui nạp toán học

Với n= 1, Moves (1) = 2 1 -1=1 công thức đã đúng

Giả sử công thức đã đúng với n=k, nghĩa là:

Với n = k+1 theo công thức tính truy hồi

Công thức đã được xác nhận đúng với k+1, do đó nó cũng đúng với mọi giá trị n Một công cụ phổ biến trong việc phân tích các giải thuật đệ quy là cây đệ quy, giúp người dùng đánh giá sự tiêu tốn bộ nhớ và thời gian chạy của các giải thuật này.

Sự chiếm dụng bộ nhớ trong thuật toán đệ quy tỷ lệ thuận với cấp đệ quy, tức là tỷ lệ với chiều sâu của cây đệ quy, và không phụ thuộc vào số lượng nút có trong cây.

Thời gian chạy của giải thuật thường được xác định bằng cách đếm số tác vụ cần thực hiện trên cây đệ quy Chẳng hạn, trong bài toán tháp Hà Nội, cấu trúc của cây đệ quy sẽ được biểu diễn như sau:

Sự chiếm dụng bộ nhớ: Tỉ lệ với chiều sâu (cao) của cây: O(n), với n là số đĩa cần chuyển

Sự chiếm dụng thời gian: Tỉ lệ với số lần thực hiện t ác vụ chuyển một đĩa:

Tác vụ chuyển một đĩa

Bài tập

3.1 Xét định nghĩa đệ quy:

Hàm này được gọi là hàm Ackermann Nó có đặc điểm là giá trị của nó tăng rất nhanh, ứng với giá trị nguyên của m và n

- Viết một thủ tục đệ quy thực hiện tính giá trị hàm này

3.2 Giải thuật tính ước số chung lớn nhất của hai số nguyên dương p và q (p > q) được mô tả như sau:

Gọi r là số dư trong phép chia p cho q

- Nếu r= 0 thì q là ước số chung lớn nhất

Để xây dựng hàm USCLN (q, p) theo định nghĩa đệ quy, nếu r # 0, ta gán p = q, q = r và lặp lại quá trình Cần viết một giải thuật đệ quy và một giải thuật lặp để thể hiện hàm này Đặc điểm của giải thuật đệ quy trong trường hợp này là khả năng gọi lại chính nó với các tham số mới cho đến khi đạt được điều kiện dừng Để xử lý trường hợp giá trị q lớn hơn p, giải thuật cần phải đảm bảo rằng p luôn là số nhỏ hơn hoặc bằng q trước khi thực hiện các bước tiếp theo.

3.3 Hàm C(n,k) với n, k là các giá trị nguyên không âm và k  n , được định nghĩa:

C(n, k) = C(n-1, k-1)+C(n-1, k) nếu 0 < k < n a) Viết một thủ tục đệ quy thực hiện tính giá trị C(n, k) khi biết n, k b) Chứng minh rằng thủ tục này cho ra đúng giá trị

3.4 Hãy nêu rõ các bước thực hiện khi có lời gọi call HANOI (4, A, B, C)

3.5 Viết một thủ tục đệ quy thực hiện in ngược một dòng ký tự cho trước, ví dụ cho dòng “PASCAL” thì in ra “LACSAP”

3.6 Viết một thủ tục đệ quy nhằm in ra tất cả các hoán vị của n phần tử của một dãy số a= {a 1 , a 2 ,…,a n } Ví dụ n=3, a1=1, a2=2, a3=3 thì in ra: 1 2 3; 1 3 2; 2 1 3; 2 3 1; 3 1 2; 3 2 1;

(Gợi ý Hãy để ý nhận xét: 123 132 231

) , ker( n m khi n m Ac m Ac n khi m

3.7 Viết giải thuật đệ quy xác định chiều dài của một xâu kí tự

3.8 Viết giải thuật đệ quy đổi một số nguyên dương n từ hệ thập phân sang hệ đếm cơ số a

3.9 Viết giải thuật đệ quy tìm số lớn nhất của một dãy số: a1, a2, , an

3.10 Viết giải thuật đệ quy kiểm tra một xâu kí tự có phải là xâu xuôi ngược (palindrome) không

3.11 Hãy viết giải thuật đệ quy tính tổng n số nguyên dương đầu tiên

3.12 Hãy viết giải thuật đệ quy tính tổng n số nguyên dương lẻ đầu tiên

3.13 Hãy viết lời giải và giải thuật đệ quy tính wi trong đó i là một số nguyên không âm và wi biểu diễn phép ghép i bản sao của xâu w

3.14 Trên bàn cờ 8x8 hãy viết giải thuật đi con mã 64 nước sao cho mỗi ô chỉ đi qua một lần (xuất phát từ một ô bất kỳ) Ví dụ một lời giải:

3.15 Viết giải thuật đệ quy:

- Liệt kê các xâu nhi phân có độ dài n

- Liệt kê các tập con m phần tử của tập n phần tử

- Liệt kê hoán vị của n phần tử.

MẢNG VÀ DANH SÁCH

DANH SÁCH MÓC NỐI

CÂY

SẮP XẾP

TÌM KIẾM

Ngày đăng: 08/06/2021, 14:11

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

TÀI LIỆU LIÊN QUAN

🧩 Sản phẩm bạn có thể quan tâm