Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 116 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
116
Dung lượng
359,58 KB
Nội dung
CẤU TRÚC DỮ LIỆU Cấu trúc liệu Chương I: Các kiểu liệu trừu tượng CHƯƠNG I CÁC KIỂU DỮ LIỆU TRỪU TƯỢNG CƠ BẢN (BASIC ABSTRACT DATA TYPES) TỔNG QUAN Mục tiêu Sau học xong chương này, sinh viên - Nắm vững kiểu liệu trừu tượng như: danh sách, ngăn xếp, hàng đợi - Cài đặt kiểu liệu ngôn ngữ lập trình cụ thể - Ứng dụng kiểu liệu trừu tượng toán thực tế Kiến thức cần thiết Để học tốt chương này, sinh viên phải nắm vững kỹ lập trình như: - Kiểu cấu trúc (struct) , kiểu mảng kiểu trỏ - Các cấu trúc điều khiển, lệnh vòng lặp - Lập trình theo modul (chương trình con) cách gọi chương trình Tài liệu tham khảo [1] Aho, A V , J E Hopcroft, J D Ullman "Data Structure and Algorithms", Addison– Wesley; 1983 (chapter 2) [2] Đỗ Xuân Lôi "Cấu trúc liệu giải thuật" Nhà xuất khoa học kỹ thuật Hà nội, 1995 (chương 4,5 trang 71-119) [3] Nguyễn Trung Trực, "Cấu trúc liệu" BK HCM, 1990 (chương trang 22-109) [4] Lê Minh Trung ; “Lập trình nâng cao Pascal với cấu t (chương 7, 8) rúc liệu “; 1997 Nội dung cốt lõi Trong chương nghiên cứu số kiểu liệu trừu tượng sau: - Kiểu liệu trừu tượng danh sách (LIST) 22 wwaatteerrmmaarrkk Cấu trúc liệu Chương I: Các kiểu liệu trừu tượng - Kiểu liệu trừu tượng ngăn xếp (STACK) 23 C uu D uo ng T nC on g.c o m PPDDFF WWaa tee r m a r kk RR ee mm oo vv eerr DDEEMMOO :: PPuurrcchhaassee ffrroomm - Kiểu liệu trừu tượng hàng đợi (QUEUE) Trang wwaatteerrmmaarrkk 23 I KIỂU DỮ LIỆU TRỪU TƯỢNG DANH SÁCH (LIST) 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 a1 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 Các phép tố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 Và thấy tồ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 toá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 a1, 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 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 khơng phải 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 thêmtophần tử vào đầu hay cuối danh sách ta gọi phép Muốn gọi phép án nào? tốn Ví dụ: Dùng phép toá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: Trang wwaatteerrmmaarrkk 25 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); } } 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 tố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 Cài đặt danh sách a 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 II.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) Chỉ số Nội dung Phần tử thứ phần tử Phần tử thứ … Last-1 … … Phần tử cuối … danh sách Maxlength-1 Hình II.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 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; } Trang 27 Cấu trúc liệu Chương II: Các kiểu liệu trừu tượng Hãy trình bày cách gọi thực thi chương trình tạo danh sách rỗng trên? Hãy giải thích cách khai báo tham số hình thức chương trình cách truyền tham số gọi chương trình đó? 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 k há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; /*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; Trang 29 (*D)[Bucket]->Next=P; } } Xoá phần tử từ điển cài bảng băm mở Xoá phần tử có khố x từ điển bao gồm việc tìm chứa khố xố Phần tử x, có từ điển, nằm bucket D[h(x)] Có hai trường hợp cần phân biệt Nếu x nằm đầu bucket, sau xoá x phần tử sau x bucket trở thành đầu bucket Nếu x không nằm đầu bucket ta duyệt bucket để tìm xố x Trong trường hợp ta phải định vị trỏ duyệt "ô trước" ô chứa x để cập nhật lại trỏ Next ô Giải thuật sau: void DeleteSet(ElementType X, Dictionary *D) { int Bucket, Done; Position P,Q; Bucket=H(X); // Neu danh sach ton tai if ((*D)[Bucket]!=NULL) { // X o dau danh sach if ((*D)[Bucket]->Data==X) { Q=(*D)[Bucket]; (*D)[Bucket]=(*D)[Bucket]->Next; free(Q); } else // Tim X { Done=0; P=(*D) [Bucket]; while ((P->Next!=NULL) && (!Done)) if (P->Next->Data==X) Done=1; else P=P->Next; // Neu tim thay if (Done) { //Xoa P->Next Q=P->Next; P->Next=Q->Next; free(Q); } } } } 2.2 Cài đặt từ điển bảng băm đóng Định nghĩa bảng băm đóng : Bảng băm đóng lưu giữ phần tử từ điển mảng không dùng mảng làm điểm đầu danh sách liên kết Bucket thứ i chứa phần tử có giá trị băm i, có nhiều phần tử có giá trị băm nên ta gặp trường hợp sau: ta muốn đưa vào bucket i phần tử x bucket bị chiếm phần tử y (đụng độ) Như thiết kế bảng băm đóng ta phải có cách để giải đụng độ Giải đụng độ : Cách giải đụng độ gọi chiến lược băm lại (rehash strategy) Chiến lược băm lại chọn vị trí h1, , hk theo cách gặp vị trí trống để đặt x vào Dãy h1, , hk gọi dãy phép thử Một chiến lược đơn giản băm lại tuyến tính, dãy phép thử có dạng : hi(x)=(h(x) +i) mod B Ví dụ B=8 phần tử từ điển a,b,c,d có giá trị băm là: h(a)=3, h(b)=0, h(c)=4, h(d)=3 Ta muốn đưa phần tử vào bảng băm Khởi đầu bảng băm rỗng, coi bucket chứa giá trị đặc biệt Empty, Empty không với phần tử mà ta xét tập hợp phần tử muốn đưa vào bảng băm Ta đặt a vào bucket 3, b vào bucket 0, c vào bucket Xét phần tử d, d có h(d)=3 bucket bị a chiếm ta tìm vị trí h1(x)= (h (x)+1) mod B = 4, vị trí bị c chiếm, tiếp tục tìm sang vị trí h2 (x)= (h(x)+2) mod B= bucket rỗng ta đặt d vào (xem hình IV.2) b a c d Hình IV.2: Giải đụng độ bảng băm đóng chiến lược băm lại tuyến tính Trong bảng băm đóng, phép kiểm tra thành viên(thủ tục MEMBER (x,A)) phải xét dãy bucket h(x),h1(x),h2(x), tìm thấy x tìm thấy vị trí trống Bởi hk(x) vị trí trống gặp x khơng thể tìm gặ p vị trí xa Tuy nhiên, nói chung điều với trường hợp ta k hơng xố phần tử bảng băm Nếu chấp nhận phép xố qui ước phần tử bị xóa thay giá trị đặc biệt, gọi Deleted, giá trị Deleted không với phần tử tập hợp xét vào phải khác giá trị Empty Empty giá trị đặc biệt cho ta biết trống Ví dụ - Tìm phần tử e bảng băm trên, giả sử h(e)=4 Chúng ta tìm kiếm e vị trí 4,5,6 Bucket chứa Empty, khơng có e bảng băm - Tìm d, h(d)=3 ta khởi đầu vị trí duyệt qua bucket 4,5 Phần tử d tìm thấy bucket Sử dụng bảng băm đóng để cài đặt từ điển Dưới khai báo thủ tục cần thiết để cài đặt từ điển bảng băm đóng Để dễ dàng minh hoạ giá trị Deleted Empty, giả sử ta cần cài đặt từ điển gồm chuỗi 10 kí tự Ta qui ước: Empty chuỗi 10 dấu + Deleted chuỗi 10 dấu * Khai báo #define B 100 #define Deleted -1000//Gia dinh gia tri cho o da bi xoa #define Empty 1000 //Gia dinh gia tri cho o chua su dung typedef int ElementType; typedef int Dictionary [B]; Tạo hàm băm int H (ElementType X)] { return X%B; } Tạo tự điển rỗng // Tao tu dien rong void MakeNullDic(Dictionary D){ for (int i=0;iLast]=X; while ((i>0)&&(p(L->Data[i])Data[i/2]))) { temp=(*L).Data[i]; (*L).Data[i]=(*)L.Data[i/2]; (*L).Data[i/2]=temp; i=i/2; } } } Xóa phần tử có độ ưu tiên bé ElementType DeleteMin(Position P,PriorityQueue *L) { if (EmptyPriorityQueue(*L)) printf("\nHang rong!"); else { ElementType minimum= (*L).Data[1]; (*L).Data[1]=(*L).Data[(*L).Last]; (*L).Last ; // Qua trinh day xuong int i=1,found =0; while ((iLast/2)&&(found==0)) // Tim nut be nhat hai nut cua i if((p((*L).Data[2*i]Last)) j=2*i; else j=2*i+1; if ((p((*L).Data[i]>p((*L).Data[j])) { // Doi cho hai phan tu temp=(*L).Data[i]; (*L).Data[i]=(*L).Data[j]; (*L).Data[j]=temp; i=j; // Bat dau o muc moi } else found=1; return minimum; } } 151 wwaatteerrmm ... vững kỹ lập trình như: - Kiểu cấu trúc (struct) , kiểu mảng kiểu trỏ - Các cấu trúc điều khiển, lệnh vòng lặp - Lập trình theo modul (chương trình con) cách gọi chương trình Tài liệu tham khảo... Trang 27 Cấu trúc liệu Chương II: Các kiểu liệu trừu tượng Hãy trình bày cách gọi thực thi chương trình tạo danh sách rỗng trên? Hãy giải thích cách khai báo tham số hình thức chương trình cách... 1983 (chapter 2) [2] Đỗ Xuân Lôi "Cấu trúc liệu giải thuật" Nhà xuất khoa học kỹ thuật Hà nội, 1995 (chương 4,5 trang 71-119) [3] Nguyễn Trung Trực, "Cấu trúc liệu" BK HCM, 1990 (chương trang