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

Cấu trúc dữ liệu và giải thuật + Bài tập

44 306 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

Định dạng
Số trang 44
Dung lượng 459,06 KB

Nội dung

Cấu trúc dữ liệu và giải thuật là một trong những môn học cơ bản của sinh viên ngành Công nghệ thông tin. Các cấu trúc dữ liệu và giải thuật được xem như là hai yếu tố quan trọng nhất trong lập trình, đúng như câu nói nổi tiếng của Niklaus Wirth: Chương trình = Cấu trúc dữ liệu+ Giải thuật (Programs = Data Structures + Algorithms). Nắm vững các cấu trúc dữ liệu và giải thuật là cơ sở để sinh viên tiếp cận với việc thiết kế và xây dựng phần mềm cũng như sử dụng các công cụ lập trình hiện đại. Cấu trúc dữ liệu có thể được xem như là một phương pháp lưu trữ dữ liệu trong máy tính nhằm sử dụng một cách có hiệu quả các dữ liệu này. Và để sử dụng các dữ liệu một cách có hiệu quả thì cần phải có các thuật toán áp dụng trên các dữ liệu đó. Do vậy cấu trúc dữ liệu và giải thuật là hai yếu tố không thể tách rời và có những liên quan chặt chẽ với nhau. Việc lựa chọn một cấu trúc dữ liệu có thể sẽ ảnh hưởng lớn đến việc lựa chọn áp dụng giải thuật nào.

