Danh sách liên kết (Linked List)... Lê Mậu Long 6.[r]
(1)Lê Mậu Long
(2)Lê Mậu Long
(3)Lê Mậu Long
Giới thiệu
• Định nghĩa: Là danh sách bao gồm các
(4)Lê Mậu Long
Các thao tác 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ử danh sách
• Tìm kiếm phần tử danh sách • Khởi đầu từ đầu danh sách
• Lấy dữ liệu phần tư
• Chuyển sang phần tử kế tiếp • Hết danh sách
(5)Lê Mậu Long
Danh sách liên kết đơn
• Là danh sách mà mỡi phần tử có mối liên kết để kết nối với phần tử kế tiếp
• Cài đặt: dựa trỏ, bao gờm:
• 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
(6)Lê Mậu Long
Mô tả kiểu dữ liệu
typedef struct nodet {
elem data;
struct nodet *next; } node;
(7)Lê Mậu Long
typedef struct {
nodeptr head, pos, rear; int count;
} list;
(8)Lê Mậu Long Khởi tạo danh sách rỗng
Gán
– head, pos và rear = NULL – count =
// Hàm khởi tạo
void createlist(list &l) {
l.head = l.pos = l.rear = NULL; l.count = 0;
(9)Lê Mậu Long Kiểm tra danh sách rỡng?
• Kiểm tra sớ phần tử = 0
int emptylist(list l) {
(10)Lê Mậu Long 10 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;
head pos rear
(11)Lê Mậu Long 11
• Chèn sau phần tử p (p!=NULL)
newp->next = p->next; p->next = newp;
head pos p rear
(12)Lê Mậu Long 12
• Trường hợp chèn ći (newpnext == NULL)
• Thay đởi rear
rear = newp;
head pos p rear
(13)Lê Mậu Long 13
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;
(14)Lê Mậu Long 14
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 ći danh sách
void insertrear(list &l, elem &x) {
(15)Lê Mậu Long 15 Xoá phần tử 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
head p t rear
head rear
(16)Lê Mậu Long 16 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;
(17)Lê Mậu Long 17
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)
{
(18)Lê Mậu Long 18
Tìm kiếm DS
X=5
1. Khởi đầu từ đầu danh sách (pos = NULL; c = head) 2. 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)
head pos c rear
(19)Lê Mậu Long 19
Tìm kiếm 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; }
(20)Lê Mậu Long 20
Tìm kiếm 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; }
(21)Lê Mậu Long 21
Tìm kiếm 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;
(22)Lê Mậu Long 22
Ví du 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 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);
}
(23)Lê Mậu Long 23 • 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
(24)Lê Mậu Long 24
• Kiểm tra hết danh sách int eol(list l)
{
return l.pos == NULL; }
• Lấy dữ liệu phần tử
void getdata(list l, elem &x) {
memcpy(&x, &l.pos->data, sizeof(elem)); }
• Sớ phần tử danh sách int nolist(list l)
{
(25)Lê Mậu Long 25
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, trước” (Last In, First Out – LIFO)
Ví dụ: Chồng đĩa, đổi số nhị phân
(26)Lê Mậu Long 26
Các thao tác Stack
4 thao tác bả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)
(27)Lê Mậu Long 27
Cài đặt sở mảng
• 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;
1 1 0
top
e
(28)Lê Mậu Long 28
Các thao tác 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) {
(29)Lê Mậu Long 29 • Đư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 khỏi stack s void pop(stack &s, elem &x)
{
if (s.top==-1) exit(0);
(30)Lê Mậu Long 30
Ví dụ: Đổi số nhị phân
#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; }
(31)Lê Mậu Long 31
(32)Lê Mậu Long 32
Định nghĩa
• Một định nghĩa gọi là đệ qui nếu nó được định nghĩa chính nó cách trực tiếp hay gián tiếp
• Đệ qui ln gờm phần
(33)Lê Mậu Long 33 Ví du 0 )! ( ! n n n n n 0 0 . 1 n n x x
xn n
(34)Lê Mậu Long 34
Giai thừa
long gt(int n) {
if (n==0) return 1; return n*gt(n-1); }
void main() {
(35)Lê Mậu Long 35
Khử bỏ đệ qui
• Sử dung Stack
• Đệ qui thay bằng:
– Hàm đệ qui: Vòng lặp
– Lời gọi đệ qui: Push các giá trị cuc – Thực hiện đệ qui: Pop các giá trị cuc
(36)Lê Mậu Long 36
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');
(37)Lê Mậu Long 37
Bài toán Tháp Hanoi không đệ qui
1 Khởi tạo stack s rỗng
2 Push (3, ‘A’, ‘B’, ‘C’) vào s 3 Lặp
– Pop khỏi s (n, A, B, C); – Nếu n=1
• cout<<"\nChuyen "<<A<<" qua "<<C;
– Ngược lại
• Push (n-1, B, A, C) vào s • Push (1, A, ‘ ‘, C) vào s • Push (n-1, A, C, B) vào s
(38)Lê Mậu Long 38
Cài đặt sở trỏ
• Cài đặt tương tư danh sách liên kết đơn với thao tác
– Chèn đầu danh sách
– Lấy ở đầu danh sách
s
(39)Lê Mậu Long 39 • Tạo tập tin Stack.cpp:
typedef struct nodet { elem data;
struct nodet *next; } node;
typedef node *stack;
void createstack(stack &s) {
(40)Lê Mậu Long 40
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; }
newp
(41)Lê Mậu Long 41 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?
s
(42)Lê Mậu Long 42
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, trước” (First In, First Out – FIFO)
(43)Lê Mậu Long 43
Các thao tác Queue
4 thao tác bả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)
(44)Lê Mậu Long 44 Cài đặt 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:
(45)Lê Mậu Long 45
Các thao tác 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) {
(46)Lê Mậu Long 46
• Đư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 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;
(47)Lê Mậu Long 47
Ví du: Radix sort
• Sắp xếp dãy sớ ngun 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
70 50 71 21 32 53 63 84
0
(48)Lê Mậu Long 48
Cài đặt sở trỏ
• Cài đặt tương tư danh sách liên kết đơn với thao tác
– Chèn cuối danh sách – Lấy ở đầu danh sách
front
remove add
(49)Lê Mậu Long 49 • 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) {
(50)Lê Mậu Long 50
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;
}
newp
(51)Lê Mậu Long 51
void removequeue(queue &q, elem &x) {
nodeptr t = q.front;
if (q.front == NULL) exit(0); q.front = t->next;
memcpy(&x, &t->data, sizeof(elem)); delete t;
}
front
(52)Lê Mậu Long 52