Giáo trình Cấu trúc dữ liệu và giải thuật (Nghề Lập trình máy tính)

136 9 0
Giáo trình Cấu trúc dữ liệu và giải thuật (Nghề Lập trình máy tính)

Đ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Ộ NÔNG NGHIỆP VÀ PHÁT TRIỂN NÔNG THÔN TRƯỜNG CAO ĐẲNG CƠ GIỚI NINH BÌNH GIÁO TRÌNH MƠN HỌC: MH19_CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT NGHỀ: LẬP TRÌNH MÁY TÍNH TRÌNH ĐỘ: Cao đẳng/ trung cấp Ban hành kèm theo Quyết định số: /QĐ-…TCGNB ngày…….tháng….năm Hiệu trưởng Trường Cao Đẳng Cơ giới Ninh Bình Ninh Bình TUYÊN BỐ BẢN QUYỀN - Tài liệu thuộc loại sách giáo trình nên nguồn thơng tin phép dùng nguyên trích dùng cho mục đích đào tạo tham khảo - Mọi mục đích khác mang tính lệch lạc sử dụng với mục đích kinh doanh thiếu lành mạnh bị nghiêm cấm Lời giới thiệu Các kiến thức cấu trúc liệu (CTDL) giải thuật đóng vai trị quan trọng việc đào tạo nghề Lập trình máy tính Sách đựơc hình thành sở giảng CTDL giải thuật mà đồng nghiệp đọc nhiều năm khoa Toán-Cơ-Tin học - Trường Đại học Khoa học Tự nhiên – Đại học Quốc Gia Hà Nội; Khoa Công nghệ thông tin - Đại học Bách Khoa Hà Nội; Khoa Công nghệ thông tin - Đại học Giao thông vận tải Sách biên soạn chủ yếu để làm tài liệu tham khảo cho học sinh, sinh viên nghề Lập trình máy tính, bổ ích cho độc giả khác cần có hiểu biết đầy đủ CTDL giải thuật Giáo trình gồm bốn chương Chương Giới thiệu cấu trúc liệu giải thuật Chương Kiểu liệu nâng cao Chương Danh sách Chương Ngăn xếp hàng đợi Chương Sắp xếp tìm kiếm Để biên soạn giáo trình này, chúng tơi tham khảo tài liệu: Cấu trúc liệu giải thuật, PTS Đinh Mạnh Tường; Lê Minh Hoàng, Cấu trúc liệu giải thuật Giáo trình Cấu trúc liệu giải thuật Hổi đồng thẩm định Trường Cao đẳng nghề Cơ Giới Ninh Bình xét duyệt Tuy nhiên q trình biên soạn khơng tránh khỏi sai sót, mong đóng góp quý báu chân thành bạn đọc Ninh Bình, ngày tháng năm 2018 Tham gia biên soạn: Chủ biên Đoàn Xuân Luận Phạm Thị Thoa Nguyễn Anh Văn Mục lục Lời giới thiệu Mục lục Chương Giới thiệu cấu trúc liệu giải thuật Mối liên hệ cấu trúc liệu giải thuật .9 1.1 Xây dựng cấu trúc liệu 1.2 Xây dựng giải thuật 1.3 Mối quan hệ cấu trúc liệu giải thuật .10 Kiểu liệu mơ hình liệu 10 2.1 Biểu diễn liệu .10 2.3 Hệ kiểu ngôn ngữ Pascal 14 2.4 Mô hình liệu kiểu liệu trừu tượng 16 Thiết kế giải thuật 20 3.1 Các tiêu chuẩn đánh giá cấu trúc liệu 20 3.2 Đánh giá độ phức tạp thuật toán 21 Chương .22 Các kiểu liệu nâng cao 22 Mảng .22 Con trỏ 24 2.1 Con trỏ địa 24 2.2 Con trỏ mảng chiều .26 2.2.2 Tên mảng địa 26 2.2.3 Con trỏ trỏ tới phần tử mảng chiều 26 2.3 Con trỏ mảng nhiều chiều 30 2.4 Kiểu trỏ, kiểu địa chỉ, phép toán trỏ 32 Cấu trúc hợp .39 3.1 Cấu trúc (struct) 39 3.2 Kiểu union 40 File 41 4.1 Khái niệm tệp tin 41 4.2 Khai báo sử dụng tệp - số hàm thường dùng thao tác tệp 43 Chương .49 Danh sách 49 Các khái niệm .49 1.1 Khái niệm danh sách 49 1.2 Các phép toán danh sách 49 Lưu tữ danh sách tuyến tính 51 2.1 Định nghĩa 51 2.2 Danh sách liên kết đơn (Singly Linked List) 51 Lưu trữ móc nối danh sách tuyến tính 76 3.1 Cấu trúc liệu 76 3.2 Các thao tác danh sách 78 Chương .100 Ngăn xếp hàng đợi 100 Định nghĩa ngăn xếp (stack) .100 Lưu trữ stack mảng 102 2.1 Khởi tạo ngăn xếp 102 2.2 Thêm (Đẩy) phần tử vào ngăn xếp (Push) .102 2.3 Lấy nội dung phần tử ngăn xếp để xử lý (Pop) 103 2.4 Hủy ngăn xếp 104 3.Ví dụ ứng dụng stack 104 Định nghĩa hàng đợi(Queue) 108 Lưu trữ queue mảng 110 5.1 Khởi tạo hàng đợi (Initialize) .110 5.2 Thêm (Đưa) phần tử vào hàng đợi (Add) 111 5.3 Lấy nội dung phần tử hàng đợi để xử lý (Get) 112 5.4 Hủy hàng đợi 113 Stack queue móc nối 113 6.1 Stack móc nối .113 6.2 Queue móc nối 116 Chương .119 Sắp xếp tìm kiếm 119 Giới thiệu xếp tìm kiếm 119 1.1 Giới thiệu xếp 119 1.2 Giới thiệu tìm kiếm 120 Các phương pháp xếp 121 2.1 Sắp xếp kiểu chọn (Selection sort) .121 2.2 Thuật toán xếp bọt (bubble sort) 122 2.3 Thuật toán xếp kiểu chèn (insertion sort) .122 2.4 Thuật toán xếp kiểu phân đoạn (quick sort) 125 2.5 Thuật toán xếp trộn 129 Các phương pháp tìm kiếm 134 3.1 Tìm kiếm (Sequential search) 134 3.2 Tìm kiếm nhị phân (Binary search) 134 TÀI LIỆU THAM KHẢO 136 MÔN HỌC CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT Tên Môn học: Cấu trúc liệu giải thuật Mã mơn học: MH19 Vị trí, tính chất, ý nghĩa vai trị mơn học: - Vị trí mơn học: Mơn học học sau mơn học Tin học bản, Lập trình - Tính chất mơn học: Mơn học u cầu phải có tư logic kiến thức lập trình bản, lập trình hướng đối tượng - Ý nghĩa, vai trị mơn học: Đây mơn học sở ngành ngành liên quan đến công nghệ thông tin, cung cấp cho sinh viên kiến thức lập trình Mục tiêu mơn học: - Kiến thức: + Trình bày mối liên hệ cấu trúc liệu giải thuật; cách khai báo sử dụng kiểu liệu nâng cao; + Trình bày kỹ thuật ngăn xếp hàng đợi, thuật toán xếp tìm kiếm, loại danh sách liên kết - Kỹ năng: + Phân tích loại liệu, giải thuật kết hợp liệu giải thuật; + Cài đặt thuật toán xếp tìm kiếm; + Cài đặt thuật tốn cấu trúc liệu: mảng, danh sách, danh sách liên kết - Thái độ: + Rèn luyện tính cẩn thận, tỉ mỉ, xác, sáng tạo, làm việc độc lập theo nhóm; + Rèn luyện kỹ lập trình; + Đảm bảo an tồn cho người trang thiết bị Nội dung môn học: Số Tên chương mục Thời gian TT I II III IV IV Tổng số Chương 1: Giới thiệu cấu trúc liệu giải thuật Mỗi liên hệ cấu trúc liệu giải thuật Kiểu liệu mơ hình liệu Thiết kế giải thuật Chương 2: Kiểu liệu nâng cao 20 Kiểu mảng Con trỏ Cấu trúc hợp File Chương 3: Danh sách 20 Các khái niệm Lưu trữ danh sách tuyến tính Lưu trữ móc nối danh sách tuyến tính Chương 4: Ngăn xếp hàng đợi 20 Định nghĩa ngăn xếp (stack) Lưu trữ stack mảng 3.Ví dụ ứng dụng stack 4 Định nghĩa hàng đợi(Queue) Lưu trữ queue mảng Stack queue móc nối Chương 5: Sắp xếp tìm kiếm 25 Giới thiệu xếp tìm kiếm Các phương pháp xếp 10 Các phương pháp tìm kiếm 12 Cộng 90 Lý thuyết Thực hành Kiểm tra 2 1 2 14 4 3 13 5 1 1 2 2 30 11 3 18 56 1 Chương Giới thiệu cấu trúc liệu giải thuật Mã chương: MH19_CH01 Giới thiệu: Bài giới thiệu mối liên hệ cấu trúc liệu giải thuật 1 Mục tiêu: - Trình bày kiến thức cở cấu trúc liệu, giải thuật, kiểu liệu, mơ hình liệu; - Phân tích giải thuật; - Sử dụng phương pháp phân tích, thiết kế giải thuật; - Rèn luyện tính cẩn thận, tỉ mỉ, xác, sáng tạo, thực thao tác an tồn với máy tính Nội dung: Mối liên hệ cấu trúc liệu giải thuật 1.1 Xây dựng cấu trúc liệu - Có thể nói khơng có chương trình máy tính mà khơng có liệu để xử lý Dữ liệu liệu đưa vào (input data), liệu trung gian liệu đưa (output data) Do vậy, việc tổ chức để lưu trữ liệu phục vụ cho chương trình có ý nghĩa quan trọng tồn hệ thống chương trình Việc xây dựng cấu trúc liệu định lớn đến chất lượng cơng sức người lập trình việc thiết kế, cài đặt chương trình 1.2 Xây dựng giải thuật - Khái niệm giải thuật hay thuật giải mà nhiều cịn gọi thuật tốn dùng để phương pháp hay cách thức (method) để giải vần đề Giải thuật minh họa ngôn ngữ tự nhiên (natural language), sơ đồ (flow chart) mã giả (pseudo code) Trong thực tế, giải thuật thường minh họa hay thể mã giả tựa hay số ngơn ngữ lập trình (thường ngơn ngữ mà người lập trình chọn để cài đặt thuật tốn), chẳng hạn C, Pascal, … - Khi xác định cấu trúc liệu thích hợp, người lập trình bắt đầu tiến hành xây dựng thuật giải tương ứng theo yêu cầu toán đặt sở cấu trúc liệu chọn Để giải vấn đề có nhiều phương pháp, lựa chọn phương pháp phù hợp việc mà người lập trình phải cân nhắc tính tốn Sự lựa chọn góp phần đáng kể việc giảm bớt cơng việc người lập trình phần cài đặt thuật tốn ngơn ngữ cụ thể 1.3 Mối quan hệ cấu trúc liệu giải thuật - Mối quan hệ cấu trúc liệu Giải thuật minh họa đẳng thức: Cấu trúc liệu + Giải thuật = Chương trình - Như vậy, có cấu trúc liệu tốt, nắm vững giải thuật thực việc thể chương trình ngơn ngữ cụ thể vấn đề thời gian Khi có cấu trúc liệu mà chưa tìm thuật giải khơng thể có chương trình ngược lại khơng thể có Thuật giải chưa có cấu trúc liệu Một chương trình máy tính hồn thiện có đầy đủ Cấu trúc liệu để lưu trữ liệu Giải thuật xử lý liệu theo yêu cầu toán đặt Kiểu liệu mơ hình liệu 2.1 Biểu diễn liệu - Trong máy tính điện tử (MTĐT), liệu dù có chất khác (số nguyên, số thực, hay xâu ký tự, ), biểu diễn dạng nhị phân Mỗi liệu biểu diễn dạng dãy số nhị phân Về mặt kỹ thuật cách biểu diễn thích hợp nhất, giá trị dễ dàng mã hoá phần tử vật lý có hai trạng thái Chúng ta không quan tâm đến cách biểu diễn liệu, cách tiến hành thao tác, phép toán liệu biểu diễn dạng nhị phân - Cách biểu diễn nhị phân liệu không thuận tiện người Việc xuất ngôn ngữ lập trình bậc cao (FORTRAN, BASIC, PASSCAL, C ) giải phóng người khỏi khó khăn làm việc với cách biểu diễn máy liệu Trong ngơn ngữ lập trình bậc cao, liệu, hiểu theo nghĩa đó, trìu tượng hố tính chất đối tượng giới thực Nói liệu trìu tượng hố từ giới thực, ta bỏ qua nhân tố, tính chất mà ta cho khơng bản, giữ lại tính chất đặc trưng cho đối tượng thuộc phạm vi tốn xét Chẳng hạn, vị trí đối tượng thực tiễn, đặc trưng cặp số thực (x,y) (đó toạ đoạ đê-các điểm mặt phẳng) Do đó, ngơn ngữ Pascal, vị trí đối tượng biểu diễn ghi gồm hai 10 Đối với phương pháp kiểu lựa chọn, ta coi phép so sánh (kj < kjmin) phép tốn tích cực để đánh giá hiệu suất thuật toán mặt thời gian Ở lượt thứ i, để chọn khoá nhỏ cần n - i phép so sánh, số lượng phép so sánh khơng phụ thuộc vào tình trạng ban đầu dãy khố Từ suy tổng số phép so sánh phải thực là: (n - 1) + (n - 2) + + = n * (n - 1) / Vậy thuật tốn xếp kiểu chọn có cấp O(n2) 2.2 Thuật toán xếp bọt (bubble sort) Trong thuật toán xếp bọt, dãy khoá duyệt từ cuối dãy lên đầu dãy (từ kn k1), gặp hai khoá kế cận bị ngược thứ tự đổi chỗ chúng cho Sau lần duyệt vậy, phần tử nhỏ dãy khố chuyển vị trí vấn đề trở thành xếp dãy khoá từ k2 tới kn: Mã giả: procedure BubbleSort; var i, j: Integer; begin for i := to n for j := n downto i do{Duyệt từ cuối dãy lên, làm khoá nhỏ số ki1, ,kn vị trí i-1} if kj < kj-1 then end; Đối với thuật toán xếp bọt, ta coi phép tốn tích cực phép so sánh kj < kj-1 Và số lần thực phép so sánh là: (n - 1) + (n - 2) + + = n * (n - 1) / Vậy thuật toán xếp bọt có cấp O(n2) Bất kể tình trạng liệu vào 2.3 Thuật toán xếp kiểu chèn (insertion sort) Xét dãy khoá k1, k2, , kn Ta thấy dãy gồm khố k1 coi xếp Xét thêm k2, ta so sánh với k1, thấy k2 < k1 122 chèn vào trước k1 Đối với k3, ta lại xét dãy gồm khoá k1, k2 xếp tìm cách chèn k3 vào dãy khố để thứ tự xếp Một cách tổng quát, ta xếp dãy k1, k2, , ki điều kiện dãy k1, k2, , ki-1 xếp cách chèn ki vào dãy vị trí xếp Mã giả: procedure InsertionSort; var i, j: Integer; tmp: TKey; {Biến giữ lại giá trị khoá chèn} begin for i := to n {Chèn giá trị ki vào dãy k1, , ki-1 để toàn đoạn k1, k2, , ki trở thành xếp} begin tmp := ki; {Giữ lại giá trị ki} j := i - 1; while (j > 0) and (tmp < kj) {So sánh giá trị cần chèn với khoá kj (i-1≥j≥0)} begin kj+1 := kj; {Đẩy lùi giá trị kj phía sau vị trí, tạo "khoảng trống" vị trí j} j := j - 1; end; kj+1 := tmp; {Đưa giá trị chèn vào "khoảng trống" tạo ra} end; end; Đối với thuật tốn xếp kiểu chèn, chi phí thời gian thực thuật tốn phụ thuộc vào tình trạng dãy khố ban đầu Nếu coi phép tốn tích cực phép so sánh tmp < kj thì: - Trường hợp tốt ứng với dãy khoá xếp rồi, lượt cần phép so sánh, tổng số phép so sánh thực n - 123 - Trường hợp tồi tệ ứng với dãy khoá có thứ tự ngược với thứ tự cần lượt thứ i, cần có i - phép so sánh tổng số phép so sánh là: (n - 1) + (n - 2) + + = n * (n - 1) / - Trường hợp giá trị khoá xuất cách ngẫu nhiên, ta coi xác suất xuất khố đồng khả năng, coi lượt thứ i, thuật tốn cần trung bình i / phép so sánh tổng số phép so sánh là: (1 / 2) + (2 / 2) + + (n / 2) = (n + 1) * n / Nhìn kết đánh giá, ta thấy thuật toán xếp kiểu chèn tỏ tốt so với thuật toán xếp chọn xếp bọt Tuy nhiên, chi phí thời gian thực thuật toán xếp kiểu chèn cịn lớn Và xét phương diện tính tốn lý thuyết cấp thuật tốn xếp kiểu chèn O(n2) Có thể cải tiến thuật toán xếp chèn nhờ nhận xét: Khi dãy khoá k1, k2, , ki-1 xếp việc tìm vị trí chèn làm thuật tốn tìm kiếm nhị phân kỹ thuật chèn làm lệnh dịch chuyển vùng nhớ cho nhanh Tuy nhiên điều khơng làm tốt cấp độ phức tạp thuật toán trường hợp xấu nhất, ta phải n - lần chèn lần chèn thứ i ta phải dịch lùi i khoá để tạo khoảng trống trước đẩy giá trị khố chèn vào chỗ trống procedure InsertionSortwithBinarySearching; var i, inf, sup, median: Integer; tmp: TKey; begin for i := to n begin tmp := ki; {Giữ lại giá trị ki} inf := 1; sup := i - 1; {Tìm chỗ chèn giá trị tmp vào đoạn từ kinf tới ksup+1} repeat {Sau vòng lặp đoạn tìm bị co lại nửa} median := (inf + sup) div 2; {Xét số nằm số inf số sup} if tmp < k[median] then sup := median - else inf := median + 1; until inf > sup; {Kết thúc vòng lặp inf = sup + vị trí chèn} 124 kinf := tmp; {Đưa giá trị tmp vào "khoảng trống" tạo ra} end; end; 2.4 Thuật toán xếp kiểu phân đoạn (quick sort) Quick Sort phương pháp xếp tốt nhất, nghĩa dù dãy khoá thuộc kiểu liệu có thứ tự nào, Quick Sort xếp khơng có thuật tốn xếp nhanh Quick Sort mặt tốc độ trung bình (theo tơi biết) Người sáng lập C.A.R Hoare mạnh dạn đặt tên cho xếp "NHANH" Ý tưởng chủ đạo phương pháp tóm tắt sau: Sắp xếp dãy khố k1, k2, , kn coi xếp đoạn từ số tới số n dãy khố Để xếp đoạn dãy khố, đoạn có ≤ phần tử khơng cần phải làm cả, cịn đoạn có phần tử, ta chọn khố ngẫu nhiên đoạn làm "chốt" Mọi khố nhỏ khố chốt xếp vào vị trí đứng trước chốt, khoá lớn khoá chốt xếp vào vị trí đứng sau chốt Sau phép hốn chuyển đoạn xét chia làm hai đoạn khác rỗng mà khoá đoạn đầu ≤ chốt khoá đoạn sau ≥ chốt Hay nói cách khác: Mỗi khố đoạn đầu ≤ khoá đoạn sau Và vấn đề trở thành xếp hai đoạn tạo (có độ dài ngắn đoạn ban đầu) phương pháp tương tự Mã giả: procedure QuickSort; procedure Partition(L, H: Integer); {Sắp xếp đoạn từ kL, kL+1, , kH} var i, j: Integer; Key: TKey; {Biến lưu giá trị khoá chốt} begin if L ≥ H then Exit; {Nếu đoạn có ≤ phần tử khơng phải làm cả} Key := kRandom(H-L+1)+L; {Chọn khố ngẫu nhiên đoạn làm khoá chốt} 125 i := L; j := H; {i := vị trí đầu đoạn; j := vị trí cuối đoạn} repeat while ki < Key i := i + 1; {Tìm từ đầu đoạn khố ≥ khoá chốt} while kj > Key j := j - 1; {Tìm từ cuối đoạn khố ≤ khố chốt} {Đến ta tìm hai khố ki kj mà ki ≥ key ≥ kj} if i ≤ j then begin if i < j then {Nếu số i đứng trước số j đảo giá trị hai khoá ki kj} {Sau phép đảo ta có: ki ≤ key ≤ kj } i := i + 1; j := j - 1; end; until i > j; Partition(L, j); Partition(i, H); {Sắp xếp hai đoạn tạo ra} end; begin Partition(1, n); end; Ta thử phân tích xem đoạn chương trình hoạt động đúng: Xét vòng lặp repeat until lần lặp đầu tiên, vịng lặp while thứ chắn tìm khoá ki ≥ khoá chốt chắn tồn đoạn khố khóa chốt Tương tự vậy, vịng lặp while thứ hai chắn tìm khoá kj ≤ khoá chốt Nếu khoá ki đứng trước khố kj ta đảo giá trị hai khố, tăng i giảm j Khi ta có nhận xét khố đứng trước vị trí i phải ≤ khoá chốt khoá đứng sau vị trí j phải ≥ khố chốt kL ki kj kH ≤ khoá chốt ≥ khoá chốt Điều đảm bảo cho vòng lặp repeat until bước sau, hai vòng lặp while bên chắn lại tìm hai khố ki kj mà ki ≥ khoá chốt ≥ kj, khoá ki đứng trước khố kj lại đảo giá trị chúng, cho i tiến cuối bước j lùi đầu bước Vậy q trình hốn chuyển phần tử vòng lặp repeat until đảm bảo bước: 126 Hai vòng lặp while bên ln tìm hai khố ki, kj mà ki ≥ khố chốt ≥ kj Khơng có trường hợp hai số i, j chạy ngồi đoạn (ln ln có L ≤ i, j ≤ H) Sau phép hốn chuyển, khố đứng trước vị trí i ln ≤ khố chốt khố đứng sau vị trí j ln ≥ khố chốt Vịng lặp repeat until kết thúc mà số i đứng phía sau số j ≥ khoá chốt kL kj ki kH ≤ khoá chốt Theo nhận xét trên, có khố nằm kj ki khố phải khố chốt đặt vị trí nó, nên bỏ qua khoá mà xét hai đoạn hai đầu Cơng việc cịn lại gọi đệ quy để làm tiếp với đoạn từ kL tới kj đoạn từ ki tới kH Hai đoạn ngắn đoạn xét L ≤ j < i ≤ H Vậy thuật tốn khơng bị rơi vào q trình vơ hạn mà dừng cho kết đắn Xét độ phức tạp tính tốn: Trường hợp tồi tệ nhất, chọn khoá chốt, ta chọn phải khoá nhỏ hay lớn đoạn, phép phân đoạn chia thành đoạn gồm n - phần tử đoạn cịn lại có phần tử Có thể chứng minh trường hợp này, thời gian thực giải thuật T(n) = O(n2) Trường hợp tốt nhất, phép phân đoạn bước chia thành hai đoạn Tức chọn khoá chốt, ta chọn trung vị dãy khố Có thể chứng minh trường hợp này, thời gian thực giải thuật T(n) = O(nlog2n) Trường hợp khoá phân bố ngẫu nhiên, trung bình thời gian thực giải thuật T(n) = O(nlog2n) Việc tính tốn chi tiết, đặc biệt xác định T(n) trung bình, phải dùng cơng cụ tốn phức tạp, ta công nhận kết Chú ý: Vài cải tiến Quick Sort Việc chọn chốt cho phép phân đoạn định hiệu Quick Sort, chọn chốt khơng tốt, việc phân đoạn bị suy biến thành trường hợp xấu khiến Quick Sort hoạt động chậm tràn ngăn xếp chương trình gặp phải dây chuyền đệ qui dài Một cải tiến sau khắc phục tượng tràn ngăn xếp chậm trường hợp xấu, kỹ thuật phân 127 [L, H] hai đoạn [L, j] [i, H] gọi đệ quy để tiếp tục đoạn ngắn, lặp lại trình phân đoạn đoạn dài procedure QuickSort; procedure Partition(L, H: Integer); {Sắp xếp đoạn từ kL, kL+1, , kH} var i, j: Integer; begin repeat if L ≥ H then Exit; if then begin Partition(L, j); L := i; end else begin Partition(i, R); R := j; end; until False; end; begin Partition(1, n); end; Cải tiến thứ hai Quick Sort trình phân đoạn nên làm đến mức đó, đến đoạn xét có độ dài ≤ M (M số nguyên tự chọn nằm khoảng từ tới 25) khơng phân đoạn tiếp mà nên áp dụng thuật toán xếp kiểu chèn Cải tiến thứ ba Quick Sort là: Nên lấy trung vị dãy đoạn để làm chốt, (trung vị dãy n phần tử phần tử đứng thứ n / thứ tự) Cách chọn đánh giá cao chọn trung vị ba phần tử đầu, cuối đoạn 128 Cuối cùng, ta có nhận xét: Quick Sort cơng cụ xếp mạnh, có điều khó chịu gặp phải trường hợp suy biến Quick Sort (quá trình phân đoạn chia thành dãy ngắn dãy dài) Và điều phương diện lý thuyết khơng thể khắc phục được: Ví dụ với n = 10000 - Nếu chọn chốt khoá đầu đoạn (Thay dịng chọn khố chốt Key := kL) hay chọn chốt khoá cuối đoạn (Thay Key := kH) với dãy sau, chương trình hoạt động chậm: (1, 2, 3, 4, 5, , 9999, 10000) - Nếu chọn chốt khoá đoạn (Thay dịng chọn khố chốt Key := k(L+H) div 2) với dãy sau, chương trình chậm: (1, 2, , 4999, 5000, 5000, 4999, , 2, 1) - Trong trường hợp chọn chốt trung vị dãy hay chọn chốt ngẫu nhiên, thật khó tìm liệu khiến cho Quick Sort hoạt động chậm Nhưng ta cần hiểu với chiến lược chọn chốt, 10000! dãy hoán vị dãy (1, 2, 10000) có dãy làm Quick Sort bị suy biến, nhiên trường hợp chọn chốt ngẫu nhiên, xác suất xảy dãy nhỏ tới mức ta không cần phải tính đến, chọn chốt ngẫu nhiên ta khơng cần phải quan tâm tới ngăn xếp đệ quy, không cần quan tâm tới kỹ thuật khử đệ quy vấn đề suy biến Quick Sort 2.5 Thuật toán xếp trộn 2.5.1 Phép trộn đường Phép trộn đường phép hợp hai dãy khoá xếp để ghép lại thành dãy khố có kích thước tổng kích thước hai dãy khoá ban đầu dãy khoá tạo thành có thứ tự xếp Nguyên tắc thực đơn giản: so sánh hai khố đứng đầu hai dãy, chọn khoá nhỏ đưa vào miền xếp (một dãy khố phụ có kích thước tổng kích thước hai dãy khố ban đầu) vị trí thích hợp Sau đó, khố bị loại khỏi dãy khố chứa Q trình tiếp tục hai dãy khoá cạn, cần chuyển tồn dãy khố cịn lại miền xếp xong Ví dụ: Với hai dãy khoá: (1, 3, 10, 11) (2, 4, 9) Dãy Dãy Khoá nhỏ dãy Miền xếp 129 (1, 3, 10, 11) (2, 4, 9) (1) (3, 10, 11) (2, 4, 9) (1, 2) (3, 10, 11) (4, 9) (1, 2, 3) (10, 11) (4, 9) (1, 2, 3, 4) (10, 11) (9) (1, 2, 3, 4, 9) (10, 11) ∅Dãy ∅, đưa nốt dãy vào miền xếp (1, 2, 3, 4, 9, 10, 11) 2.5.2 Sắp xếp trộn đường trực tiếp Ta coi khố dãy khoá k1, k2, , kn mạch với độ dài 1, mạch dãy xếp rồi: 3654981027 Trộn hai mạch liên tiếp lại thành mạch có độ dài 2, ta lại dãy gồm mạch sắp: 3645890127 Cứ trộn hai mạch liên tiếp, ta mạch độ dài lớn hơn, số mạch dãy giảm dần xuống: 3456018927 0134568927 0123456789 Để tiến hành thuật toán xếp trộn hai đường trực tiếp, ta viết thủ tục - Thủ tục Merge(var x, y: TArray; a, b, c: Integer); thủ tục trộn mạch x[a], x[a+1], , x[b] với mạch x[b+1], x[b+2] , x[c] để mạch y[a], y[a+1], , y[c] - Thủ tục MergeByLength(var x, y: TArray; len: Integer); thủ tục trộn cặp mạch theo thứ tự: + Trộn mạch x[1] x[len] x[len+1] x[2len] thành mạch y[1] y[2len] 130 + Trộn mạch x[2len+1] x[3len] x[3len+1] x[4len] thành mạch y[2len+1] y[4len] Lưu ý đến cuối ta gặp hai trường hợp: Hoặc lại hai mạch mà mạch thứ hai có độ dài < len Hoặc cịn lại mạch Trường hợp thứ ta phải quản lý xác số để thực phép trộn, trường hợp thứ hai khơng qn thao tác đưa thẳng mạch lại sang dãy y Cuối thủ tục MergeSort, thủ tục cần dãy khoá phụ t1, t2, , tn Trước hết ta gọi MergeByLength(k, t, 1) để trộn hai phần tử liên tiếp k thành mạch t, sau lại gọi MergeByLength(t, k, 2) để trộn hai mạch liên tiếp t thành mạch k, lại gọi MergeByLength(k, t, 4) để trộn hai mạch liên tiếp k thành mạch t Như k t sử dụng với vai trò luân phiên: dãy chứa mạch dãy dùng để trộn cặp mạch liên tiếp để mạch lớn procedure MergeSort; var t: TArray; {Dãy khoá phụ} len: Integer; Flag: Boolean; {Flag = True: trộn mạch k vào t; Flag = False: trộn mạch t vào k} procedure Merge(var X, Y: TArray; a, b, c: Integer);{Trộn Xa Xb Xb+1 Xc} var i, j, p: Integer; begin {Chỉ số p chạy miền xếp, i chạy theo mạch thứ nhất, j chạy theo mạch thứ hai} p := a; i := a; j := b + 1; while (i ≤b) and (j ≤c) then {Chừng hai mạch chưa xét hết} begin if Xi ≤Xj then {So sánh hai phần tử nhỏ hai mạch mà chưa bị đưa vào miền xếp} 131 begin Yp := Xi; i := i + 1; {Đưa xi vào miền xếp cho i chạy} end else begin Yp := Xj; j := j + 1; {Đưa xj vào miền xếp cho j chạy} end; p := p + 1; end; if i ≤b then {Mạch hết trước} (Yp, Yp+1, , Yc) := (Xi, Xi+1, , Xb) {Đưa phần cuối mạch vào miến xếp} else {Mạch hết trước} (Yp, Yp+1, , Yc) := (Xj, Xj+1, , Xc); {Đưa phần cuối mạch vào miến xếp} end; procedure MergeByLength(var X, Y: TArray; len: Integer); begin a := 1; b := len; c := * len; while c ≤n {Trộn hai mạch xa xb xb+1 xc có độ dài len} begin Merge(X, Y, a, b, c); {Dịch số a, b, c sau 2.len vị trí} a := a + * len; b := b + * len; c := c + * len; end; if b < n then Merge(X, Y, a, b, n) {Cịn lại hai mạch mà mạch thứ hai có độ dài ngắn len} else if a ≤n then {Còn lại mạch} (Ya, Ya+1, , Yn) := (Xa, Xa+1, , Xn); {Đưa thẳng mạch sang miền y} end; 132 begin {Thuật toán xếp trộn} Flag := True; len := 1; while len < n begin if Flag then MergeByLength(k, t, len) else MergeByLength(t, k, len); len := len * 2; Flag := not Flag; {Đảo cờ để luân phiên vai trò k t} end; if not Flag then k := t; {Nếu kết cuối nằm t chép kết vào k} end; Về độ phức tạp thuật toán, ta thấy thủ tục Merge, phép toán tích cực thao tác đưa khố vào miền xếp Mỗi lần gọi thủ tục MergeByLength, tất phần tử dãy khố chuyển hồn tồn sang miền xếp, nên độ phức tạp thủ tục MergeByLength O(n) Thủ tục MergeSort có vịng lặp thực không log2n + lời gọi MergeByLength biến len tăng theo cấp số nhân cơng bội Từ suy độ phức tạp MergeSort O(nlog2n) bất chấp trạng thái liệu vào Cùng thuật toán xếp tổng quát với độ phức tạp trung bình nhau, khơng giống QuickSort hay HeapSort, MergeSort có tính ổn định Nhược điểm MergeSort phải dùng thêm vùng nhớ để chứa dãy khố phụ có kích thước dãy khố ban đầu Người ta cịn lợi dụng trạng thái liệu vào để khiến MergeSort chạy nhanh hơn: từ đầu, ta không coi phần tử dãy khoá mạch mà coi đoạn dãy khoá mạch Bởi dãy khố coi gồm mạch xếp nằm liên tiếp Khi người ta gọi phương pháp phương pháp trộn hai đường tự nhiên Tổng quát nữa, thay phép trộn hai mạch, người ta sử dụng phép trộn k mạch, ta thuật toán xếp trộn k đường 133 Các phương pháp tìm kiếm 3.1 Tìm kiếm (Sequential search) Tìm kiếm kỹ thuật tìm kiếm đơn giản Nội dung sau: Bắt đầu từ ghi đầu tiên, so sánh khố tìm kiếm với khố tương ứng ghi danh sách, tìm thấy ghi mong muốn duyệt hết danh sách mà chưa thấy {Tìm kiếm dãy khố k1, k2, , kn; hàm thử tìm xem dãy có khố = X khơng, thấy trả số khố ấy, khơng thấy trả Có sử dụng khố phụ kn+1 gán giá trị = X} function SequentialSearch(X: TKey): Integer; var i: Integer; begin i := 1; while (i X có nghĩa đoạn từ kmedian tới ksup chứa tồn khố > X, ta tiến hành tìm kiếm tiếp với đoạn từ kinf tới kmedian - - Nếu kmedian = X việc tìm kiếm thành cơng (kết thúc q trình tìm kiếm) 134 Quá trình tìm kiếm thất bại đến bước đó, đoạn tìm kiếm rỗng (inf > sup) {Tìm kiếm nhị phân dãy khố k1 ≤k2 ≤ ≤kn; hàm thử tìm xem dãy có khố = X khơng, thấy trả số khố ấy, khơng thấy trả 0} function BinarySearch(X: TKey): Integer; var inf, sup, median: Integer; begin inf := 1; sup := n; while inf ≤sup begin median := (inf + sup) div 2; if kmedian = X then begin BinarySearch := median; Exit; end; if kmedian < X then inf := median + else sup := median - 1; end; BinarySearch := 0; end; Người ta chứng minh độ phức tạp tính tốn thuật tốn tìm kiếm nhị phân trường hợp tốt O(1), trường hợp xấu O(log2n) trường hợp trung bình O(log2n) Tuy nhiên, ta khơng nên quên trước sử dụng tìm kiếm nhị phân, dãy khoá phải xếp rồi, tức thời gian chi phí cho việc xếp phải tính đến Nếu dãy khố ln ln biến động phép bổ sung hay loại bớt lúc chi phí cho xếp lại lên rõ làm bộc lộ nhược điểm phương pháp 135 TÀI LIỆU THAM KHẢO ROBERT SEDGEWICK, Algorithms, Addison-Wesley Publishing Company, năm 1990 PTS Đinh Mạnh Tường, Giáo trình Cấu trúc liệu giải thuật, NXB Đại học Quốc gia, năm 2000 Lê Minh Hoàng, Cấu trúc liệu giải thuật, năm 2003 136 ... thiệu cấu trúc liệu giải thuật Mối liên hệ cấu trúc liệu giải thuật .9 1.1 Xây dựng cấu trúc liệu 1.2 Xây dựng giải thuật 1.3 Mối quan hệ cấu trúc liệu giải thuật. .. người lập trình phần cài đặt thuật tốn ngơn ngữ cụ thể 1.3 Mối quan hệ cấu trúc liệu giải thuật - Mối quan hệ cấu trúc liệu Giải thuật minh họa đẳng thức: Cấu trúc liệu + Giải thuật = Chương trình. .. thiệu cấu trúc liệu giải thuật Mã chương: MH19_CH01 Giới thiệu: Bài giới thiệu mối liên hệ cấu trúc liệu giải thuật 1 Mục tiêu: - Trình bày kiến thức cở cấu trúc liệu, giải thuật, kiểu liệu,

Ngày đăng: 28/12/2021, 19:30

Hình ảnh liên quan

Bảng sau chỉ ra các giá trị của kiể u: Tên kiểuý nghĩa - Giáo trình Cấu trúc dữ liệu và giải thuật (Nghề Lập trình máy tính)

Bảng sau.

chỉ ra các giá trị của kiể u: Tên kiểuý nghĩa Xem tại trang 44 của tài liệu.

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

Tài liệu liên quan