BIA CT DL va GT cdr GIÁO TRÌNH CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT LÊ VĂN VINH 2 BỘ GIÁO DỤC VÀ ĐÀO TẠO TRƢỜNG ĐẠI HỌC SƢ PHẠM KỸ THUẬT THÀNH PHỐ HỒ CHÍ MINH ******************* ThS LÊ VĂN VINH NHÀ XUẤT BẢ[.]
LÊ VĂN VINH GIÁO TRÌNH CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT BỘ GIÁO DỤC VÀ ĐÀO TẠO TRƢỜNG ĐẠI HỌC SƢ PHẠM KỸ THUẬT THÀNH PHỐ HỒ CHÍ MINH ******************* ThS LÊ VĂN VINH NHÀ XUẤT BẢN ĐẠI HỌC QUỐC GIA THÀNH PHỐ HỒ CHÍ MINH LỜI NĨI ĐẦU Cấu trúc liệu giải thuật khối kiến thức sở chương trình đào tạo cử nhân ngành Công nghệ Thông tin Khoa Công nghệ Thông tin, Trường Đại học Sư phạm Kỹ thuật Thành phố Hồ Chí Minh Khối kiến thức giúp cho người học hiểu biết kiểu liệu trừu tượng thường sử dụng xây dựng chương trình máy tính, cách thực áp dụng kiểu liệu thực tế Nội dung giáo trình bao gồm chương bao quát hầu hết vấn đề cốt lõi môn học Nội dung chương trình bày theo trình tự: trình bày khái niệm, kiến thức trước, nêu ví dụ minh họa để người đọc dễ dàng tiếp cận lý thuyết sau cài đặt giải thuật ngơn ngữ lập trình cụ thể Cuối chương có tập để người đọc tự kiểm tra củng cố lại kiến thức Rất mong nhận ý kiến đóng góp đồng nghiệp bạn sinh viên để giảng ngày hoàn thiện Mọi ý kiến đóng góp xin vui lịng gửi theo địa email: levinhcntt@gmail.com MỤC LỤC LỜI NÓI ĐẦU MỤC LỤC Chƣơng TỔNG QUAN 1.1 GIẢI QUYẾT BÀI TOÁN TRÊN MÁY TÍNH 1.1.1 Xác định yêu cầu toán 1.1.2 Xây dựng cấu trúc liệu 1.1.3 Thiết kế giải thuật 10 1.1.4 Cài đặt chƣơng trình 10 1.1.5 Kiểm lỗi sửa lỗi chƣơng trình 10 1.2 KIỂU DỮ LIỆU TRỪU TƢỢNG 11 1.3 ĐÁNH GIÁ ĐỘ PHỨC TẠP CỦA GIẢI THUẬT 11 1.4 BÀI TẬP CHƢƠNG 12 Chƣơng 13 ĐỆ QUY 13 2.1 KHÁI NIỆM ĐỆ QUY 13 2.2 GIẢI THUẬT ĐỆ QUY 14 2.2.1 Định nghĩa 14 2.2.2 Thiết kế giải thuật đệ quy 16 2.3 PHÂN LOẠI ĐỆ QUY 16 2.3.1 Đệ quy trực tiếp 16 2.3.2 Đệ quy gián tiếp 18 2.4 ĐỆ QUY ĐI (TAIL-RECURSION) 19 2.5 BÀI TỐN THÁP HÀ NỘI (TOWER OF HANOI) 22 2.6 BÀI TẬP CHƢƠNG 24 Chƣơng 27 TÌM KIẾM VÀ SẮP XẾP 27 3.1 GIẢI THUẬT TÌM KIẾM 27 3.1.1 Tìm kiếm tuyến tính 27 a Ý tƣởng giải thuật 27 b Ví dụ minh họa 28 c Cài đặt 29 3.1.2 Tìm kiếm nhị phân 29 a Ý tƣởng giải thuật 29 b Ví dụ minh họa 30 c Cài đặt 31 3.2 GIẢI THUẬT SẮP XẾP 32 3.2.1 Phƣơng pháp đổi chỗ trực tiếp (Interchange Sort) 32 a Ý tƣởng giải thuật 32 b Ví dụ minh họa 33 c Cài đặt 34 3.2.2 Phƣơng pháp chọn trực tiếp (Selection Sort) 35 a Ý tƣởng giải thuật 35 b Ví dụ minh họa 35 c Cài đặt 36 3.2.3 Phƣơng pháp chèn trực tiếp (Insertion Sort) 37 a Ý tƣởng giải thuật 37 b Ví dụ minh họa 38 c Cài đặt 39 3.2.4 Phƣơng pháp bọt (Bubble Sort) 41 a Ý tƣởng giải thuật 41 b Ví dụ minh họa 41 c Cài đặt 42 3.2.5 Phƣơng pháp dựa phân hoạch (Quick Sort) 43 a Ý tƣởng giải thuật 43 b Ví dụ minh họa 44 c Cài đặt 45 3.3 BÀI TẬP CHƢƠNG 47 Chƣơng 49 DANH SÁCH 49 4.1 ĐỊNH NGHĨA 49 4.2 DANH SÁCH ĐẶC 50 4.2.1 Khởi tạo danh sách 50 4.2.2 Kiểm tra danh sách rỗng 51 4.2.3 Kiểm tra danh sách đầy 51 4.2.4 Thêm phần tử vào danh sách 51 4.2.5 Hủy phần tử khỏi danh sách 54 4.3 DANH SÁCH LIÊN KẾT 57 4.3.1 4.4 Danh sách liên kết đơn 57 BÀI TẬP CHƢƠNG 68 Chƣơng 71 NGĂN XẾP VÀ HÀNG ĐỢI 71 5.1 NGĂN XẾP 71 5.1.1 Định nghĩa ngăn xếp 71 5.1.2 Một số phép toán ngăn xếp 72 a Thêm phần tử vào ngăn xếp (Push()) 72 b Lấy thông tin phần tử đầu ngăn xếp (Top()) 72 c Trích hủy phần tử khỏi ngăn xếp (Pop()) 73 5.1.3 a Cài đặt ngăn xếp mảng 73 b Cài đặt ngăn xếp kiểu trỏ 76 5.1.4 Cài đặt ngăn xếp 73 Một số ứng dụng ngăn xếp 78 5.2 HÀNG ĐỢI 83 5.3 ĐỊNH NGHĨA HÀNG ĐỢI 83 5.3.1 Một số phép toán hàng đợi 84 5.3.2 Cài đặt hàng đợi 85 5.3.3 Cài đặt danh sách liên kết đơn 88 5.4 BÀI TẬP CHƢƠNG 90 Chƣơng 91 CẤU TRÚC CÂY 91 6.1 CẤU TRÚC CÂY 91 6.1.1 Các thuật ngữ 91 a Định nghĩa 91 b Một số khái niệm 91 6.1.2 6.2 CÂY NHỊ PHÂN 93 6.2.1 a Định nghĩa 93 Duyệt nhị phân 93 6.2.2 6.3 Các loại cấu trúc liệu 92 Cài đặt nhị phân 94 CÂY NHỊ PHÂN TÌM KIẾM 98 6.3.1 Định nghĩa 98 6.3.2 Các thao tác nhị phân tìm kiếm (NPTK) 99 a Thêm nút vào NPTK 99 b Tìm kiếm NPTK 100 c Hủy nút 100 6.4 BÀI TẬP CHƢƠNG 102 TÀI LIỆU THAM KHẢO 105 PHỤ LỤC 107 Chương TỔNG QUAN 1.1 GIẢI QUYẾT BÀI TỐN TRÊN MÁY TÍNH Máy tính công cụ giúp ngƣời giải vấn đề, toán thực tế Khi viết chƣơng trình u cầu máy tính thực cơng việc đó, số bƣớc cần phải tiến hành nhƣ sau: 1.1.1 Xác định yêu cầu toán Ở bƣớc này, cần xác định xem phải giải vấn đề Những giả thiết cho yêu cầu cần phải đạt đƣợc Việc xác định yêu cầu toán quan trọng ảnh hƣởng đến cách thức giải tính hiệu lời giải Thơng tin lấy từ tốn thực tế thƣờng mơ hồ hình thức, cần phát biểu lại cách rõ ràng xác để xây dựng thuật tốn phù hợp Ví dụ tốn tơ màu đồ nhƣ sau: “Hãy sử dụng số màu tối thiểu để tô màu cho đồ giới cho nƣớc đƣợc tô màu hai nƣớc láng giềng (cùng biên giới) phải đƣợc tơ hai màu khác nhau” Xem nƣớc đồ đỉnh đồ thị Khi hai nƣớc láng giềng hai đỉnh đại diện đƣợc nối với cạnh Khi đó, tốn thực tế đƣợc chuyển thành toán đồ thị nhƣ sau: “Cho đồ thị có n đỉnh Hãy sử dụng số màu tối thiểu để tô cho đỉnh đồ thị cho hai đỉnh kề phải có màu khác nhau” Từ đây, áp dụng thuật toán lý thuyết đồ thị để giải toán cách dễ dàng 1.1.2 Xây dựng cấu trúc liệu Khi giải toán, cần định nghĩa tập hợp liệu để biểu diễn cách đầy đủ thơng tin có thực tế Dữ liệu thực tế đa dạng, phong phú thƣờng chứa đựng mối quan hệ với Việc lựa chọn cách biểu diễn liệu hay cấu trúc liệu phải tùy thuộc vào yêu cầu vấn đề cần giải thao tác tiến hành liệu đầu vào Một số giải thuật phù hợp với cách tổ chức liệu định, với cách tổ chức liệu khác hiệu khơng thể thực đƣợc Vì vậy, lựa chọn cấu trúc liệu, mốt số tiêu chuẩn sau cần đƣợc đảm bảo: Phản ánh đầy đủ thông tin thực tế Tiêu chuẩn định tính đắn tồn chƣơng trình Phù hợp với thao tác liệu đƣợc lựa chọn để giải toán Cấu trúc liệu phải cài đặt đƣợc máy tính với ngơn ngữ lập trình có 1.1.3 Thiết kế giải thuật Giải thuật hệ thống chặt chẽ rõ ràng quy tắc nhằm xác định dãy thao tác cấu trúc liệu cho với liệu đầu vào, sau số hữu hạn bƣớc thực hiện, chƣơng trình đạt đƣợc mục tiêu định Tùy theo yêu cầu thực tế mà ngƣời viết chƣơng trình cần áp dụng giải thuật phù hợp để giải Giải thuật sử dụng phải tƣơng ứng với cấu trúc liệu tốn Hay nói cách khác, giải thuật cấu trúc liệu có mối quan hệ chặt chẽ với Donald Knuth trình bày số tính chất quan trọng giải thuật là: Tính hữu hạn (finiteness): Giải thuật phải ln kết thúc sau số hữu hạn bƣớc Tính xác định (definiteness): Mỗi bƣớc giải thuật phải đƣợc xác định rõ ràng quán Tính hiệu (effectiveness): Giải thuật phải đƣợc thực khoảng thời gian chấp nhận đƣợc 1.1.4 Cài đặt chƣơng trình Khi xác định đƣợc thuật tốn cấu trúc liệu sử dụng, tiến hành lập trình để thực chúng Thơng thƣờng, lập trình, khơng nên cụ thể hóa tồn chƣơng trình mà nên tiến hành theo phƣơng pháp tinh chế bƣớc (stepwise refinement) (Theo Niklaus Wirth): Ban đầu, chƣơng trình nên đƣợc thể ngơn ngữ tự nhiên, hay mơ hình hóa Đối với cơng việc đơn giản cài đặt tiến hành viết mã nguồn cho Đối với cơng việc phức tạp chia thành công việc nhỏ để tiếp tục thực với cơng việc nhỏ 1.1.5 Kiểm lỗi sửa lỗi chƣơng trình Tìm lỗi, sửa lỗi cơng việc cần thực q trình cài đặt chƣơng trình Thơng thƣờng, có ba loại lỗi phát sinh lập trình là: 10 Trƣờng hợp x có nút Trƣờng hợp này, hủy phần tử x đƣợc mà ta phải thay nút lớn trái nút nhỏ phải Khi đó, nút đƣợc giải phóng nhớ hai nút Trong thuật toán dƣới đây, thay x nút nhỏ phải (là phần tử cực trái phải) Sau hàm cài đặt hủy nút có khóa x int DeleteNode(TNode*root, ElementType x) { if(root==NULL) return 0;//Khơng tồn nút có khóa x if(rootkey>x) return DeleteNode(rootpLeft, x); if(rootkeynext=myList.Head; myList.Head=p; } } //Thêm phần tử vào cuối void AddLast(LINKEDLIST& myList, NODE*p) { if(IsEmptyList(myList))//Danh sách rỗng myList.Head=myList.Tail=p; else//Danh sách không rỗng { myList.Tail->next=p; myList.Tail=p; } } //Thêm phần tử vào sau phần tử q void AddNode(LINKEDLIST& myList, NODE*q, NODE*p) { p->next=q->next; 108 q->next=p; if(myList.Tail==q) myList.Tail=p; } //Hủy phần tử đầu void RemoveFirst(LINKEDLIST& myList) { if(IsEmptyList(myList))//Danh sách rỗng coutnext=NULL; myList.Tail=p; } delete q;//Giải phóng vùng nhớ } } //Hủy phần tử sau phần tử q void RemoveNode(LINKEDLIST& myList, NODE*q) { NODE*p=q->next; if(p==NULL) coutnext; if(p==myList.Tail)//Nếu p phần tử cuối myList.Tail=q; delete p; } } //Tìm phần tử có giá trị x danh sách int SearchNode(LINKEDLIST myList, int x) { NODE*p=myList.Head; while(p!=NULL) { if(p->info==x) return 1;//Tìm thấy p=p->next; } return 0;//Khơng tìm thấy } //Sắp xếp danh sách thuật toán Quick sort void QuickSort(LINKEDLIST& myList) 110 { LINKEDLIST myList1; LINKEDLIST myList2; NODE *pivot, *p; InitList(myList1); InitList(myList2); /*Trƣờng hợp danh sách rỗng có phần tử*/ if (myList.Head==myList.Tail) return; /*Phân hoạch danh sách thành danh sách con*/ pivot = myList.Head;//Phần tử cầm canh p=myList.Head->next; while (p!=NULL) { NODE*q = p; p=p->next; q->next=NULL; if (q->info < pivot->info) AddLast(myList1, q);//Thêm vào cuối danh sách else AddLast(myList2, q);//Thêm vào cuối danh sách }; //Gọi đệ quy xếp cho danh sách QuickSort(myList1); QuickSort(myList2); //Ghép nối danh sách + pivot if (!IsEmptyList(myList1)) { myList.Head=myList1.Head; myList1.Tail->next=pivot; } else 111 myList.Head=pivot; //Ghép nối pivot + danh sách pivot->next=myList2.Head; if (!IsEmptyList(myList2)) myList.Tail=myList2.Tail; else myList.Tail=pivot; } //Liệt kê nội dung phần tử void PrintList(LINKEDLIST myList) { for(NODE*p=myList.Head;p!=NULL;p=p->next) cout