Tài liệu giảng dạy Cấu trúc dữ liệu gồm có 6 chương với những nội dung chính như sau: Chương 1: tổng quan về cấu trúc dữ liệu và giải thuật, chương 2: đệ quy và giải thuật đệ quy, chương 3: tìm kiếm, chương 4: các phương pháp sắp xếp cơ bản, chương 5: danh sách, chương 6: cây nhị phân. Mời các bạn cùng tham khảo để biết thêm nội dung chi tiết.
Mục lục MỤC LỤC Chương 1: TỔNG QUAN VỀ CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT 01 I Các tiêu chuẩn danh gia cấu trúc liệu 01 Phản ánh thực tế 01 Phù hợp với thao tác 01 Tiết kiệm tài nguyên hệ thống 02 II Kiểu liệu 02 III Kiểu liệu 03 IV Các kiểu liệu có cấu trúc 04 Kiểu chuỗi ký tự 04 Kiểu mảng 05 Kiểu Union 06 Kiểu mẫu tin (cấu trúc) 07 Kiểu trỏ 12 Kiểu tập tin 26 Mối quan hệ cấu trúc liệu giải thuật 37 Bài tập 38 Chương 2: ĐỆ QUY VÀ GIẢI THUẬT ĐỆ QUY 39 I Khái niệm đệ quy 39 II Thuật toán đệ quy chương trình đệ quy 39 Giải thuật đệ quy 39 Các chương trình đệ quy 41 III Các toán đệ quy 46 Hàm tính giai thừa 46 Dãy số Fibonacci 47 Bài tập 48 Chương 3: TÌM KIẾM 49 I Tìm kiếm tuyến tính 49 Giải thuật 50 Cài đặt 51 Ðánh giá giải thuật 51 II Tìm kiếm nhị phân 51 Giải thuật 51 Cài đặt 52 Ðánh giá giải thuật 53 Bài tập 54 Mục lục Chương 4: CÁC PHƯƠNG PHÁP SẮP XẾP CƠ BẢN 55 I Định nghĩa toán xếp 55 II Phương pháp chọn (Selection Sort) 55 Giải thuật 55 Ví dụ 56 Cài đặt 57 Ðánh giá giải thuật 57 III Phương pháp chèn (Insertion Sort) 58 Giải thuật 58 Ví dụ 59 Cài đặt 59 Đánh giá giải thuật 60 III Phương pháp đổi chỗ (Interchange Sort) 61 Giải thuật 61 Ví dụ 61 Cài đặt 64 Ðánh giá giải thuật 64 IV Phương pháp bọt (Bubble Sort) 65 Giải thuật 65 Ví dụ 65 Cài đặt 67 Ðánh giá giải thuậ 68 V Phương pháp xếp nhanh Quick Sort 68 Giải thuật phân hoạch dãy al, al+1, , ar thành dãy 69 Giải thuật phân hoạch dãy xếp dãy al, al+1, , ar 69 Cài đặt 71 Ðánh giá giải thuật 72 Bài tập 72 Chương 5: DANH SÁCH 74 I Danh sách liên kết (Xâu liên kết ) 74 Định nghiã 74 Biểu diễn Xâu liên kết 74 II Danh sách liên kết đơn (Xâu đơn) 75 Khai báo xâu liên kết đơn 75 Các thao tác xâu liên kết đơn 76 Loại bỏ phần tủ xâu 81 Duyệt xâu 85 Mục lục Sắp thứ tự Xâu 85 Thuật Toán QuickSort 86 III Ngăn xếp – stack 87 Định nghiã 87 Cài đặt ngăn xếp xâu đơn 88 Cài đặt ngăn xếp mảng thao tác 90 Ứng dụng ngăn xếp xử lý biểu thức hậu tố 91 IV Hàng đợi – Queue 94 Khái niệm 94 Cài đặt hàng đợi xâu liên kết 95 Cài đặt hàng đợi mảng 96 Bài tập 99 Chương 6: CÂY NHỊ PHÂN 102 I Định nghĩa khái niệm 102 Định nghĩa 102 Các khái niệm khác 102 II Cây nhị phân 104 Định nghĩa 104 Vài tính chất nhị phân 104 Biểu diễn nhị phân 104 III Duyệt nhị phân 106 Định nghĩa 106 Các thuật toán duyệt nhị phân 106 Cài đặt thuật toán duyệt qua nhị phân LNR 107 Cài đặt nhị phân 109 III Cây tìm kiếm nhị phân (Binary Search Trees) 112 Định nghĩa 112 Cài đặt tìm kiếm nhị phân 113 Tìm kiếm phần tử BST 113 Chèn phần tử vào BST, xây dựng BST 115 Phương pháp xếp BST 118 Xóa phần tử khỏi BST, hủy nhị phân 118 Bài tập 122 Chương I: Tổng quan cấu trúc liệu giải thuật Chương I: TỔNG QUAN VỀ CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT Chương trình bày tổng quan cấu trúc liệu giải thuật, tiêu chuẩn danh gia cấu trúc liệu ,phản ánh thực tếp, phù hợp với thao tác đó, tiết kiệm tài nguyên hệ thống Kiểu liệu, kiểu liệu bản, kiểu liệu có cấu trúc, kiểu chuỗi ký tự, kiểu mảng, kiểu union, kiểu mẫu tin (cấu trúc), kiểu trỏ, kiểu tập tin, mối quan hệ cấu trúc liệu giải thuật I KHÁI NIỆM THUẬT GIẢI VÀ ĐÁNH GIÁ ĐỘ PHỨC TẠP CỦA GIẢI THUẬT Khái niệm thuật giải 1.1 Thuật giải Tập bước tính tốn để đạt kết mong muốn Khi có mơ hình thích hợp cho tốn ta cần cố gắng tìm cách giải tốn mơ hình Khởi đầu tìm giải thuật, chuỗi hữu hạn thị (instruction) mà thị có ý nghĩa rõ ràng thực lượng thời gian hữu hạn Knuth (1973) định nghĩa giải thuật chuỗi hữu hạn thao tác để giải toán Các tính chất quan trọng giải thuật là: - Hữu hạn (finiteness): giải thuật phải luôn kết thúc sau số hữu hạn bước - Xác định (definiteness): bước giải thuật phải xác định rõ ràng phải thực xác, quán - Hiệu (effectiveness): thao tác giải thuật phải thực lượng thời gian hữu hạn Mỗi thuật tốn có liệu vào (Input) liệu (Output); Nói tóm lại, giải thuật phải giải xong công việc ta cho liệu vào Có nhiều cách để thể giải thuật: dùng lời, dùng lưu đồ, Và lối dùng phổ biến dùng ngôn ngữ giả, kết hợp ngơn ngữ tự nhiên cấu trúc ngôn ngữ lập trình Ví dụ: Tính tổng số ngun lẻ từ 1n B1: S=0 B2: i=1 B3: Nếu i>n sang B7, ngược lại sang B4 B4: S=S+i B5: i=i+2 Chương I: Tổng quan cấu trúc liệu giải thuật B6: Quay lại B3 B7: Tổng cần tìm S 1.2 Đặc trưng thuật giải - Tính đắn: Thuật toán cần phải đảm bảo cho kết sau thực liệu đầu vào Đây nói đặc trưng quan trọng thuật toán: Thuật toán cần phải đảm bảo dừng sau số hữu hạn bước - Tính xác định: Các bước thuật toán phải phát biểu rõ ràng, cụ thể, tránh gây nhập nhằng nhầm lẫn người đọc hiểu, cài đặt thuật tốn - Tính hiệu quả: Thuật toán xem hiệu có khả giải hiệu toán đặt thời gian điều kiện cho phép thực tế đáp ứng yêu cầu người dùng - Tính phổ qt: Thuật tốn gọi có tính phố qt (phổ biến) giải lớp tốn tương tự 1.3 Biểu diễn thuật giải - Cách 1: Mô tả bước thực thuật giải - Cách 2: Sử dụng sơ đồ giải thuật Ví dụ: mơ tả thuật tốn giải phương trình bậc ax+b=0 (a,b số thực) Cách 1: Mô tả bước thực thuật toán Cách 2: Sử dụng sơ đồ giải thuật Sử dụng ký hiệu hình khối để tạo thành mô tả mang tính hình thức Chương I: Tổng quan cấu trúc liệu giải thuật Hình 3.1 ký hiệu hình khối Hình 3.2 Sơ đồ giải thuật Đánh giá độ phức tạp giải thuật 2.1 Các tiêu chuẩn đánh giá cấu trúc liệu Để đánh giá cấu trúc liệu thường dựa vào số tiêu chí sau: - Cấu trúc liệu phải tiết kiệm tài nguyên (bộ nhớ trong), - Cấu trúc liệu phải phản ảnh thực tế toán, Chương I: Tổng quan cấu trúc liệu giải thuật - Cấu trúc liệu phải dễ dàng việc thao tác liệu 2.2 Đánh giá độ phức tạp thuật giải Việc đánh giá độ phức tạp thuật toán không dễ dàng chút Ở dây, muốn ước lượng thời gian thực thuận toán T(n) để có so sánh tương đối thuật toán với Trong thực tế, thời gian thực thuật tốn cịn phụ thuộc nhiều vào điều kiện khác cấu tạo máy tính, liệu đưa vào, …, xem xét mức độ lượng liệu đưa vào ban đầu cho thuật toán thực Để ước lượng thời gian thực thuật toán xem xét thời gian thực thuật toán hai trường hợp: - Trong trường hợp tốt nhất: Tmin - Trong trường hợp xấu nhất: Tmax Từ ước lượng thời gian thực trung bình thuật tốn: Ta Để đánh giá hiệu thuật tốn, tính số lượng phép tính phải thực thuật tốn này: - Phép so sánh - Phép gán - Thông thường số phép tính thực phụ thuộc vào cỡ toán,tức độ lớn đầu vào - Vì độ phức tạp thuật tốn hàm phụ thuộc đầu vào - Tuy nhiên, không cần biết xác hàm mà cần biết ước lượng đủ tốt chúng - Để ước lượng độ phức tạp thuật toán ta thường dùng khái niệm Big-O Bước Gán Tổng = Gán i = Bước - Tăng i thêm đơn vị - Gán Tổng = Tổng + i Bước So sánh i với n - Nếu i < n, quay lại bước - Ngược lại, dừng thuật toán Số phép gán thuật toán bao nhiêu? • Số phép so sánh bao nhiêu? - Gán: f(2n + 2), So sánh: f(n) Độ phức tạp: O(n) Ví dụ: Thuật tốn tính tổng số từ đến n s=0; Chương I: Tổng quan cấu trúc liệu giải thuật for(i= 1; iData); LNRĐệQuy (Root->RChild) ; } return; } Thuật toán duyệt nhị phân theo thứ tự (LNR) viết lại dạng lặp, cách sử dụng stack để lưu lại địa nút gốc trước đến trái Trước hết, ta khai báo cấu trúc nút stack trên: typedef struct NS { TreePointer Data; struct NS * Next; } NodeStack; typedef NodeStack * StackType; 3.2 Cài đặt thuật toán LNR dưới dạng lặp : /* Input: - Root : trỏ đến nút gốc nhị phân Output: - Duyệt qua xử lý nút nhị phân theo thứ tự LNR */ void LNRLap(TreePointer Root) { TreePointer p; int TiepTuc = 1; StackType S; p = Root; S = CreateEmptyStack(); // Khởi tạo ngăn xếp rỗng { while (p != NULL) { Push(S,p); // Đẩy p vào stack S p = p->LChild; } if (!EmptyStack(S)) // Nếu stack S khác rỗng { Pop(S,p); // Lấy phần tử p đỉnh stack S XuLy(p); p = p->RChild; Chương VI : Cây nhị phân 106 } else TiepTuc = 0; } while (TiepTuc); return ; } Với hai trường hợp duyệt lại (NLR LRN), ta cài đặt chúng dạng đệ quy lặp (bài tập) Một cách tổng qt, ta viết lại ba thuật tốn duyệt dạng lặp (bài tập) Cài đặt nhị phân Tương tự tổng quát, ta cài đặt nhị phân trỏ cách thiết kế nút có hai trỏ, trỏ trỏ nút trái, trỏ trỏ nút phải, trường Data chứa nhãn nút typedef … TData; typedef struct Tnode { TData Data; TNode* left,right; }; typedef TNode* TTree; Với cách khai báo ta thiết kế phép toán nhị phân sau : Tạo rỗng Cây rỗng không chứa nút Như tạo rỗng ta cần cho trỏ tới giá trị NULL void MakeNullTree(TTree *T) { (*T)=NULL; } Kiểm tra rỗng int EmptyTree(TTree T) { return T==NULL; } Xác định trái nút TTree LeftChild(TTree n) { Chương VI : Cây nhị phân 107 if (n!=NULL) return n->left; else return NULL; } Xác định phải nút TTree RightChild(TTree n) { if (n!=NULL) return n->right; else return NULL; } Kiểm tra nút lá: Nếu nút nút khơng có nên trái phải NULL int IsLeaf(TTree n) { if(n!=NULL) return(LeftChild(n)==NULL)&&(RightChild(n)==NULL); else return NULL; } Xác định số nút int nb_nodes(TTree T) { if(EmptyTree(T)) return 0; else return 1+nb_nodes(LeftChild(T))+ nb_nodes(RightChild(T)); } Các thủ tục duyệt cây: tiền tự, trung tự, hậu tự Thủ tục duyệt tiền tự void PreOrder(TTree T) { coutData) Chương VI : Cây nhị phân 110 return TìmBSTĐệQuy (Root->RChild,Item); else return TìmBSTĐệQuy (Root->LChild,Item); } else return(NULL); } * Thủ tục viết dạng đệ qui thích hợp với lối tư tự nhiên giải thuật định nghĩa đệ qui nhị phân Song trường hợp thủ tục viết dạng lặp lại tỏ hiệu Thuật tốn tìm kiếm dạng lặp: /* Input: - Root: trỏ đến nút gốc BST - Item: giá trị khóa phần tử cần tìm Output: - Trả trỏ LocPtr đến nút BST chứa Item trỏ Parent đến nút cha nút chứa Item tìm thấy Item BST - Trả trị NULL ngược lại */ TreePointer TìmBSTLặp(TreePointer Root, ElementType Item, TreePointer &Parent) { TreePointer LocPtr = Root; Parent = NULL; while (LocPtr != NULL) if (Item==LocPtr->Data) return (LocPtr); else {Parent = LocPtr; if (Item > LocPtr->Data) LocPtr = LocPtr->RChild; else LocPtr = LocPtr->LChild; } return(NULL); } Với cấu trúc cây, việc tìm kiếm theo khóa nhanh nhiều so với cấu trúc danh sách liên kết Chi phí tìm kiếm (độ phức tạp) trung bình nhị phân có n nút khoảng log2 n 5.4 Chèn phần tử vào BST, xây dựng BST Việc chèn thêm phần tử Item vào BST cần phải thỏa ràng buộc định nghĩa BST Trước chèn Item, ta cần tìm khóa Item có BST hay khơng, có khỏi chèn (do BST ta chứa phần tử có khóa khác nhau); ngược lại, chấm dứt thao tác tìm kiếm ta biết vị trí chèn (ở nút lá) * Ví dụ: Giả sử ta có BST (với nút có khóa khác nhau): Chương VI : Cây nhị phân 111 Ta cần thêm phần tử ‘R’: Yêu cầu “vào – ra” thao tác chèn: /* Input: - Root: trỏ đến nút gốc BST - Item: giá trị liệu nút cần chèn Output: - Trả trị trỏ Root đến nút gốc BST chèn - Trả trị -1 Item có - Trả trị gặp lỗi cấp phát nhớ cho nút */ Thao tác chèn nút Item vào BST (dạng lặp): int ChènBSTLặp(TreePointer &Root, ElementType Item) { TreePointer LocPtr, Parent; if (TìmBSTLặp(Root, Item, Parent)) { cout RChild = NULL; if (Parent == NULL) Root = LocPtr; // rỗng else if (Item < Parent->Data) Parent->LChild = LocPtr; Chương VI : Cây nhị phân 112 else Parent->RChild = LocPtr; return 1; } } Thủ tục chèn nút Item vào BST (dạng đệ qui): int ChènBSTĐệQui(TreePointer &Root, ElementType Item) { TreePointer LocPtr; if (Root == (TreePointer) NULL) // chèn nút vào rỗng { if ((Root = CấpPhát ()) == NULL) return 0; Root ->Data = Item; Root ->LChild = NULL; Root ->RChild = NULL; } else if (Item < Root->Data) ChènBSTĐệQui (Root->LChild,Item); else if (Item > Root->Data) ChènBSTĐệQui(Root->RChild,Item); else { cout LChild; if (SubTree == NULL ) SubTree = x->RChild; //SubTree khác rỗng (nếu có) x if (Parent == NULL) Root = SubTree; // xoá nút gốc else if (Parent->LChild == x) Parent->LChild = SubTree ; else Parent->RChild = SubTree; delete x; Xoá nút có hai nút con: Giả sử ta cần xố nút E có nút BST sau : Đưa trường hợp đầu cách sau: Thay trị nút mà x trỏ đến trị nút theo thứ tự (nút nút cực trái xa theo nhánh phải x, nút nhỏ (tất nhiên theo trường khóa) số nút lớn x->Data) Sau xố nút (nút nút có tối đa nút ) Chương VI : Cây nhị phân 115 * Sau ta xây dựng thủ tục XóaBST để xóa nút Item BST Trong thủ tục có dùng đến thủ tục TìmBSTLặp Thủ tục XốBST tìm nút có khóa Item xố khỏi BST Gọi: - x: trỏ đến nút chứa Item - xSucc: phần tử x theo thứ tự (nếu x có con) - Parent: trỏ đến cha x hay xSucc - SubTree: trỏ đến x /* Input: - Root: trỏ đến nút gốc BST - Item: giá trị liệu nút cần xóa Output: - Trả trị trỏ Root đến nút gốc BST tìm thấy nút chứa Item xoá - Trả trị ngược lại */ int XóaBST (TreePointer &Root, ElementType Item) { TreePointer x,Parent, xSucc,SubTree; if ((x = TìmBSTLặp(Root,Item,Parent)) ==NULL) return 0;//khơng thấy Item else { if ((x->LChild != NULL) && (x->RChild != NULL)) // nút có Chương VI : Cây nhị phân 116 { xSucc = x->RChild; Parent = x; while (xSucc->LChild != NULL) { Parent = xSucc; xSucc = xSucc->LChild; } x->Data = xSucc->Data; x = xSucc; } //đã đưa nút có nút có tối đa SubTree = x->LChild; if (SubTree == NULL) SubTree = x->RChild; if (Parent == NULL) Root = SubTree; // xoá nút gốc else if (Parent->LChild == x) Parent->LChild = SubTree; else Parent->RChild = SubTree; delete x; return 1; } } Ta hủy tồn BST cách sử dụng ý tưởng duyệt theo thứ tự cuối LRN: hủy trái, hủy phải hủy nút gốc void HủyCâyNhịPhân (PointerType &Root) { if (Root) { HủyCâyNhịPhân (Root->LChild); HủyCâyNhịPhân (Root->RChild); delete Root; } return ; } Chương VI : Cây nhị phân 117 BÀI TẬP Hãy vẽ tất nhị phân có nút, nút Viết chương trình nhập vào nhịp phân Hãy cài đặt tác vụ sau: a Xác định số nút cậy b Xác định số c Xác định số nút có d Xác định số nút có hai e Xác định chiều sâu f Xác định số nút mức Tài liệu tham khỏa 118 TÀI LIỆU THAM KHẢO Trần hạnh Nhi, Dương Anh Đức, “Giáo trình cấu trúc liệu giải thật”NXB Đại học Quốc gia Tp.HCM, 2010 Đỗ Xn Lơi, “Giáo trình Cấu trúc liệu giải thuật”- NXB Khoa học Kỹ thuật, 1996 Nguyễn Hồng Chương, “Cấu trúc liệu - Ứng dung cài đặt C”, NXB Tp.HCM, 1999 N.Wirtyh, “Algorithms + data Structure = Programs”, Prentise Hall, 1976 R.F.Gilberg & B.A Forouzan, “Data Strutures: A Pseudocode Approach with C, Second Edition” Thomson Leaning, 2005 ... - Cấu trúc liệu phải tiết kiệm tài nguyên (bộ nhớ trong), - Cấu trúc liệu phải phản ảnh thực tế toán, Chương I: Tổng quan cấu trúc liệu giải thuật - Cấu trúc liệu phải dễ dàng việc thao tác liệu. .. quan cấu trúc liệu giải thuật Chương I: TỔNG QUAN VỀ CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT Chương trình bày tổng quan cấu trúc liệu giải thuật, tiêu chuẩn danh gia cấu trúc liệu ,phản ánh thực tếp,... chọn cấu trúc liệu thích hợp có ngơn ngữ lập trình cấu trúc liệu phức hợp xây dựng lên từ kiểu liệu ngơn ngữ lập trình IV CÁC CẤU TRÚC DỮ LIỆU CƠ BẢN Tuy nhiên nhiều trường hợp, với kiểu liệu