PHẦN TỔNG QUAN  Giới thiệu: Cấu trúc liệu giải thuật môn học sinh viên ngành Công nghệ thông tin Các cấu trúc liệu giải thuật xem hai yếu tố quan trọng lập trình, câu nói tiếng Niklaus Wirth: Chương trình = Cấu trúc liệu+ Giải thuật (Programs = Data Structures + Algorithms) Nắm vững cấu trúc liệu giải thuật sở để sinh viên tiếp cận với việc thiết kế xây dựng phần mềm sử dụng cơng cụ lập trình đại Cấu trúc liệu xem phương pháp lưu trữ liệu máy tính nhằm sử dụng cách có hiệu liệu để sử dụng liệu cách có hiệu cần phải có thuật tốn áp dụng liệu Do cấu trúc liệu giải thuật hai yếu tố khơng thể tách rời có liên quan chặt chẽ với Việc lựa chọn cấu trúc liệu ảnh hưởng lớn đến việc lựa chọn áp dụng giải thuật Tài liệu cấu trúc liệu giải thuật bao gồm chương trình bày cấu trúc liệu giải thuật tin học Chương 1: trình bày tổng quan cấu trúc liệu giải thuật như: bước lập trình để giải tốn, trình bày khái niệm kiểu liệu trừu tượng Thời gian thực chương trình, cách đánh giá độ phức tạp giải thuật Chương 2: trình bày thuật tốn xếp tìm kiếm, cách xác định độ phức tạp thuật toán, phương pháp cài đặt cụ thể thuật tốn Chương 3: trình bày khái niệm kiểu liệu trừu tượng như: danh sách, ngăn xếp, hàng đợi,… cách xây dụng hàm kiểu liệu Cách ứng dụng kiểu liệu trừu tượng tốn thực tế Chương 4: trình bày cấu trúc liệu dạng Các khái niệm cây, cách cài đặt hàm phép toán II Thành phần tham gia biên soạn giáo trình: Ths Trương Thanh Tú III Giới thiệu môn học: + Tên môn học: Cấu trúc liệu giải thuật + Tổng số tiết: 75, số tiết lý thuyết: 15, số tiết thực hành: 60 IV Đối tượng sử dụng: Giáo trình sử dụng cho sinh viên hệ Cao đẳng Khoa CNTT V Tài liệu tham khảo: I Phụ lục 03 QT – KKT– 03/ 03 Trang 1/44 PHẦN NỘI DUNG CHƯƠNG 3: CÁC KIỂU DỮ LIỆU TRỪU TƯỢNG CƠ BẢN (BASIC ABSTRACT DATA TYPES) Tóm tắt nội dung: Chương 3: trình bày khái niệm kiểu liệu trừu tượng như: danh sách, ngăn xếp, hàng đợi,… cách xây dụng hàm kiểu liệu Cách ứng dụng kiểu liệu trừu tượng toán thực tế Nội dung học tập, nghiên cứu: 3.1 Kiểu liệu trừu tượng danh sách 3.1.1 Khái niệm danh sách Mơ hình tốn học danh sách tập hợp hữu hạn phần tử có kiểu, mà tổng quát ta gọi kiểu phần tử (Elementtype) Ta biểu diễn danh sách chuỗi phần tử nó: a1, a2, , anvới n ≥ Nếu n=0 ta nói danh sách rỗng (empty list) Nếu n > ta gọi a phần tử an phần tử cuối danh sách Số phần tử danh sách ta gọi độ dài danh sách Một tính chất quan trọng danh sách phần tử danh sách có thứ tự tuyến tính theo vị trí (position) xuất phần tử Ta nói a i đứng trước ai+1, với i từ đến n-1; Tương tự ta nói ailà phần tử đứng sau ai-1, với i từ đến n Ta nói phần tử vị trí thứ i, hay phần tử thứ i danh sách Ví dụ: Tập hợp họ tên sinh viên lớp TINHOC 28 liệt kê giấy sau: Nguyễn Trung Cang Nguyễn Ngọc Chương Lê Thị Lệ Sương Trịnh Vũ Thành Nguyễn Phú Vĩnh danh sách Danh sách gồm có phần tử, phần tử có vị trí danh sách theo thứ tự xuất 3.1.2 Các phép toán danh sách Để thiết lập kiểu liệu trừu tượng danh sách (hay ngắn gọn danh sách) ta phải định nghĩa phép toán danh sách thấy toàn giáo trình, khơng có tập hợp phép tốn thích hợp cho ứng dụng (application) Vì ta định nghĩa số phép toán danh sách Để thuận tiện cho việc định nghĩa ta giả sử danh sách gồm phần tử có kiểu kiểu phần tử (elementType); vị trí phần tử danh sách có kiểu kiểu vị trí vị trí sau phần tử cuối danh sách L ENDLIST(L) Cần nhấn mạnh khái niệm vị trí (position) ta định nghĩa, khơng phải giá trị phần tử danh sách Vị trí đồng với vị trí lưu trữ phần tử khơng Các phép tốn định nghĩa danh sách là: INSERT_LIST(x,p,L): xen phần tử x ( kiểu ElementType ) vị trí p (kiểu position) danh sách L Tức danh sách a 1, a2, , ap-1, ap , , an sau xen ta có kết a1, a2, , ap-1, x, ap, , an Nếu vị trí p khơng tồn danh sách phép tốn khơng xác định Phụ lục 03 QT – KKT– 03/ 03 Trang 2/44 LOCATE(x,L) thực việc định vị phần tử có nội dung x danh sách L Locate trả kết vị trí (kiểu position) phần tử x danh sách Nếu x khơng có danh sách vị trí sau phần tử cuối danh sách trả về, tức ENDLIST(L) RETRIEVE(p,L) lấy giá trị phần tử vị trí p (kiểu position) danh sách L; vị trí p khơng có danh sách kết khơng xác định (có thể thơng báo lỗi) DELETE_LIST(p,L) chương trình thực việc xố phần tử vị trí p (kiểu position) danh sách Nếu vị trí p khơng có danh sách phép tốn khơng định nghĩa danh sách L không thay đổi NEXT(p,L) cho kết vị trí phần tử (kiểu position) sau phần tử p; p phần tử cuối danh sách L NEXT(p,L) cho kết ENDLIST(L) Next khơng xác định p khơng phải vị trí phần tử danh sách PREVIOUS(p,L) cho kết vị trí phần tử đứng trước phần tử p danh sách Nếu p phần tử danh sách Previous(p,L) khơng xác định Previous không xác định trường hợp p vị trí phần tử danh sách FIRST(L) cho kết vị trí phần tử danh sách Nếu danh sách rỗng ENDLIST(L) trả EMPTY_LIST(L) cho kết TRUE danh sách có rỗng, ngược lại cho giá trị FALSE MAKENULL_LIST(L) khởi tạo danh sách L rỗng Trong thiết kế giải thuật sau dùng phép toán trừu tượng định nghĩa phép toán nguyên thủy Muốn thêm phần tử vào đầu hay cuối danh sách ta gọi phép tốn gọi phép tốn nào? Ví dụ: Dùng phép tốn trừu tượng danh sách, viết chương trình nhận tham số danh sách xếp danh sách theo thứ tự tăng dần (giả sử phần tử danh sách thuộc kiểu có thứ tự) Giả sử SWAP(p,q) thực việc đổi chỗ hai phần tử vị trí p q danh sách, chương trình xếp viết sau: void SORT(LIST L){ Position p,q; //kiểu vị trí phần tử danh sách p= FIRST(L); //vị trí phần tử danh sách while (p!=ENDLIST(L)){ q=NEXT(p,L); //vị trí phần tử đứng sau phần tử p while (q!=ENDLIST(L)){ if (RETRIEVE(p,L) > RETRIEVE(q,L)) swap(p,q); // dịch chuyển nội dung phần tử q=NEXT(q,L); } p=NEXT(p,L); Phụ lục 03 QT – KKT– 03/ 03 Trang 3/44 } } Tuy nhiên, cần phải nhấn mạnh rằng, phép toán trừu tượng định nghĩa, chưa cài đặt ngơn ngữ lập trình Do để cài đặt giải thuật thành chương trình chạy ta phải cài đặt phép toán thành chương trình chương trình Hơn nữa, cài đặt cụ thể, số tham số hình thức phép tốn trừu tượng khơng đóng vai trò chương trình cài đặt chúng, ta bỏ qua danh sách tham số chương trình Ví dụ: phép tốn trừu tượng INSERT_LIST(x,p,L) có tham số hình thức: phần tử muốn thêm x, vị trí thêm vào p danh sách thêm vào L Nhưng cài đặt danh sách trỏ (danh sách liên kết đơn), tham số L khơng cần thiết với cấu trúc có trỏ vị trí p phải thay đổi để nối kết với ô chứa phần tử Trong giảng này, ta giữ tham số cách cài đặt để làm cho chương trình đồng suốt phương pháp cài đặt kiểu liệu trừu tượng 3.1.3 Cài đặt danh sách 3.1.3.1 Cài đặt danh sách mảng (danh sách đặc) Ta cài đặt danh sách mảng sau: dùng mảng để lưu giữ liên tiếp phần tử danh sách từ vị trí mảng Với cách cài đặt này, dĩ nhiên, ta phải ước lượng số phần tử danh sách để khai báo số phần tử mảng cho thích hợp Dễ thấy số phần tử mảng phải khai báo khơng số phần tử danh sách Nói chung mảng thừa số chỗ trống Mặt khác ta phải lưu giữ độ dài danh sách, độ dài cho biết danh sách có phần tử cho biết phần mảng trống hình 3.1.1 Ta định nghĩa vị trí phần tử danh sách số mảng vị trí lưu trữ phần tử + 1(vì phần tử mảng số 0) Hình 3.1.1 Cài đặt danh sách mảng Với hình ảnh minh họa trên, ta cần khai báo cần thiết #define MaxLength //Số nguyên thích hợp để độ dài danh sách typedef ElementType;//kiểu phần tử danh sách typedef int Position; //kiểu vị trí cuả phần tử typedef struct { ElementType Elements[MaxLength]; //mảng chứa phần tử danh sách Phụ lục 03 QT – KKT– 03/ 03 Trang 4/44 Position Last; //giữ độ dài danh sách } List; Trên biểu diễn kiểu liệu trừu trượng danh sách cấu trúc liệu mảng Phần cài đặt phép toán danh sách Khởi tạo danh sách rỗng Danh sách rỗng danh sách không chứa phần tử (hay độ dài danh sách 0) Theo cách khai báo trên, trường Last vị trí phần tử cuối danh sách độ dài danh sách, để khởi tạo danh sách rỗng ta việc gán giá trị trường Last void MakeNull_List(List *L) { L->Last=0; } Kiểm tra danh sách rỗng Danh sách rỗng danh sách mà độ dài int Empty_List(List L){ return L.Last==0; } Xen phần tử vào danh sách Khi xen phần tử có nội dung x vào vị trí p danh sách L xuất khả sau: Mảng đầy: phần tử mảng chứa phần tử danh sách, tức phần tử cuối danh sách nằm vị trí cuối mảng Nói cách khác, độ dài danh sách số tối đa mảng; Khi khơng chỗ cho phần tử mới, việc xen khơng thể thực được, chương trình gặp lỗi Ngược lại ta tiếp tục xét: Nếu p không hợp lệ (p>last+1 pLast==MaxLength) printf("Danh sach day"); else if ((PL->Last+1)) printf("Vi tri khong hop le"); else{ Position Q; Phụ lục 03 QT – KKT– 03/ 03 Trang 5/44 /*Dời phần tử từ vị trí p (chỉ số mảng p-1) đến cuối danh sách sang phải vị trí*/ for(Q=(L->Last-1)+1;Q>P-1;Q ) L->Elements[Q]=L->Elements[Q-1]; //Đưa x vào vị trí p L->Elements[P-1]=X; //Tăng độ dài danh sách lên L->Last++; } } Xóa phần tử khỏi danh sách Xố phần tử vị trí p khỏi danh sách L ta làm công việc ngược lại với xen Trước tiên ta kiểm tra vị trí phần tử cần xóa xem có hợp lệ hay chưa Nếu p>L.last pLast)) printf("Vi tri khong hop le"); else if (EmptyList(*L)) printf("Danh sach rong!"); else{ Position Q; /*Dời phần tử từ vị trí p+1 (chỉ số mảng p) đến cuối danh sách sang trái vị trí*/ for(Q=P-1;QLast-1;Q++) L->Elements[Q]=L->Elements[Q+1]; L->Last ; } } Định vị phần tử danh sách Để định vị vị trí phần tử có nội dung x danh sách L, ta tiến hành dò tìm từ đầu danh sách Nếu tìm thấy x vị trí phần tử tìm thấy trả về, khơng tìm thấy hàm trả vị trí sau vị trí phần tử cuối danh sách, tức ENDLIST(L) (ENDLIST(L)= L.Last+1) Trong trường hợp có nhiều phần tử giá trị x danh sách vị trí phần tử tìm thấy trả Position Locate(ElementType X, List L){ Position P; int Found = 0; Phụ lục 03 QT – KKT– 03/ 03 Trang 6/44 P = First(L); //vị trí phần tử /*trong chưa tìm thấy chưa kết thúc danh sách xét phần tử kế tiếp*/ while ((P != EndList(L)) && (Found == 0)) if (Retrieve(P,L) == X) Found = 1; else P = Next(P, L); return P; } Lưu ý : Các phép toán sau phải thiết kế trước Locate o First(L)=1 o Retrieve(P,L)=L.Elements[P-1] o EndList(L)=L.Last+1 o Next(P,L)=P+1 Hãy giải thích nội dung phần tử vị trí P danh sách L L.Elements[P-1]? Ví dụ : Vận dụng phép tốn danh sách đặc để viết chương trình nhập vào danh sách số nguyên hiển thị danh sách vừa nhập hình Thêm phần tử có nội dung x vào danh sách ví trí p (trong x p nhập từ bàn phím) Xóa phần tử có nội dung x (nhập từ bàn phím) khỏi danh sách Hướng giải : Giả sử ta cài đặt đầy đủ phép toán danh sách Để thực yêu cầu trên, ta cần thiết kế thêm số chương trình sau : - Nhập danh sách từ bàn phím (READ_LIST(L)) (Phép tốn chưa có kiểu danh sách) - Hiển thị danh sách hình (in danh sách) (PRINT_LIST(L)) (Phép tốn chưa có kiểu danh sách) Thực cần sử dụng phép toán MakeNull_List, Insert_List, Delete_List, Locate chương trình Read_List, Print_List vừa nói giải tốn Để đáp ứng u cầu đặt ra, ta viết chương trình để nối kết chương trình lại với sau: int main() { List L; ElementType X; Position P; MakeNull_List(&L); //Khởi tạo danh sách rỗng Read_List(&L); printf("Danh sach vua nhap: "); Print_List(L); // In danh sach len man hinh printf("Phan tu can them: ");scanf("%d",&X); printf("Vi tri can them: ");scanf("%d",&P); Phụ lục 03 QT – KKT– 03/ 03 Trang 7/44 Insert_List(X,P,&L); printf("Danh sach sau them phan tu la: "); PrintList(L); printf("Noi dung phan tu can xoa: ");scanf("%d",&X); P=Locate(X,L); Delete_List(P,&L); printf("Danh sach sau xoa %d la: ",X); Print_List(L); return 0; } 3.1.3.2 Cài đặt danh sách trỏ ( danh sách liên kết) Cách khác để cài đặt danh sách dùng trỏ để liên kết ô chứa phần tử Trong cách cài đặt phần tử danh sách lưu trữ ơ, đến chứa phần tử danh sách Có thể hình dung chế qua ví dụ sau: Giả sử lớp có bạn: Đơng, Tây, Nam, Bắc có địa d,t,n,b Giả sử: Đơng có địa Nam, Tây khơng có địa bạn nào, Bắc giữ địa Đơng, Nam có địa Tây (xem hình 3.1.2) Hình 3.1.2 Danh sách liên kết Như vậy, ta xét thứ tự phần tử chế đến ta có danh sách: Bắc, Đơng, Nam, Tây Hơn để có danh sách ta cần cần giữ địa Bắc Trong cài đặt, để đến khác ta cài đặt ô mẩu tin (record, struct) có hai trường: trường Element giữ giá trị phần tử danh sách; trường next trỏ giữ địa ô kế tiếp.Trường next phần tử cuối danh sách đến giá trị đặc biệt NULL Cấu trúc gọi danh sách cài đặt trỏ hay danh sách liên kết đơn hay ngắn gọn danh sách liên kết Hình 3.1.3 Danh sách liên kết đơn Phụ lục 03 QT – KKT– 03/ 03 Trang 8/44 Để quản lý danh sách ta cần biến giữ địa ô chứa phần tử danh sách, tức trỏ trỏ đến phần tử danh sách Biến gọi điểm đầu danh sách (Header) Để đơn giản hóa vấn đề, chi tiết cài đặt, Header biến kiểu với ô chứa phần tử danh sách cấp phát ô nhớ y ô chứa phần tử danh sách (hình II.3) Tuy nhiên Header đặc biệt nên khơng chứa phần tử danh sách, trường liệu ô rỗng, có trường trỏ Next trỏ tới chứa phần tử thật danh sách Nếu danh sách rỗng Header->next trỏ tới NULL Việc cấp phát ô nhớ cho Header ô chứa liệu bình thường nhằm tăng tính đơn giản giải thuật thêm, xoá phần tử danh sách Ở ta cần phân biệt rõ giá trị phần tử vị trí (position) cấu trúcdụ giá trị phần tử danh sách hình 3.1.4 a1, Trong vị trí địa chứa nó, tức giá trị nằm trường next Header Giá trị vị trí phần tử danh sách hình 3.1.4 sau: Hình 3.1.4 Vị trí phần tử danh sách liên kết Như thấy bảng trên, vị trí phần tử thứ i (i-1), để biết vị trí phần tử thứ i ta phải truy xuất vào ô thứ (i-1) Khi thêm xoá phần tử danh sách liên kết vị trí p, ta phải cập nhật lại trỏ trỏ tới vị trí này, tức cập nhật lại (p-1) Nói cách khác, để thao tác vào vị trí p ta phải biết trỏ trỏ vào p mà trỏ (p-1) Do ta định nghĩa p-1 vị trí p Có thể nói nơm na vị trí phần tử a i địa ô đứng phía trước chứa Hay xác hơn, ta nói, vị trí phần tử thứ i trỏ trỏ tới có trường next trỏ tới chứa phần tử a i Như vị trí phần tử thứ trỏ trỏ đến Header, vị trí phần tử thứ trỏ trỏ ô chứa phần tử a 1, vị trí phần tử thứ trỏ trỏ ô a 2, , vị trí phần tử thứ n trỏ trỏ chứa a n-1 Vậy vị trí sau phần tử cuối danh sách, tức ENDLIST, trỏ trỏ chứa phần tử an (xem hình II.3) Theo định nghĩa ta có, p vị trí phần tử thứ p danh sách giá trị phần tử vị trí p nằm trường element ô trỏ p->next Nói cách khác p->next>element chứa nội dung phần tử vị trí p danh sách Các khai báo cần thiết typedef ElementType; //kiểu phần tử danh sách Phụ lục 03 QT – KKT– 03/ 03 Trang 9/44 typedef struct Node{ ElementType Element;//Chứa nội dung phần tử Node* Next; /*con trỏ đến phần tử danh sách*/ }; typedef Node* Position; // Kiểu vị trí typedef Position List; Tạo danh sách rỗng Như nói phần trên, ta dùng Header biến trỏ có kiểu giống kiểu ô chứa phần tử danh sách Tuy nhiên trường Element Header không dùng, có trường Next dùng để trỏ tới ô chứa phần tử danh sách Vậy danh sách rỗng trường Header phải tồn có trường next đến NULL (do khơng có phần tử nào) Vì khởi tạo danh sách rỗng, ta phải cấp phát ô nhớ cho HEADER cho trỏ trường next trỏ tới NULL void MakeNull_List(List *Header){ (*Header)=(Node*)malloc(sizeof(Node)); (*Header)->Next= NULL; } Kiểm tra danh sách rỗng Danh sách rỗng trường next ô Header trỏ tới NULL int Empty_List(List L){ return (L->Next==NULL); } Xen phần tử vào danh sách : Xen phần tử có giá trị x vào danh sách L vị trí p ta phải cấp phát để lưu trữ phần tử nối kết lại trỏ để đưa ô vào vị trí p Sơ đồ nối kết thứ tự thao tác cho hình 3.1.5 Hình 3.1.5 Thêm phần tử vào danh sách vị trí P void Insert_List(ElementType X, Position P, List *L){ Position T; T=(Node*)malloc(sizeof(Node)); T->Element=X; Phụ lục 03 QT – KKT– 03/ 03 Trang 10/44 int EmptyTree(Tree T){ return T.MaxNode == 0; } Xác định nút cha nút Node Parent(Node n,Tree T){ if (EmptyTree(T) || (n>T.MaxNode-1)) return NIL; else return T.Parent[n]; } Xác định nhãn nút DataType Label_Node(Node n,Tree T){ if (!EmptyTree(T) && (nright; else return NULL; } Kiểm tra nút lá: Nếu nút nút khơng có nên trái phải nil 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)); } Tạo từ hai có sẵn TTree Create2(Tdata v,TTree l,TTree r){ TTree N; Phụ lục 03 QT – KKT– 03/ 03 Trang 36/44 N=(TNode*)malloc(sizeof(TNode)); N->Data=v; N->left=l; N->right=r; return N; } 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){ printf("%c ",T->Data); if (LeftChild(T)!=NULL) PreOrder(LeftChild(T)); if (RightChild(T)!=NULL)PreOrder(RightChild(T)); } Thủ tục duyệt trung tự void InOrder(TTree T){ if (LeftChild(T)=!NULL)InOrder(LeftChild(T)); printf("%c ",T->data); if (RightChild(T)!=NULL) InOrder(RightChild(T)); } Thủ tục duyệt hậu tự void PosOrder(TTree T){ if (LeftChild(T)!=NULL) PosOrder(LeftChild(T)); if (RightChild(T)!=NULL)PosOrder(RightChild(T)); printf("%c ",T->data); } 4.5 Cây Tìm kiếm nhị phân 4.5.1 Định nghĩa Cây tìm kiếm nhị phân (TKNP) nhị phân mà khoá nút lớn khoá tất nút thuộc bên trái nhỏ khoá tất nút thuộc bên phải Lưu ý: liệu lưu trữ nút phức tạp record chẳng hạn, trường hợp khố nút tính dựa trường đó, ta gọi trường khố Trường khố phải chứa giá trị so sánh được, tức phải lấy giá trị từ tập hợp có thứ tự Ví dụ: hình III.15 minh hoạ TKNP có khố số ngun (với quan hệ thứ tự tập số nguyên) Phụ lục 03 QT – KKT– 03/ 03 Trang 37/44 Hình 4.15 Cây Tìm kiếm nhị phân Qui ước: Cũng tất cấu trúc khác, ta coi rỗng TKNP Nhận xét: Trên TKNP khơng có hai nút khố Cây TKNP TKNP Khi duyệt trung tự (InOrder) TKNP ta dãy có thứ tự tăng Chẳng hạn duyệt trung tự ta có dãy: 5, 10, 15, 17, 20, 22, 30, 35, 42 4.5.2 Cài đặt TKNP Cây TKNP, trước hết, nhị phân Do ta áp dụng cách cài đặt trình bày phần nhị phân Sẽ khơng có khác biệt việc cài đặt cấu trúc liệu cho TKNP so với nhị phân, tất nhiên, có khác biệt giải thuật thao tác TKNP tìm kiếm, thêm xố nút TKNP để ln đảm bảo tính chất cuả TKNP Một cách cài đặt TKNP thường gặp cài đặt trỏ Mỗi nút mẩu tin (record) có ba trường: trường chứa khố, hai trường hai trỏ trỏ đến hai nút (nếu nút vắng mặt ta gán trỏ NIL) Khai báo sau typedef KeyType; typedef struct Node{KeyType Key; Node* Left,Right;} typedef Node* Tree; Khởi tạo TKNP rỗng Ta cho trỏ quản lý nút gốc (Root) NIL void MakeNullTree(Tree *Root){ (*Root)=NULL; } Tìm kiếm nút có khóa cho trước TKNP Để tìm kiếm nút có khố x TKNP, ta tiến hành từ nút gốc cách so sánh khoá nút gốc với khố x Nếu nút gốc NULL khơng có khố x Nếu x khố nút gốc giải thuật dừng ta tìm nút chứa khoá x Phụ lục 03 QT – KKT– 03/ 03 Trang 38/44 Nếu x lớn khoá nút gốc ta tiến hành (một cách đệ qui) việc tìm khố x bên phải Nếu x nhỏ khố nút gốc ta tiến hành (một cách đệ qui) việc tìm khố x bên trái Ví dụ: tìm nút có khố 30 trong hình III.15 - So sánh 30 với khố nút gốc 20, 30 > 20 ta tìm tiếp bên phải, tức có nút gốc có khố 35 - So sánh 30 với khoá nút gốc 35, 30 < 35 ta tìm tiếp bên trái, tức có nút gốc có khố 22 - So sánh 30 với khố nút gốc 22, 30 > 22 ta tìm tiếp bên phải, tức có nút gốc có khố 30 - So sánh 30 với khoá nút gốc 30, 30 = 30 đến giải thuật dừng ta tìm nút chứa khố cần tìm Hàm trả kết trỏ trỏ tới nút chứa khố x NULL khơng tìm thấy khố x TKNP Tree Search(KeyType x,Tree Root){ if (Root == NULL) return NULL; //khơng tìm thấy khố x else if (Root->Key == x) /* tìm thấy khố x */ return Root; else if (Root->Key < x) //tìm tiếp bên phải return Search(x,Root->right); else {tìm tiếp bên trái} return Search(x,Root->left); } Nhận xét: giải thuật hiệu mặt thời gian TKNP tổ chức tốt, nghĩa tương đối "cân bằng" Về chủ đề cân bạn tham khảo thêm tài liệu tham khảo mơn Thêm nút có khóa cho trước vào TKNP Theo định nghĩa tìm kiếm nhị phân ta thấy tìm kiếm nhị phân khơng có hai nút có khố Do ta muốn thêm nút có khố x vào TKNP trước hết ta phải tìm kiếm để xác định có nút chứa khố x chưa Nếu có giải thuật kết thúc (khơng làm cả!) Ngược lại, thêm nút chứa khoá x Việc thêm khoá vào TKNP việc tìm kiếm thêm nút, tất nhiên, phải đảm bảo cấu trúc TKNP không bị phá vỡ Giải thuật cụ thể sau: Ta tiến hành từ nút gốc cách so sánh khóa cuả nút gốc với khố x Nếu nút gốc NULL khố x chưa có cây, ta thêm nút chứa khoá x Nếu x khoá nút gốc giải thuật dừng, trường hợp ta khơng thêm nút Nếu x lớn khoá nút gốc ta tiến hành (một cách đệ qui) giải thuật bên phải Phụ lục 03 QT – KKT– 03/ 03 Trang 39/44 Nếu x nhỏ khố nút gốc ta tiến hành (một cách đệ qui) giải thuật bên trái Ví dụ: thêm khố 19 vào hình 4.15 - So sánh 19 với khoá nút gốc 20, 19 < 20 ta xét tiếp đến bên trái, tức có nút gốc có khố là10 Cây tìm kiếm nhị phân tổ chức để trình tìm kiếm hiệu nhất? - So sánh 19 với khoá nút gốc 10, 19 > 10 ta xét tiếp đến bên phải, tức có nút gốc có khố 17 - So sánh 19 với khố nút gốc 17, 19 > 17 ta xét tiếp đến bên phải Nút bên phải NULL, chứng tỏ khoá 19 chưa có cây, ta thêm nút chứa khố 19 nút bên phải nút có khố 17, xem hình 4.16 Hình 4.16 Cây nhị phân sau thêm nút có khóa 19 Thủ tục sau tiến hành việc thêm khoá vào TKNP void InsertNode(KeyType x,Tree *Root ){ if (*Root == NULL){ /* thêm nút chứa khoá x */ (*Root)=(Node*)malloc(sizeof(Node)); (*Root)->Key = x; (*Root)->left = NULL; (*Root)->right = NULL; } else if (x < (*Root)->Key) InsertNode(x,Root->left); else if (x>(*Root)->Key)InsertNode(x,Root->right); } Xóa nút có khóa cho trước khỏi TKNP Giả sử ta muốn xoá nút có khố x, trước hết ta phải tìm kiếm nút chứa khoá x Phụ lục 03 QT – KKT– 03/ 03 Trang 40/44 Hình 4.17 Xóa nút TKNP Việc xoá nút vậy, tất nhiên, ta phải bảo đảm cấu trúc TKNP không bị phá vỡ Ta có trường hợp hình 4.17: Hình 4.17 Ví dụ giải thuật xóa nút Nếu khơng tìm thấy nút chứa khố x giải thuật kết thúc Nếu tìm gặp nút N có chứa khố x, ta có ba trường hợp sau (xem hình 4.17) · Nếu N ta thay NULL · N có nút ta thay nút · N có hai nút ta thay nút lớn trái (nút cực phải trái) nút bé phải (nút cực trái phải) Trong giải thuật sau, ta thay x khoá nút cực trái bên phải ta xoá nút cực trái Việc xoá nút cực trái bên phải rơi vào hai trường hợp Giải thuật xoá nút có khố nhỏ Hàm trả khố nút cực trái, đồng thời xoá nút KeyType DeleteMin (Tree *Root ){ KeyType k; if ((*Root)->left == NULL){ k=(*Root)->key; (*Root) = (*Root)->right; return k; } else return DeleteMin(Root->left); } Phụ lục 03 QT – KKT– 03/ 03 Trang 41/44 Thủ tục xóa nút có khố cho trước TKNP Phụ lục 03 QT – KKT– 03/ 03 Trang 42/44 void DeleteNode(key X,Tree *Root){ if ((*Root)!=NULL) if (x < (*Root)->Key) DeleteNode(x,Root->left) else if (x > (*Root)->Key) DeleteNode(x,Root->right) else if ((*Root)->left==NULL)&&((*Root)->right==NULL) (*Root)=NULL; else if ((*Root)->left == NULL) (*Root) = (*Root)->right else if ((*Root)->right==NULL) (*Root) = (*Root)->left else (*Root)->Key = DeleteMin(Root->right); } Câu hỏi ôn tập: Bài tập Trình bày biểu thức duyệt tiền tự, trung tự, hậu tự sau: Duyệt theo mức duyệt gốc, duyệt nút nằm mức theo thứ tự từ trái sang phải, đến nút nằm mức theo thứ tự từ trái sang phải a Hãy liệt kê nút theo thứ tự duyệt theo mức b Viết thủ tục duyệt theo mức (Gợi ý: dùng hàng đợi) Vẽ biểu diễn cho biểu thức ((a+b)+c*(d+e)+f)*(g+h) Trình bày biểu thức tiền tố hậu tố biểu thức cho Viết chương trình để tính giá trị biểu thức cho: a Biểu thức tiền tố b Biểu thức hậu tố Ví dụ: - đầu vào (input): * + - đầu (output) là: 50 biểu thức dạng tiền tố (6+4) * Tương tự: - đầu vào (input): + * - đầu (output) là: 54 biểu thức dạng hậu tố * (4+5) Cho nhị phân a Hãy trình bày duyệt: tiền tự (node-left-right), trung tự (left-node-right), hậu tự (left-rightnode) b Minh hoạ lưu trữ nút mảng Chứng minh rằng: biết biểu thức duyệt tiền tự trung tự nhị phân ta dựng Điều khơng? Khi biết biểu thức duyệt: a Tiền tự hậu tự b Trung tự hậu tự Nêu trường hợp mà giải thuật TKNP: - Có hiệu - Kém hiệu Từ nêu hướng tổ chức TKNP để đạt hiệu cao thời gian thực giải thuật a- Vẽ hình tìm kiếm nhị phân tạo từ rỗng cách thêm vào khoá số nguyên: 54, 31, 43, 29, 65, 10, 20, 36, 78, 59 b- Vẽ lại hình tìm kiếm nhị phân câu a/ sau xen thêm nút 15, 45, 55 c- Vẽ lại hình tìm kiếm nhị phân câu a/ sau xoá nút 10, 20, 43, 65, 54 Hãy dựng tìm kiếm nhị phân ứng với dãy khóa (thứ tự tính theo qui tắc so sánh chuỗi (string)): HAIPHONG, CANTHO, NHATRANG, DALAT, HANOI, ANGIANG, MINHHAI, HUE, SAIGON, VINHLONG Đánh dấu đường tìm kiếm khóa DONGTHAP Trưởng khoa (Ký tên, học vị, họ tên) Người biên soạn (Ký tên, học vị, họ tên) Ths Trương Thanh Tú ... printf(”Loi : Hang rong”); } Một số ứng dụng cấu trúc hàng Hàng đợi cấu trúc liệu dùng phổ biến thiết kế giải thuật Bất kỳ nơi ta cần quản lí liệu, q trình theo kiểu vào trước-ra trước ứng dụng hàng đợi... sau Các giải thuật duyệt theo chiều rộng đồ thị có hướng vơ hướng dùng hàng đợi để quản lí nút đồ thị Các giải thuật đổi biểu thức trung tố thành hậu tố, tiền tố Câu hỏi ôn tập: Bài tập Viết... độ ưu tiên ta kết hợp từ trái sang phải Ví dụ a+b+c-d = ((a+b)+c)-d 4.2 Kiểu liệu trừu tượng Để hoàn tất định nghĩa kiểu liệu trừu tượng cây, kiểu liệu trừu tượng khác, ta phải định nghĩa phép

Ngày đăng: 06/11/2017, 22:28

TỪ KHÓA LIÊN QUAN

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

TÀI LIỆU LIÊN QUAN

w