cấu trúc dữ liệu danh sách

36 283 0
cấu trúc dữ liệu danh sách

Đ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

Trần Quốc Chiến Cấu trúc liệu giải thuật CHƯƠNG II CẤU TRÚC DỮ LIỆU DANH SÁCH Chương II Cấu trúc liệu danh sách II.1 Trần Quốc Chiến Cấu trúc liệu giải thuật I TỔNG QUAN VỀ DANH SÁCH Định nghĩa Danh sách (List) dãy phần tử a1, , an (n  1) với tính chất: biết biết ai+1 Danh sách xếp tuyến tính theo vị trí chúng Số phần tử n gọi độ dài danh sách Nếu n = 0, ta có danh sách rỗng  Ví dụ - Danh sách nhân viên quan - Danh sách sinh viên lớp - Danh sách môn học - Danh sách số tự nhiên không 100 Các phép toán danh sách Để tạo lập, cập nhật, khai thác danh sách, người ta định nghĩa phép toán sau a Phép duyệt danh sách Duyệt danh sách duyệt qua tất phần tử danh sách thoả mãn để thực cơng việc (chẳng hạn hiển thị phần tử)  Ví dụ: Liệt kê danh sách nữ nhân viên quan b Phép tìm kiếm Tìm kiếm thao tác tìm phần tử danh sách thoả mãn điều kiện Kết phép tìm kiếm tìm thấy khơng tìm thấy Sau tìm thấy phần tử cần tìm ta thực phép tốn phần tử sửa đổi hay xố  Ví dụ: Trong danh sách nhân viên quan, tìm nhân viên có tên “Trần Công Minh” c Thêm phần tử vào danh sách Đây thao tác thêm phần tử vào danh sách Phần tử thêm vào cuối danh sách, đầu danh sách chèn vào danh sách Nếu danh sách đầy, tức số phần tử danh sách số cực đại cho phép phép tốn thêm khơng Chương II Cấu trúc liệu danh sách II.2 Trần Quốc Chiến Cấu trúc liệu giải thuật thực Nếu danh sách chưa đầy thêm phần tử vào danh sách độ dài (số phần tử) danh sách tăng thêm  Ví dụ: Trong danh sách nhân viên quan, thêm nhân viên hợp đồng có tên “Trần Cơng Minh” d Loại bỏ phần tử khỏi danh sách Đây thao tác loại bỏ phần tử khỏi danh sách Trước loại bỏ phần tử, chưa xác định phần tử loại bỏ, phải thực phép tìm kiếm Nếu khơng tìm thấy khơng thể thực phép loại bỏ Nếu tìm thấy thực phép loại bỏ độ dài (số phần tử) danh sách giảm Phần tử loại bỏ cuối danh sách, đầu danh sách danh sách  Ví dụ Trong danh sách nhân viên quan, loại bỏ nhân viên cắt hợp đồng có tên “Trần Công Minh” e Sửa đổi phần tử danh sách Đây thao tác hiệu chỉnh phần tử danh sách Trước hiệu chỉnh phần tử, chưa xác định phần tử hiệu chỉnh, phải thực phép tìm kiếm Nếu khơng tìm thấy khơng thể thực phép hiệu chỉnh Nếu tìm thấy thực phép hiệu chỉnh Số phần tử danh sách không thay đổi Phần tử hiệu chỉnh cuối danh sách, đầu danh sách danh sách  Ví dụ Trong danh sách nhân viên quan, hiệu chỉnh mức lương cho nhân viên có tên “Trần Cơng Minh” f Sắp xếp thứ tự danh sách Đây thao tác xếp lại thứ tự phần tử danh sách theo khố Thứ tự phần tử thay đổi, số phần tử giữ nguyên  Ví dụ: Sắp xếp danh sách nhân viên quan theo họ tên theo mức lương g Tách danh sách thành nhiều danh sách Đây thao tác tách phần lấy tất phần tử danh sách đưa sang danh sách khác  Ví dụ Từ danh sách nhân viên quan tách riêng danh sách nữ nhân viên h Ghép nhiều danh sách thành danh sách Đây thao tác lấy tất phần tử từ danh sách khác tạo thành danh sách Các phần tử danh sách xếp cạnh Chương II Cấu trúc liệu danh sách II.3 Trần Quốc Chiến Cấu trúc liệu giải thuật  Ví dụ Từ danh sách nhân viên phòng ghép lại thành danh sách nhân viên toàn quan i Trộn nhiều danh sách thành danh sách Đây thao tác lấy tất phần tử từ danh sách khác tạo thành danh sách theo cấu trúc Các phần tử danh sách bị xáo trộn  Ví dụ Từ danh sách nhân viên phòng xếp theo họ tên trộn lại thành danh sách nhân viên toàn quan xếp theo họ tên Chương II Cấu trúc liệu danh sách II.4 Trần Quốc Chiến Cấu trúc liệu giải thuật II DANH SÁCH ĐẶC Định nghĩa khai báo a Định nghĩa Danh sách đặc (condensed list) hay gọi danh sách kề (contiguous list) danh sách mà phần tử lưu trữ nhớ, phần tử thứ i+1 đứng sau phần tử thứ i Hình sau mơ tả danh sách đặc, phần tử có kích thước xếp a1 add[1] a2 ai+1 add[i] d an1 an add[n] Nếu phần tử có độ dài d byte ký hiệu địa phần tử i add[i], ta sử dụng cơng thức tính địa sau: add[i] = add[1] + (i1)*d b Khai báo  Trong PASCAL: Const ElemNo = ; Type InfoType = ; KeyType = ; Element = record key : KeyType; {khoá} info : InfoType; {dữ liệu} end; ListType = array[1 ElemNo] of Element; Var List: ListType; ListNum: integer; {số phần tử danh sách, không vượt ElemNo}  Trong C: #define ElemNo typedef InfoType; typedef KeyType; struct Element { KeyType key; //khoá InfoType info; // liệu }; struct Element List[ElemNo+1]; int ListNum; // số phần tử danh sách, không vượt ElemNo Chương II Cấu trúc liệu danh sách II.5 Trần Quốc Chiến Cấu trúc liệu giải thuật Các phép toán a Khởi tạo danh sách Ban đầu danh sách rỗng, nên ta khởi tạo đặt độ dài danh sách ListNum = Trong PASCAL procedure Initialize; begin ListNum := 0; end; Trong C void Initialize() { ListNum = 0; } b Duyệt danh sách Duyệt danh sách thoả mãn để Trong PASCAL procedure Traverse; var i: integer; {biến cục bộ} begin for i := to ListNum if then end; Trong C void Traverse() { int i; //biến cục for ( i = 1; i next2 = p; p->next2 = q; return p; Chương II Cấu trúc liệu danh sách II.22 Trần Quốc Chiến Cấu trúc liệu giải thuật } d Loại phần tử khỏi danh sách Xét danh sách đa liên kết có hai vùng liên kết next1 next2 xếp theo thứ tự tăng dần theo info1 info2 ghi kiểu InfoType Giả sử ta cần loại bỏ phần tử có nội dung DelInfo Thủ tục Delete_Element cài đặt thuật toán xoá phần tử khỏi danh sách  Trong PASCAL: Procedure Delete_Element(DelInfo : InfoType); var q , {* phần tử phụ trợ dò tìm *} q1 , {* phần tử tìm thấy theo next1 *} before {* phần tử đứng trước q *} : NodePointer; begin q := plist1; { dò tìm theo vùng next1 } while (q nil) and (q^.info DelInfo) if q^.info.info1 > DelInfo.info1 then q := nil else begin before := q; q := q^.next1 end; if q nil then { tìm thấy phần tử cần loại bỏ } begin q1 := q; { ngắt next1 } if q = plist1 then plist1 := q^.next1 else before^.next1 := q^.next1; { dò tìm theo vùng next2 } q := plist2; while q q1 begin before := q; q := q^.next2 end; if q = plist2 then plist2 := q^.next2 else before^.next2 := q^.next2; Chương II Cấu trúc liệu danh sách II.23 Trần Quốc Chiến Cấu trúc liệu giải thuật end; dispose(q) end;  Trong C: void Delete_Element(InfoType DelInfo) { NodePointer q , /* phần tử phụ trợ dò tìm */ q1 , /* phần tử tìm thấy theo next1 */ before; /* phần tử đứng trước q */ q = plist1; // dò tìm theo vùng next1 while ((q != NULL) && (q->info != DelInfo)) if (q->info.info1 > DelInfo.info1) q = NULL; else { before = q; q = q->next1; } if (q != NULL) // tìm thấy phần tử cần loại bỏ { q1 = q; // ngắt next1 if (q == plist1) plist1 = q->next1; else before->next1 = q->next1; //dò tìm theo vùng next2 q = plist2; while (q != q1) { before = q; q = q->next2; } if (q == plist2) plist2 = q->next2; else before->next2 = q->next2; } free(q); } Chương II Cấu trúc liệu danh sách II.24 Trần Quốc Chiến Cấu trúc liệu giải thuật V DANH SÁCH LIÊN KẾT KÉP Định nghĩa Danh sách liên kết kép (doubly linked list) danh sách mà phần tử có hai vùng liên kết Một vùng liên kết đến phần tử đứng trước nó, gọi liên kết ngược (previous) vùng liên kết đến phần tử đứng sau nó, gọi liên kết thuận (next)  Ví dụ Danh sách thêm vào lấy hai đầu Tổ chức danh sách liên kết kép Mỗi phần tử danh sách liên kết kép bao gồm vùng thông tin info vùng liên kết previous next ứng với vùng liên kết ta có điểm đầu first điểm cuối last Phần tử danh sách liên kết kép có dạng: previous info next Tổ chức danh sách liên kết kép sau: first         last Chương II Cấu trúc liệu danh sách II.25 Trần Quốc Chiến Cấu trúc liệu giải thuật  Khai báo Trong PASCAL Trong C Type InfoType = record typedef struct data Info1 : ; { … info1; Info2 : ; … info2; … end; } InfoType; NodePointer = ^Node; struct Node { Node = record InfoType info; info : InfoType; struct Node *previous; previous : NodePointer; struct Node *next; next : NodePointer; }; end; typedef struct Node *NodePointer; Var first, last : NodePointer;{ trỏ đầu NodePointer first, last, … ;// trỏ đầu trỏ cuối danh sách} trỏ cuối danh sách Các phép toán a Khởi tạo: danh sách rỗng Trong PASCAL procedure Initialize; begin first := nil; last := nil; end; Trong C void Initialize() { first = NULL; last = NULL; } b Duyệt danh sách Duyệt danh sách theo liên kết thuận theo liên kết ngược, giải thuật giống giải thuật duyệt danh sách liên kết đơn c Chèn phần tử vào danh sách: Giả sử ta chèn phần tử có nội dung NewInfo  Trường hợp thêm phần tử vào đầu danh sách Hàm Insert_First trả địa phần tử thêm vào Chương II Cấu trúc liệu danh sách II.26 Trần Quốc Chiến Trong PASCAL Cấu trúc liệu giải thuật Trong C function Insert_First(NewInfo: InfoType): NodePointer Insert_First(InfoType NodePointer; NewInfo) var p {*phần tử *}: NodePointer; { begin NodePointer p ;//phần tử new(p); p = (NodePointer)malloc(sizeof(struct p^.info := NewInfo;{* ghi liệu vào Node)); phần tử p *} p->info = NewInfo;// ghi liệu vào p^.previous := nil; phần tử p p^.next := first; p->previous = NULL; if first nil then p->next = first; first^.previous := p; if (first != NULL) first := p; first->previous = p; if last = nil then first = p; last := p; if (last = NULL) Insert_First := p last = p; end; return p; }  Trường hợp thêm phần tử vào sau phần tử q Hàm Insert_Element trả địa phần tử thêm vào Trong PASCAL Trong C function Insert_Element(NewInfo: NodePointer Insert_Element(InfoType InfoType; q: NodePointer): NodePointer; NewInfo, NodePointer q) Var p, {*phần tử *} r :{ NodePointer; NodePointer p , /*phần tử */ r; begin p = (NodePointer)malloc(sizeof(struct new(p); Node)); p^.info := NewInfo;{* ghi liệu vào p->info = NewInfo;// ghi liệu vào phần tử p *} phần tử p p^.next := q^.next; p->next = q->next; p^.previous := q; p->previous = q; q^.next := p; q->next = p; r := p^.next; r = p->next; if r nil then {thêm vào danh if (r != NULL) /*thêm vào danh sách} sách */ r^.previous := p r->previous = p; else {thêm vào cuối danh sách} else /*thêm vào cuối danh sách */ last := p; last = p; Insert_Element := p return p; end; } Chương II Cấu trúc liệu danh sách II.27 Trần Quốc Chiến Cấu trúc liệu giải thuật  Trường hợp thêm phần tử vào danh sách có thứ tự Hàm Insert_Element trả địa phần tử thêm vào  Trong PASCAL: function Insert_Element(NewInfo: InfoType): NodePointer; var p , {*phần tử thêm vào*} q, before : NodePointer; begin new(p); p^.info := NewInfo; {* ghi liệu vào phần tử p *} {tìm phần tử before trước phần tử p} q := first; while (q nil) and (q^.info < NewInfo) begin before := q; q := q^.next; end; if q = first then {thêm vào đầu danh sách} begin p^.next := first; p^.previous := nil; if first nil then first^.previous := p; first := p; if last = nil then last := p; end else {thêm vào sau before} begin p^.next := before^.next; p^.previous := before; before^.next := p; if q nil then {thêm vào danh sách} q^.previous := p else {thêm vào cuối danh sách} last := p; end Insert_Element := p end;  Trong C: NodePointer Insert_Element(InfoType NewInfo) { Chương II Cấu trúc liệu danh sách II.28 Trần Quốc Chiến Cấu trúc liệu giải thuật NodePointer p , /*phần tử thêm vào*/ q, before; p = (NodePointer)malloc(sizeof(struct Node)); p->info = NewInfo;// ghi liệu vào phần tử p {tìm phần tử before trước phần tử p} q = first; while ((q != NULL) && (q->info < NewInfo)) { before = q; q = q->next; } if (q == first) //thêm vào đầu danh sách { p->next = first; p->previous = NULL; if (first != NULL) first->previous = p; first = p; if (last == NULL) last = p; } else /*thêm vào sau before */ { p->next = before->next; p->previous = before; before->next = p; if (q != NULL) //thêm vào danh sách q->previous = p; else //thêm vào cuối danh sách last = p; } return p; } d Loại phần tử khỏi danh sách Giả sử ta cần loại bỏ phần tử có địa p Thủ tục Delete_Element xoá phần tử khỏi danh sách Chương II Cấu trúc liệu danh sách II.29 Trần Quốc Chiến Trong PASCAL Cấu trúc liệu giải thuật Trong C procedure Delete_Element(p : NodePointer); void Delete_Element(NodePointer p) var { before, {* phần tử đứng trước p *} NodePointer before, /* phần tử after {* phần tử đứng sau p *} đứng trước p */ : NodePointer; after ; // phần tử đứng sau p begin before = p->previous; before := p^.previous; after = p->next; after := p^.next; if (before != NULL) if before nil then before->next = p->next; before^.next := p^.next; if (after != NULL) if after nil then after->previous = p->previous; after^.previous := p^.previous; if (p == first) if p = first then first = after; first := after; if (p == last) if p = last then last = before; last := before; free(p); dispose(p) } end; e Tìm kiếm phần tử danh sách Có thể tìm theo vùng next điểm first (thứ tự tăng dần) theo vùng previous điểm last (thứ tự giảm dần) Giải thuật giống danh sách liên kết đơn Chương II Cấu trúc liệu danh sách II.30 Trần Quốc Chiến Cấu trúc liệu giải thuật VI DANH SÁCH LIÊN KẾT VỊNG Định nghĩa Danh sách liên kết vòng danh sách liên kết mà vùng liên kết phần tử cuối trỏ đến phần tử đầu Có thể biểu diễn phần tử danh sách liên kết vòng sau: first      Khai báo Trong PASCAL Trong C Type InfoType = ; InfoType info; NodePointer = ^Node; struct Node *next; Node = record }; info : InfoType; typedef struct Node *NodePointer; next : NodePointer; NodePointer first, p;// first trỏ danh end; sách Var first, p: NodePointer ;{ first trỏ p = (NodePointer)malloc(sizeof(struct danh sách} Node));//cấp phát nút động cho p Các phép toán danh sách Các phép toán duyệt, tìm kiếm, chèn, xố tương tự danh sách liên kết đơn Tuy nhiên cần ý vùng liên kết phần tử cuối trỏ đến phần tử đầu Danh sách liên kết vòng thích hợp với phép tách ghép danh sách Chương II Cấu trúc liệu danh sách II.31 Trần Quốc Chiến Cấu trúc liệu giải thuật  Thủ tục chèn phần tử vào cuối danh sách Trong PASCAL Trong C procedure Insert(NewInfo: InfoType); void Insert(InfoType NewInfo) var p, q : NodePointer; { begin NodePointer p, q; {tạo nút p} p = (NodePointer)malloc(sizeof(struct new(p); Node)); p^.info := NewInfo; p->info = NewInfo; p^.next := nil; p->next = NULL; {tìm nút cuối danh sách q} // tìm nút cuối danh sách q q := first; q = first; while (q^.next first) while (q->next != first) q := q^.next; q = q->next; q^.next := p; {liên kết nút q đến p} q->next = p;// liên kết nút q đến p; p^.next := first;{ p trở thành nút cuối p->next = first;// p trở thành nút cuối danh sách} danh sách end; }  Thủ tục loại phần tử sau phần tử q Trong PASCAL procedure Delete(q : NodePointer); var p,r : NodePointer; begin p := q^.next; if p nil then begin q^.next := p^.next; end; if p = first then begin {tìm nút cuối danh sách r} r := first; while (r^.next first) r := r^.next; first := p^.next; r^.next := first; end; dispose(p); end; Trong C void Delete(NodePointer q) { NodePointer p, r; p = q->next; if (p != NULL) { q->next = p->next; } if (p ==first) { r = first; while (r->next != first) r = r->next; first = p->next; r->next = first; } free(p); }  Ví dụ: Bài tốn Josephus Chương II Cấu trúc liệu danh sách II.32 Trần Quốc Chiến Cấu trúc liệu giải thuật Một nhóm n binh sĩ bị kẻ thù bao vây họ phải chọn người cầu cứu viện binh Việc chọn người thực sau Cho trước số nguyên s gọi bước đếm Các binh sĩ xếp thành vòng tròn đánh số 1, 2, , n người huy Đếm từ người thứ nhất, đạt đến s binh sĩ tương ứng bị loại khỏi vòng Lại bắt đầu đếm từ người tiếp theo, đạt đến s binh sĩ tương ứng bị loại khỏi vòng Q trình tiếp tục lại binh sĩ, người người điều cầu cứu viện binh Sau chương trình cài đặt giải thuật toán Trong PASCAL Type NodePointer = ^Node; Node = record info : integer; next : NodePointer; end; Var q, p, first : NodePointer; n, {số binh sĩ} s, {bước đếm} i : integer; Procedure Initialize; {*** khởi tạo ***} begin first := nil; write(„cho số binh sĩ : „); readln(n); write(„cho số bước đếm: „); readln(s); end; Procedure CreateRing; {Tạo danh sách} var p, last : NodePointer; begin {tạo nút đầu tiên} new(first); first^.info := 1; first^.next := nil; {nối tiếp n-1 phần tử } last := first; for i := to n begin new(p); p^.info := i; Chương II Cấu trúc liệu danh sách Trong C struct node { int v;/*dinh ke*/ struct node *link; }; typedef struct node *nodeptr; int n, s; nodeptr first, last; void addnode(int i); void init(void); /*** khởi tạo ***/ main() { nodeptr p1, p; int k, i; clrscr(); printf("nhap n, s = "); scanf("%d %d", &n, &s); // Tạo danh sách init(); for (k = 2; k link; p1->link = p->link; free(p); II.33 Trần Quốc Chiến Cấu trúc liệu giải thuật p^.next := nil; } last^.next := p; printf("\n người lại: %d", p1->v); last := p; } end; void addnode(int i) {kết nối phần tử cuối đến phần tử đầu} { last^.next := first; nodeptr p; end; p = (nodeptr)malloc(sizeof(struct BEGIN node)); Initialize; p->v = i; CreateRing; last->link = p; {loại dần n - binh sĩ} p->link = first; new(p); last = p; p^.next := first; } while p p^.next void init(void) begin { {di chuyển đến phần tử thứ s-1} nodeptr p; for i := to s-1 p = (nodeptr)malloc(sizeof(struct p := p^.next; node)); { loại phần tử thứ s khỏi vòng} p->v = 1; q:=p^.next; first = p; p^.next := q^.next; last = p; disposei(q) last->link = first; end; } write(„Người chọn : ‟, p^.info); END Chương II Cấu trúc liệu danh sách II.34 Trần Quốc Chiến Cấu trúc liệu giải thuật BÀI TẬP Viết chương trình nhập số nguyên n, a, b (0 < n  100, a < b , n

Ngày đăng: 29/03/2018, 21:28

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

Tài liệu liên quan