520 likes | 714 Views
Xin vui lòng yên lặng!. Danh sách liên kết (Linked List). Giới thiệu. Định nghĩa: Là danh sách bao gồm các phần tử kết nối với nhau bằng 1 hay nhiều mối liên kết. Các thao tác trên danh sách. Khởi tạo danh sách rỗng Kiểm tra danh sách rỗng?
E N D
Xin vui lòng yên lặng! Lê Mậu Long
Danh sách liên kết(Linked List) Lê Mậu Long
Giới thiệu • Định nghĩa: Là danh sách bao gồm các phần tử kết nối với nhau bằng 1 hay nhiều mối liên kết Lê Mậu Long
Các thao tác trên danh sách • Khởi tạo danh sách rỗng • Kiểm tra danh sách rỗng? • Chèn phần tử vào danh sách • Xóa phần tử trong danh sách • Tìm kiếm phần tử trong danh sách • Khởi đầu từ đầu danh sách • Lấy dữ liệu 1 phần tư • Chuyển sang phần tử kế tiếp • Hết danh sách • …. Lê Mậu Long
Danh sách liên kết đơn • Là danh sách mà mỗi phần tử có 1 mối liên kết để kết nối với phần tử kế tiếp • Cài đặt: dựa trên con trỏ, bao gồm: • 3 con trỏ: head (đầu ds), pos (phần tử hiện hành), và rear (cuối ds) • biến count: số phần tử của danh sách head pos rear Lê Mậu Long
Mô tả kiểu dữ liệu typedef struct nodet { elem data; struct nodet *next; } node; typedef node *nodeptr; data next Lê Mậu Long
head pos rear typedef struct { nodeptr head, pos, rear; int count; } list; Lê Mậu Long
Khởi tạo danh sách rỗng Gán • head, pos và rear = NULL • count = 0 // Hàm khởi tạo void createlist(list &l) { l.head = l.pos = l.rear = NULL; l.count = 0; } Lê Mậu Long
Kiểm tra danh sách rỗng? • Kiểm tra số phần tử = 0 int emptylist(list l) { return l.count == 0; } Lê Mậu Long
head pos rear Chèn phần tử x vào danh sách – cục bộ (local) • Cấp phát bộ nhớ cho newp và gán dữ liệu • Chèn ở đầu ds (p==NULL) newp->next = head; head = newp; newp Lê Mậu Long
Chèn sau phần tử p (p!=NULL) newp->next = p->next; p->next = newp; head pos p rear newp Lê Mậu Long
Trường hợp chèn cuối (newpnext == NULL) • Thay đổi rear rear = newp; head pos p rear newp Lê Mậu Long
void insertlist(list &l, elem &x, nodeptr p) { nodeptr newp = new node; memcpy(&newp->data, &x, sizeof(elem)); if (p==NULL) { newp->next = l.head; l.head = newp; } else { newp->next = p->next; p->next = newp; } if (newp->next == NULL) l.rear = newp; l.count++; } Lê Mậu Long
Các hàm chèn phần tử – toàn cục (global) • Chèn đầu danh sách void inserthead(list &l, elem &x) { insertlist(l, x, NULL); } • Chèn vị trí hiện hành void insertpos(list &l, elem &x) { insertlist(l, x, l.pos); } • Chèn cuối danh sách void insertrear(list &l, elem &x) { insertlist(l, x, l.rear); } Lê Mậu Long
t head p t rear rear head Xoá phần tử trong danh sách – cục bộ • Xoá phần tử đầu danh sách (p=NULL) t = head; head = t->next; • Xoá phần tử sau p (p!=NULL) t = p->next; p->next = t->next; p Lê Mậu Long
void deletelist(list &l, nodeptr p) { nodeptr t; if (p==NULL) { t = l.head; l.head = t->next; } else { t = p->next; p->next = t->next; } if (t->next == NULL) l.rear = p; delete t; l.count--; } Lê Mậu Long
Các hàm xóa phần tử – toàn cục • Xóa phần tử đầu danh sách void deletehead(list &l) { deletelist(l, NULL); } • Xóa phần tử tại vị trí hiện hành void deletepos(list &l) { deletelist(l, l.pos); } Lê Mậu Long
head pos c rear 1 8 2 5 4 3 Tìm kiếm trên DS X=5 • Khởi đầu từ đầu danh sách (pos = NULL; c = head) • Khi chưa hết ds và chưa tìm thấy Chuyển sang phần tử kế tiếp (pos = c; c = cnext) Lê Mậu Long
Tìm kiếm trên DS – bản nháp int searchlist(list &l, elem x) { nodeptr c = l.head; l.pos = NULL; while (c!=NULL && x!=c->data) { l.pos = c; c = c->next; } return c!=NULL; } Lê Mậu Long
Tìm kiếm trên DS – viết lại int searchlist(list &l, elem x, int (*comp)(elem, elem)) { nodeptr c = l.head; l.pos = NULL; while (c!=NULL && comp(x, c->data)!=0) { l.pos = c; c = c->next; } return c!=NULL; } Lê Mậu Long
Tìm kiếm trên DS có thứ tự int searchorderlist(list &l, elem x, int (*comp)(elem, elem)) { nodeptr c = l.head; l.pos = NULL; while (c!=NULL && comp(x, c->data)>0) { l.pos = c; c = c->next; } if (c!=NULL && comp(x, c->data)<0) return 0; return c!=NULL; } Lê Mậu Long
int searchorderlist(list &l, elem x, int (*comp)(elem, elem)) { nodeptr c = l.head; l.pos = NULL; while (c!=NULL && comp(x, c->data)>0) { l.pos = c; c = c->next; } if (c!=NULL && comp(x, c->data)<0) return 0; return c!=NULL; } // Hàm so sánh trên khoá int ss(int x, int y) { return x-y; } //Đoạn chương trinh nhập dãy createlist(l); cout<<"\nNhap day:"; do { cin>>x; if (x>0) { searchorderlist(l, x, ss); insertpos(l, x); } } while (x>0); Ví dụ Lê Mậu Long
Khởi đầu từ đầu danh sách void start(list &l) { l.pos = l.head; } • Chuyển sang phần tử kế tiếp void skip(list &l) { if (l.pos == NULL) l.pos = l.head; else l.pos = l.pos->next; } Lê Mậu Long
Kiểm tra hết danh sách int eol(list l) { return l.pos == NULL; } • Lấy dữ liệu 1 phần tử void getdata(list l, elem &x) { memcpy(&x, &l.pos->data, sizeof(elem)); } • Số phần tử trong danh sách int nolist(list l) { return l.count; } Lê Mậu Long
1 0 0 1 1 Ngăn xếp (Stack) • Là cấu trúc bao gồm các phần tử được truy xuất theo nguyên tắc “vào sau, ra trước” (Last In, First Out – LIFO) Ví dụ: Chồng đĩa, đổi số ra nhị phân 19 1 9 1 4 0 2 0 1 1 Lê Mậu Long
Các thao tác trên Stack 4 thao tác cơ bản trên stack • Khởi tạo stack rỗng: CreateStack(s) • Kiểm tra stack rỗng: EmptyStack(s) • Đưa phần tủ vào Stack: Push(s, x) • Lấy phần tủ ra khỏi Stack:Pop (s, x) Lê Mậu Long
Sử dụng Mảng e[Max] phần tử kiểu elem (elementtype) Chỉ số top để chỉ đỉnh stack (nơi đưa vào, lấy ra) Tạo tập tin Stack.cpp: typedef struct { elem e[Max]; int top; } stack; 0 1 1 Cài đặt trên cơ sở mảng Max-1 top e Lê Mậu Long
Các thao tác trên Stack • Khởi tạo stack s rỗng void createstack(stack &s) { s.top = -1; } • Kiểm tra stack s rỗng? int emptystack(stack s) { return s.top==-1; } Lê Mậu Long
Đưa phần tử x vào stack s void push(stack &s, elem &x) { if (s.top==Max-1) exit(0); memcpy(&s.e[++s.top], &x, sizeof(elem)); } • Lấy phần tử x ra khỏi stack s void pop(stack &s, elem &x) { if (s.top==-1) exit(0); memcpy(&x, &s.e[s.top--], sizeof(elem)); } Lê Mậu Long
#define Max 32 #include <iostream.h> typedef int elem; #include "stack.cpp" void main() { int i, n; stack s; cout<<"\nNhap so can doi:"; cin>>n; createstack(s); while (n>0) { i = n%2; push(s, i); n = n/2; } cout<<"Ket qua dang nhi phan :"; while (!emptystack(s)) { pop(s, i); cout<<i; } } Ví dụ: Đổi số ra nhị phân Lê Mậu Long
Đệ qui và tổ chức đệ qui Lê Mậu Long
Định nghĩa • Một định nghĩa được gọi là đệ qui nếu nó được định nghĩa trên chính nó một cách trực tiếp hay gián tiếp • Đệ qui luôn gồm 2 phần • Phần dừng • Phần đệ qui Lê Mậu Long
Ví dụ Lê Mậu Long
Giai thừa long gt(int n) { if (n==0) return 1; return n*gt(n-1); } void main() { cout<<gt(5); } Lê Mậu Long
Khử bỏ đệ qui • Sử dụng Stack • Đệ qui được thay bằng: • Hàm đệ qui: Vòng lặp • Lời gọi đệ qui: Push các giá trị cục bộ • Thực hiện đệ qui: Pop các giá trị cục bộ • Lưu ý: Stack là cấu trúc LIFO Lê Mậu Long
Bài toán Tháp Hanoi #include <iostream.h> void chuyen(int n, char A, char B, char C) { if (n==1) cout<<"\nChuyen "<<A<<" qua "<<C; else { chuyen(n-1, A, C, B); chuyen(1, A, ' ', C); chuyen(n-1, B, A, C); } } void main() { cout<<"\n============ De qui ==============="; chuyen(3, 'a', 'b', 'c'); } Lê Mậu Long
Bài toán Tháp Hanoi không đệ qui • Khởi tạo stack s rỗng • Push 1 bộ (3, ‘A’, ‘B’, ‘C’) vào s • Lặp • Pop ra khỏi s 1 bộ (n, A, B, C); • Nếu n=1 thì • cout<<"\nChuyen "<<A<<" qua "<<C; • Ngược lại • Push 1 bộ (n-1, B, A, C) vào s • Push 1 bộ (1, A, ‘ ‘, C) vào s • Push 1 bộ (n-1, A, C, B) vào s • Cho đến khi s rỗng Lê Mậu Long
Cài đặt trên cơ sở con trỏ • Cài đặt tương tự như danh sách liên kết đơn với 2 thao tác • Chèn đầu danh sách • Lấy ra ở đầu danh sách push s pop Lê Mậu Long
Tạo tập tin Stack.cpp: typedef struct nodet { elem data; struct nodet *next; } node; typedef node *stack; void createstack(stack &s) { s = NULL; } Lê Mậu Long
newp int emptystack(stack s) { return s==NULL; } void push(stack &s, elem &x) { stack newp = new node; memcpy(&newp->data, &x, sizeof(elem)); newp->next = s; s = newp; } s Lê Mậu Long
t s void pop(stack &s, elem &x) { stack t = s; if (s==NULL) exit(0); memcpy(&x, &s->data, sizeof(elem)); s = s->next; delete t; } Chạy lại chương trình đổi nhị phân, nhận xét? Lê Mậu Long
Hàng đợi (Queue) • Là cấu trúc bao gồm các phần tử được truy xuất theo nguyên tắc “vào trước, ra trước” (First In, First Out – FIFO) Ví dụ: Các vùng đệm giao tiếp giữa máy tính và các thiết bị Lê Mậu Long
Các thao tác trên Queue 4 thao tác cơ bản trên queue • Khởi tạo queue rỗng: CreateQueue(q) • Kiểm tra queue rỗng: EmptyQueue(q) • Đưa phần tủ vào queue : AddQueue(q, x) • Lấy phần tủ ra khỏi queue : RemoveQueue(q, x) Lê Mậu Long
Cài đặt trên cơ sở mảng • Sử dụng • Mảng e[Max] phần tử kiểu elem (elementtype) • Chỉ số • front để chỉ đầu hàng đợi (nơi lấy ra) • rear để chỉ cuối hàng đợi (nơi đưa vào) Hai chỉ số front và rear tăng xoay vòng • Tạo tập tin Queue.cpp: typedef struct { elem e[Max]; int front, rear; } queue; Lê Mậu Long
Các thao tác trên Queue • Khởi tạo queue q rỗng void createqueue(queue &q) { q.front = q.rear = 0; } • Kiểm tra queue q rỗng? int emptyqueue(queue q) { return q.front == q.rear; } Lê Mậu Long
Đưa phần tử x vào queue q void addqueue(queue &q, elem &x) { int nr = (q.rear + 1) % Max; if (nr == q.front) exit(0); memcpy(&q.e[q.rear], &x, sizeof(elem)); q.rear = nr; } • Lấy phần tử x ra khỏi queue q void removequeue(queue &q, elem &x) { if (q.front == q.rear) exit(0); memcpy(&x, &q.e[q.front], sizeof(elem)); q.front = (q.front + 1) % Max; } Lê Mậu Long
Ví dụ: Radix sort • Sắp xếp dãy số nguyên dương tăng dần 71, 32, 53, 70, 50 , 63, 84, 15, 26, 19, 8, 37, 17, 46, 98, 21 8, 15, 17, 19, 21, 26, 32, 37, 46, 50, 53, 63, 70, 71, 84, 98 0 3 4 5 6 7 8 1 2 9 21 63 46 17 98 50 70 84 15 8 71 32 53 26 37 19 19 53 71 17 26 37 46 84 98 8 15 21 32 50 63 70 Lê Mậu Long
Cài đặt trên cơ sở con trỏ • Cài đặt tương tự như danh sách liên kết đơn với 2 thao tác • Chèn cuối danh sách • Lấy ra ở đầu danh sách rear front remove add Lê Mậu Long
Tạo tập tin Queue.cpp: typedef struct nodet { elem data; struct nodet *next; } node; typedef node *nodeptr; typedef struct { nodeptr front, rear; } queue; void createqueue(queue &q) { q.front = NULL; } Lê Mậu Long
newp int emptyqueue(queue q) { return q.front == NULL; } void addqueue(queue &q, elem &x) { nodeptr newp = new node; memcpy(&newp->data, &x, sizeof(elem)); newp->next = NULL; if (q.front == NULL) q.front = newp; else q.rear->next = newp; q.rear = newp; } rear front Lê Mậu Long