CHUONG 4 - Danh Sach Lien Ket - 2015

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 33

30/03/2015

CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT

GV : ThS. Trần Văn Thọ


E-mail : tvtho2000@yahoo.com

Môn: CẤU TRÚC DỮ LIỆU VÀ GIẢI THUẬT

CHƯƠNG IV: DANH SÁCH LIÊN KẾT

MỤC TIÊU

 Tìm hiểu các loại CTDL danh sách liên kết.


 Tìm hiểu những thao tác trên danh sách liên kết
đơn. Từ đó ứng dụng vào một số bài toán cụ thể.
 Tìm hiểu những thao tác trên danh sách liên kết
đôi. Từ đó ứng dụng vào một số bài toán cụ thể.
 Tìm hiểu những thao tác trên danh sách liên kết
vòng. Từ đó ứng dụng vào một số bài toán cụ thể.

ThS. Trần Văn Thọ 3

1
30/03/2015

Nội dung

Danh sách liên kết đơn: Giới thiệu, Minh họa


và Cài đặt các thao tác, Ứng dụng.
Danh sách liên kết đôi: Giới thiệu, Minh họa và
Cài đặt các thao tác, Ứng dụng.
Danh sách liên kết vòng: Giới thiệu, Minh họa
và Cài đặt các thao tác, Ứng dụng.

ThS. Trần Văn Thọ 4

ThS. Trần Văn Thọ 5

Giới thiệu
Mảng 1 chiều
 Có kích thước cố định (cấp phát tĩnh)
 Thêm/ xóa có độ phức tạp cao
 Các phần tử tuần tự theo chỉ số 0  n-1
 Truy cập ngẫu nhiên

chèn

0 1 2 3 4 n-2 n-1
ThS. Trần Văn Thọ 6

2
30/03/2015

Giới thiệu
Danh sách liên kết
 Cấp phát động lúc chạy chương trình
 Các phần tử nằm rải rác ở nhiều nơi trong bộ
nhớ
 Kích thước danh sách chỉ bị giới hạn do RAM
 Thao tác thêm/xóa đơn giản
Insert,
Delete

ThS. Trần Văn Thọ 7

Con trỏ: Pointer


Địa chỉ

1FF0 1FF4
int i, *pi; i ? pi ?

1FF4
pi = &i; i 1FF0
*pi ? pi 1FF0

i = 10 hoặc i 1FF0 1FF4


*pi 10
? pi 1FF0
*pi = 10

ThS. Trần Văn Thọ 8

Định nghĩa
Danh sách liên kết đơn là chuỗi các phần tử
(Node), được tổ chức theo thứ tự tuyến tính. Mỗi
phần tử liên kết với 1 phần tử đứng liền kế sau trong
danh sách.

Mỗi phần tử (Node) gồm 2 thành phần:


 Thành phần dữ liệu (Data): Lưu trữ thông tin về
bản thân phần tử (Information). Data link
 Thành phần liên kết (Link): Lưu địa chỉ phần tử
đứng kế sau (Next) trong danh sách, hoặc lưu trữ
giá trị NULL nếu là phần tử cuối danh sách.
ThS. Trần Văn Thọ 9

3
30/03/2015

Minh Họa
Mô tả danh sách

Data Link

A0 A1 A2 An-1
null

Head Node Node Tail Node

ThS. Trần Văn Thọ 10

Minh Họa

Ví dụ:
Địa chỉ

700 500
‘D’ 500 ‘S’ 600

Head 600 300


‘L’ 300 ‘Q’ null

Tail

ThS. Trần Văn Thọ 11

Khai báo phần tử của danh sách


Khai báo cấu trúc một nút (Node):
typedef struct tagSNode
{
Data Info; Next
Info
tagSNode *Next;
}SNode;
Trong đó Data:
 Là kiểu dữ liệu định nghĩa trước.
 Chứa thông tin (hay dữ liệu) của từng Node.
Data có thể là: int, long, float, SV, NV,….
ThS. Trần Văn Thọ 12

4
30/03/2015

Khai báo phần tử của danh sách


typedef struct tagSNode
{
Data Info; Cấu trúc
tagSNode *Next; SNode
}SNode;

typedef struct tagSNode typedef struct tagSNode


{ {
int Info; SinhVien Info;
tagSNode *Next; tagSNode *Next;
}SNode; }SNode;

ThS. Trần Văn Thọ 13

Khai báo phần tử của danh sách


typedef int Data;
typedef struct tagSNode
{
Data Info;
tagSNode *Next;
}SNode;
typedef SNode* SNodePtr; Khai báo kiểu con trỏ SNode

ThS. Trần Văn Thọ 14

Khai báo cấu trúc dữ liệu DSLK đơn

typedef struct tagSList


{

SNode* Head; // Lưu địa chỉ SNode đầu tiên trong List
SNode* Tail; // Lưu địa chỉ của SNode cuối cùng trong List

}SList; // Tạo mới kiểu danh sách liên kết đơn

ThS. Trần Văn Thọ 15

5
30/03/2015

Ví dụ tổ chức DSLK đơn trong bộ nhớ

Head Tail

3f 4f 5f
4 4f 7 5f 6 NULL

Trong ví dụ trên thành phần dữ liệu là 1 số


nguyên

ThS. Trần Văn Thọ 16

Thao tác cơ bản trên DSLK đơn


 Khởi tạo một danh sách rỗng.
 Tạo một nút mới chứa khóa x.
 Thêm phần tử có khóa x vào danh sách.
 Xóa phần tử có khóa x khỏi danh sách.
 Tìm kiếm phần tử có khóa bằng với x
trong danh sách.
 Sắp xếp danh sách. Phần minh họa
sẽ dùng
 Duyệt danh sách.
Data là int

ThS. Trần Văn Thọ 17

Khởi tạo danh sách rỗng


 Địa chỉ của nút đầu tiên, và địa chỉ của
nút cuối cùng đều không có (NULL).

void InitSList(SList &sl)


{
sl.Head=NULL;
sl.Tail=NULL;
}
ThS. Trần Văn Thọ 18

6
30/03/2015

Tạo nút mới chứa giá trị x bất kỳ


Hàm trả về địa chỉ phần tử mới tạo: p
SNode* CreateSNode(Data x)
x
{
SNode* p=new SNode;
if(p==NULL) {
printf(“Không đủ bộ nhớ để cấp phát nút mới!”);
getch();
return NULL;
}
p→Info=x;
p→Next=NULL;
return p;
}
ThS. Trần Văn Thọ 19

Thao tác thêm phần tử vào danh sách


Nguyên tắc thêm: Khi thêm 1 phần tử vào
SList thì có làm cho các con trỏ Head, Tail
thay đổi?
Các vị trí cần thêm 1 phần tử vào SList:
 Thêm phần tử vào đầu SList
 Thêm phần tử vào cuối SList
 Thêm phần tử p vào sau 1 phần tử q trong
SList
ThS. Trần Văn Thọ 20

Thêm phần tử vào đầu danh sách


Giải thuật:
- Bước 1: Nếu phần tử muốn thêm p không tồn tại
thì không thực hiện.
- Bước 2: Nếu SList rỗng thì
+ Head=p;
+ Tail=p; //hoặc Tail=Head;
- Bước 3: Ngược lại
+ pNext=Head;
+ Head=p;
ThS. Trần Văn Thọ 21

7
30/03/2015

Ví dụ minh họa Thêm phần tử vào đầu DS

Head 2f 3f 4f
3 3f 4 4f 8…
9f
10 2f
NULL
p→Next=Head
Head=p
P new

Sử dụng hàm CreateSNode

ThS. Trần Văn Thọ 22

Thêm phần tử vào đầu danh sách


int InsertHead(SList &sl, SNode* p)
{
if(p==NULL) return 0;
if(sl.Head==NULL)
sl.Head=sl.Tail=p;//p là nút đầu đồng thời là nút cuối
else
{
p→Next=sl.Head; (1)
sl.Head=p; (2)
}
return 1;
}
ThS. Trần Văn Thọ 23

Thêm phần tử vào cuối danh sách


Giải thuật:
- Bước 1: Nếu phần tử muốn thêm p không tồn tại
thì không thực hiện.
- Bước 2: Nếu SList rỗng thì:
+ Head=p;
+ Tail=p;
- Bước 3: Ngược lại
+ TailNext =p;
+ Tail=p;
ThS. Trần Văn Thọ 24

8
30/03/2015

Ví dụ minh họa Thêm phần tử vào cuối DS

Tail
3f 4f 5f
4 4f 8 5f 5 NULL
8f Tail=p

Tail→Next=p 8f
6 NULL
new
P
Sử dụng hàm CreateSNode

ThS. Trần Văn Thọ 25

Thêm phần tử vào cuối danh sách


int InsertTail(SList &sl, SNode* p)
{
if(p==NULL) return 0;
if(sl.Head==NULL)
sl.Head=sl.Tail=p;//p là nút đầu đồng thời là nút cuối
else
{
sl.Tail→Next=p; (1)
sl.Tail=p; (2)
}
return 1;
}
ThS. Trần Văn Thọ 26

Thêm phần tử p vào sau q của danh sách

Giải thuật:
- Bước 1: Nếu phần tử q hoặc phần tử muốn
thêm p không tồn tại thì không thực hiện.
- Bước 2:
+ pNext =qNext;
+ qNext=p;
+ Nếu q là phần tử cuối thì: Tail=p;

ThS. Trần Văn Thọ 27

9
30/03/2015

Ví dụ minh họa Thêm p vào sau q

3f 4f q 5f
4 4f 8 5f
6f 5 ..
6f
q→Next=p
7 5f
NULL
p→Next=q→Next

P new

Sử dụng hàm CreateSNode

ThS. Trần Văn Thọ 28

Thêm phần tử p vào sau q của danh sách


int InsertAfter(SList &sl, SNode* q,
SNode* p)
{
if(q==NULL || p==NULL) return 0;
p→Next=q→Next; (1)
q→Next=p; (2)
if(sl.Tail==q)
sl.Tail=p;
return 1;
}

ThS. Trần Văn Thọ 29

Tìm kiếm phần tử có giá trị bằng x

Giải thuật:
- Bước 1: Nếu (Head==NULL) thì: trả về NULL;
- Bước 2: Gán p=Head; //địa chỉ của phần tử đầu trong SList
- Bước 3:
Lặp lại trong khi ( p!=NULL và pInfo!=x ) thì thực hiện:
p=pNext; //xét phần tử kế sau
- Bước 4: Trả về p; //nếu (p!=NULL) thì p lưu địa chỉ của
phần tử có khóa bằng x, hoặc NULL là không có phần tử
cần tìm.
ThS. Trần Văn Thọ 30

10
30/03/2015

Minh họa tìm phần tử trong DSLK

Head 1f 2f 3f 4f 5f
34 3 4 8 56
P
Tìm thấy, và
trả về địa chỉ
X = 8
của nút tìm
thấy là 4f

ThS. Trần Văn Thọ 31

Tìm kiếm phần tử có giá trị bằng x


SNode* FindSNode(SList sl, Data x)
{ //Hàm trả về con trỏ trỏ đến phần tử muốn tìm
SNode* p=sl.Head;
while(p!=NULL)
{
if(p→Info==x)
return p;
p=p→Next;
}
return NULL;
}
ThS. Trần Văn Thọ 32

Tìm kiếm phần tử có giá trị bằng x


SNode* FindSNode(SList sl, Data x)
{ //Hàm trả về con trỏ trỏ đến phần tử muốn tìm
SNode* p;
for(p=sl.Head; p!=NULL; p=p→Next)
if(p→Info==x)
return p;
return NULL;
}

ThS. Trần Văn Thọ 33

11
30/03/2015

Thao tác xóa phần tử trong danh sách


Nguyên tắc xóa:
 Phải cô lập phần tử cần xóa trước khi xóa nó.
 Khi xóa 1 phần tử trong SList thì có làm cho các
con trỏ Head, Tail thay đổi?
Các vị trí cần xóa 1 phần tử trong SList:
 Xóa phần tử đầu/cuối SList
 Xóa phần tử p sau/trước 1 phần tử q trong SList
 Xóa phần tử có giá trị x bất kỳ trong SList
 Xóa toàn bộ Slist
Giải phóng vùng nhớ của nút bằng hàm delete
ThS. Trần Văn Thọ 34

Xóa phần tử đầu của danh sách


Giải thuật:
- Bước 1: Nếu (Head==NULL) thì: không thực hiện gì cả.
- Bước 2: Khi (Head!=NULL) thì: thực hiện các công việc
sau:
+ Bước 2.1: p=Head;
+ Bước 2.2: Head=HeadNext;
+ Bước 2.3: Nếu (Head==NULL) thì: Tail=NULL;
+ Bước 2.4: Lưu lại thông tin nút bị xóa;
+ Bước 2.5: delete (p); //Hủy nút do p trỏ đến (con trỏ p)
ThS. Trần Văn Thọ 35

Ví dụ minh họa hủy nút đầu DS

Head=Head→Next
Head 1f 2f 3f 4f

7 2f 6 3f 3 4f 8 …

p=Head
P
delete p
ThS. Trần Văn Thọ 36

12
30/03/2015

Xóa phần tử đầu danh sách


int DeleteHead(SList &sl, Data &x)
{
if(sl.Head==NULL) return 0;
SNode* p=sl.Head; (1)
sl.Head=sl.Head→Next; (2)
if(sl.Head==NULL)
sl.Tail=NULL;
x=p→Info; //lưu Data của nút cần hủy
delete p; //Xóa nút p
return 1; //Xóa thành công
}

ThS. Trần Văn Thọ 37

Xóa phần tử p sau phần tử q của danh sách

Giải thuật:
- Bước 1: Nếu (q==NULL hoặc qNext==NULL) thì:
không thực hiện.
- Bước 2: Khi (q!=NULL và qNext!=NULL) thì: thực
hiện các công việc sau:
+ Bước 2.1: p=qNext;
+ Bước 2.2: qNext=pNext;
+ Bước 2.3: Nếu (p==Tail) thì : Tail=q;
+ Bước 2.4: Lưu lại thông tin nút bị xóa;

ThS. Trần Văn Thọ 38

Ví dụ minh họa hủy nút p sau nút q

p=q→Next
q p delete p
Head 1f 2f 3f 4f

7 2f 6 3f
4f 3 4f 8 …

q→Next=p→Next

ThS. Trần Văn Thọ 39

13
30/03/2015

Xóa phần tử sau q trong danh sách


int DeleteAfter(SList &sl, SNode* q,
Data &x)
{
if(q==NULL || q→Next==NULL) return 0;
SNode* p=q→Next; (1)
q→Next=p→Next; (2)
if(sl.Tail==p)
sl.Tail=q;
x=p→Info;
delete p; //Xóa nút p
return 1; //Xóa thành công
}
ThS. Trần Văn Thọ 40

Xóa phần tử có khóa x của danh sách


Giải thuật:
- Bước 1: Nếu (Head==NULL) thì: không thực hiện gì cả.
- Bước 2: Tìm phần tử p có khoá bằng x, và q là phần tử đứng
kế trước p.
- Bước 3: Nếu (p==NULL) thì: Không có nút chứa x nên không
thực hiện.
- Bước 4: //Ngược lại (p!=NULL)  nghĩa là tồn tại nút p chứa
khóa x
+ Nếu (p==Head) thì: //p là nút đầu danh sách  xóa đầu
DeleteHead(sl, x);
+ Ngược lại:
DeleteAfter(sl, q, x); //Xóa nút p chứa x kế sau nút q

ThS. Trần Văn Thọ 41

Xóa phần tử có khóa x của danh sách


int DeleteSNodeX(SList &sl, Data x) {
if(sl.Head==NULL) return 0; //Không thực hiện được
SNode* p=sl.Head;
SNode* q=NULL; //sẽ trỏ đến nút kế trước p
while((p!=NULL) && (pInfo!=x) )
{//vòng lặp tìm nút p chứa x, q là nút kế trước p
q=p;
p=pNext;
}
if(p==NULL) return 0; //không tìm thấy phần tử có khóa x  không thực hiện
if(p==sl.Head) //p có khóa bằng x là nút đầu danh sách
DeleteHead(sl, x);
else // xóa nút p có khóa x nằm kế sau nút q
DeleteAfter(sl, q, x);
return 1; //Thực hiện thành công }
ThS. Trần Văn Thọ 42

14
30/03/2015

Xóa phần tử có khóa x của danh sách


int DeleteSNodeX(SList &sl, Data x) {
if(sl.Head==NULL) return 0; //Không thực hiện được
SNode* p=FindSNode(sl, x);
if(p==NULL) return 0; //Không thực hiện được
if(p==sl.Head) {
DeleteHead(sl, x);
return 1; //Thực hiện thành công
}
SNode* q=sl.Head; //tìm nút q kế trước nút p
while(pNext!=p) q=qNext;
DeleteAfter(sl, q, x);
return 1; //Thực hiện thành công
}
ThS. Trần Văn Thọ 43

Xóa toàn bộ danh sách


Giải thuật:
- Bước 1: Nếu (Head==NULL) thì: không thực hiện gì cả.
- Bước 2: Lặp lại trong khi (danh sách còn phần tử) thì thực
hiện lần lượt những việc sau:
+ Bước 2.1: Gán p=Head;
+ Bước 2.2: Gán Head=HeadNext; //Cập nhật Head
+ Bước 2.3: Hủy con trỏ p;
- Bước 3: Gán Tail=NULL; //bảo toàn tính nhất quán khi
danh sách rỗng

ThS. Trần Văn Thọ 44

Ví dụ minh họa Hủy danh sách

Head Tail

1f 2f 3f 4f 5f

7 2f 6 3f 3 4f 8 5f 9 NULL

p p p p p

NULL

ThS. Trần Văn Thọ 45

15
30/03/2015

Xóa toàn bộ danh sách


void RemoveAllList(SList &sl)
{
while(sl.Head!=NULL) //còn phần tử trong SList
{
SNode *p=sl.Head;
sl.Head=sl.Head→Next;
delete p; //Xóa nút p
}
sl.Tail=NULL;
}
ThS. Trần Văn Thọ 46

Xử lý danh sách

void ProcessList(SList sl)


{
SNode *p=sl.Head;
while(p!=NULL)
{
ProcessSNode(p); //xử lý cụ thể tuỳ trường hợp
p=p→Next;
}
}
ThS. Trần Văn Thọ 47

Duyệt in danh sách: Cách 1

void ShowSList(SList sl)


{
SNode *p=sl.Head;
while(p!=NULL)
{
printf(“%4d”, p→Info);
p=p→Next;
}
}
ThS. Trần Văn Thọ 48

16
30/03/2015

Minh họa duyệt in danh sách


4 10 5
p 5000
NULL
4000
3000

Head 3000 5000 4000


3000 4 5000 10 4000 5 NULL

p = sl.Head;
while(p!=NULL)
{ Kết thúc
printf(“ %5d”, p→Info);
p = p→Next;
}

ThS. Trần Văn Thọ 49

Duyệt in danh sách: cách 2

void ShowSList(SList sl)


{
if(sl.Head==NULL)
{
printf(“\nDanh sach rong!”);
return;
}
printf(“\nNoi dung cua danh sach la: ”);
for(SNode* p=sl.Head; p!=NULL; p=p→Next)
printf(“%5d”, p→Info);
}
ThS. Trần Văn Thọ 50

Tìm phần tử lớn nhất

int FindMax(SList sl)


{//Hàm trả về giá trị phần tử lớn nhất
int max = sl.Head→Info;
for(SNode* p=sl.Head→Next; p!=NULL; p=p→Next)
if(max < p→Info)
max = p→Info;
return max ;
}

ThS. Trần Văn Thọ 51

17
30/03/2015

Tìm phần tử lớn nhất


int FindMax(SList sl)
{//Hàm trả về giá trị phần tử lớn nhất
int max = sl.Head→Info;
SNode* p=sl.Head→Next;
while(p!=NULL)
{
if(max < p→Info)
max = p→Info;
p=p→Next;
}
return max ;
}
ThS. Trần Văn Thọ 52

Tìm phần tử lớn nhất


Tìm địa chỉ chứa phần tử lớn nhất:
SNode* FindMaxPosition(SList sl)
{//Hàm trả về con trỏ trỏ đến phần tử lớn nhất
SNode* vitri=sl.Head;
for(SNode* p=sl.Head→Next; p!=NULL;
p=p→Next)
if(vitri→Info < p→Info)
vitri=p;
return vitri;
}
ThS. Trần Văn Thọ 53

Sắp xếp bằng InterchangeSort

void InterchangeSort(SList &sl)


{
SNode *p, *q;
for(p=sl.Head; p→Next!=NULL; p=p→Next)
for(q=p→Next; q!=NULL; q=q→Next)
if(p→Info > q→Info)
Swap(p→Info, q→Info);
}
ThS. Trần Văn Thọ 54

18
30/03/2015

Sắp xếp bằng SelectionSort


void SelectionSort(SList &sl)
{
SNode *q, *p, *min;
for(p=sl.Head; p→Next!=NULL; p=p→Next)
{
min = p;
for(q=p→Next; q!=NULL; q=q→Next)
if(min→Info > q→Info)
min = q;
Swap(min→Info, p→Info);
}
}
ThS. Trần Văn Thọ 55

Bài tập bổ sung

1. Đếm số Node có trong danh sách

2. Đếm số phần tử dương trong danh sách

3. Đếm số phần tử lớn hơn phần tử kề sau

4. Kiểm tra mọi phần tử trong danh sách có


chẵn không?

5. Kiểm tra danh sách có được sắp xếp tăng?

ThS. Trần Văn Thọ 56

Bài tập bổ sung

6. Tạo danh sách (h1, t1) chứa các phần tử


dương trong danh sách đã cho.

7. Xóa 1 phần tử có khoá là x

8. Thêm phần tử x vào danh sách đã có thứ


tự (tăng) sao cho sau khi thêm vẫn có
thứ tự (tăng).

ThS. Trần Văn Thọ 57

19
30/03/2015

Bài tập bổ sung

9. Xóa các phần tử trùng nhau trong danh


sách, chỉ giữ lại duy nhất một phần tử (*)

10. Trộn hai danh sách có thứ tự tăng thành


một danh sách cũng có thứ tự tăng. (*)

11. Chèn một phần tử có khoá x vào vị trí


pos bất kỳ trong danh sách.

ThS. Trần Văn Thọ 58

ThS. Trần Văn Thọ 59

Danh sách liên kết đôi

Cho phép di chuyển 2 chiều đến nút


trước và sau. Prev Data Next
 Liên kết nút trước là: Prev
 Liên kết nút sau là: Next
Nút đầu có con trỏ Prev là NULL
Nút cuối có con trỏ Next là NULL

A1 A2 An

ThS. Trần Văn Thọ 60

20
30/03/2015

Khai báo nút


typedef int Data;
typedef struct tagDNode
{
Data Info;
tagDNode* Prev; trỏ đến nút trước
tagDNode* Next; trỏ đến nút sau
}DNode;

typedef DNode* DNodePtr; Khai báo kiểu con trỏ DNode

ThS. Trần Văn Thọ 61

Khai báo và khởi tạo danh sách


typedef struct tagDList
{
DNode* Head; trỏ đến nút đầu
DNode* Tail; trỏ đến nút cuối
}DList; Khai báo kiểu DSLK đôi

void InitDList(DList &dl)


{
dl.Head=NULL;
dl.Tail=NULL;
}
ThS. Trần Văn Thọ 62

Các thao tác cơ bản


 Tạo nút mới
 Thêm vào đầu/ cuối
 Thêm vào trước q/ sau q
 Xóa đầu/ cuối
 Xóa sau q
 Duyệt danh sách
 Duyệt từ cuối danh sách
 Sắp xếp danh sách

ThS. Trần Văn Thọ 63

21
30/03/2015

Tạo nút mới


DNode* CreateDNode(Data x) p
{ NULL x NULL
DNode* p=new DNode;
if(p==NULL) Prev Info Next
{
printf(“Không đủ bộ nhớ để cấp phát nút mới!”);
getch();
return NULL;
}
p→Info=x;
p→Prev=p→Next=NULL;
return p;
}
ThS. Trần Văn Thọ 64

Thêm 1 nút vào đầu danh sách

Head
A B C D NULL

NULL
(2) (3)
(4)
X NULL
Tail
p (1)

NULL

Minh họa thêm 1 phần tử vào đầu danh sách


ThS. Trần Văn Thọ 65

Thêm 1 nút vào đầu danh sách


int InsertHead(DList &dl, DNode* p)
{
if(p==NULL) return 0;
if(dl.Head==NULL)
dl.Head=dl.Tail=p;
else
{
p→Next=dl.Head;
dl.Head→Prev=p;
dl.Head=p;
}
return 1;
}
ThS. Trần Văn Thọ 66

22
30/03/2015

Thêm 1 nút vào cuối danh sách

Minh họa thêm 1 phần tử vào cuối danh sách

Tail
Head
(4)

A B C D NULL

(2)

(3) X NULL
NULL
p (1)

NULL

ThS. Trần Văn Thọ 67

Thêm 1 nút vào cuối danh sách


int InsertTail(DList &dl, DNode* p)
{
if(p==NULL) return 0;
if(dl.Head==NULL)
dl.Head=dl.Tail=p;
else
{
dl.Tail→Next=p;
p→Prev=dl.Tail;
dl.Tail=p;
}
return 1;
}
ThS. Trần Văn Thọ 68

Thêm 1 nút p trước nút q (q ≠ )


Minh hoạ thêm 1 nút p vào trước nút q

Tail
Head
r (1) q
A B C D NULL

(6) (5)
(4) (3)
NULL X NULL

NULL p (2)

ThS. Trần Văn Thọ 69

23
30/03/2015

Thêm 1 nút p trước nút q (q ≠ )


int InsertBefore(DList &dl, DNode* q, DNode* p)
{//Chèn p vào trước q
if(q==NULL || p==NULL) return 0;
DNode* r=q→Prev;
p→Next=q;
p→Prev=r;
q→Prev=p;
if(r!=NULL)
r→Next=p;
else //r==NULL hay q==dl.Head
dl.Head=p;
return 1;
}
ThS. Trần Văn Thọ 70

Thêm 1 nút p vào sau q (q ≠ )


Minh hoạ thêm 1 nút p vào sau nút q

Head q (1) r Tail

A B C D NULL

(6)
(5)
(4) (3)

NULL X NULL

NULL p (2)

ThS. Trần Văn Thọ 71

Thêm 1 nút p vào sau q (q ≠ )


int InsertAfter(DList &dl, DNode* q, DNode* p)
{//Chèn p vào sau q
if(q==NULL || p==NULL) return 0;
DNode* r=q→Next;
p→Next=r;
p→Prev=q;
q→Next=p;
if(r!=NULL)
r→Prev=p;
else //r==NULL hay q==dl.Tail
dl.Tail=p;
return 1;
}
ThS. Trần Văn Thọ 72

24
30/03/2015

Tìm kiếm một nút có giá trị x

DNode* FindDNode(DList dl, Data x)


{
DNode* p=dl.Head;
while(p!=NULL)
{
if(p→Info==x)
return p; //tìm thấy
p=p→Next;
}
return NULL; //không tìm thấy
}
ThS. Trần Văn Thọ 73

Xóa 1 nút đầu danh sách


Minh hoạ xóa 1 nút đầu danh sách
(2)
Head=Head→Next
Head Tail

A B C D NULL

Head→Prev = NULL
p=Head (3)
NULL P (1)

delete p
(4)

ThS. Trần Văn Thọ 74

Xóa 1 nút ở đầu danh sách


int DeleteHead(DList &dl, Data &x)
{
if(dl.Head==NULL) return 0;
DNode* p=dl.Head;
dl.Head=dl.Head→Next;
if(dl.Head==NULL)
dl.Tail=NULL;
else
dl.Head→Prev=NULL;
x=p→Info; //lưu Data của nút bị hủy
delete p;
return 1;
}
ThS. Trần Văn Thọ 75

25
30/03/2015

Xóa 1 nút cuối danh sách

(2)
Tail=Tail→Prev
Head Tail

A B C D NULL

Tail→Next = NULL p=Tail


(3) (1)
NULL P
delete p
(4)

ThS. Trần Văn Thọ 76

Xóa 1 nút ở cuối danh sách


int DeleteTail(DList &dl, Data &x)
{
if(dl.Tail==NULL) return 0;
DNode* p=dl.Tail;
dl.Tail=dl.Tail→Prev;
if(dl.Tail==NULL)
dl.Head=NULL;
else
dl.Tail→Next=NULL;
x=p→Info; //lưu Data của nút cần hủy
delete p;
return 1;
}
ThS. Trần Văn Thọ 77

Minh họa xóa nút p sau nút q (qTail)

(1) (2)
p=q→Next r=p→Next
Head
q p r

A B C D NULL

q→Next=r r→Prev=q
(3) (4)
Tail
NULL delete p
(5)

ThS. Trần Văn Thọ 78

26
30/03/2015

Xóa 1 nút p sau nút q (qTail)


int DeleteAfter(DList &dl, DNode* q, Data &x)
{//Xóa nút p sau nút q
if(q==NULL || q==dl.Tail) return 0;
DNode* p=q→Next;
DNode* r=p→Next;
q→Next=r;
if(r==NULL) dl.Tail=q;
else r→Prev=q;
x=p→Info; //Lấy Data của nút bị hủy
delete p;
return 1;
}
ThS. Trần Văn Thọ 79

Xóa 1 nút p trước nút q (qHead)


Sinh viên tự làm, xem như bài tập

ThS. Trần Văn Thọ 80

Xóa nút có giá trị x của danh sách


int DeleteDNodeX(DList &dl, Data x)
{
DNode *q, *r, *p=FindDNode(dl, x);
if(p==NULL) return 0;
if(p==dl.Head) DeleteHead(dl, x);
else if(p==dl.Tail)DeleteTail(dl, x);
else {
q=p→Prev; r=p→Next;
q→Next=r; r→Prev=q;
delete p;
}
return 1;
}
ThS. Trần Văn Thọ 81

27
30/03/2015

Duyệt danh sách

Cách 1:
for(DNode* p = dl.Head; p!=NULL; p = p→Next)
< xử lý p >;

Cách 2:
for(DNode* q = dl.Tail; q !=NULL; q = q→Prev)
< xử lý q >;

ThS. Trần Văn Thọ 82

Sắp xếp danh sách dùng BubbleSort

Dùng mảng 1 chiều: (nhắc lại)


void BubbleSort_Asc(int a[ ],
int n)
{
int i, j;
for(int i=0; i<=n-2; i++)
for(int j=n-1; j>i; j--)
if(a[j] < a[j-1])
Swap(a[j], a[j-1]);
}
ThS. Trần Văn Thọ 83

Sắp xếp danh sách dùng BubbleSort

Dùng danh sách liên kết đôi:


void BubbleSort_Asc(Dlist &dl)
{
DNode *p, *q;
for(p=dl.Head; p!=dl.Tail; p=p→Next)
for(q=dl.Tail; q!=p; q=q→Prev)
if(q→Info < q→Prev→Info)
Swap(q→Info, q→Prev→Info);
}

ThS. Trần Văn Thọ 84

28
30/03/2015

Bài tập bổ sung


1. Tìm giá trị của phần tử nhỏ nhất trong danh sách?
2. Tìm giá trị phần tử dương nhỏ nhất trong danh sách?
3. Đếm số phần tử là số nguyên tố trong danh sách?
4. Đếm số phần tử lớn hơn hai phần tử lân cận?
5. Kiểm tra mọi phần tử trong danh sách có phải là số
chính phương không?
6. Kiểm tra mọi phần tử có được sắp xếp giảm?
7. Đếm số lần xuất hiện của phần tử x trong danh sách?
8. Xóa phần tử nhỏ nhất trong danh sách?
9. Xóa phần tử là số nguyên tố trong danh sách?
ThS. Trần Văn Thọ 85

ThS. Trần Văn Thọ 86

Danh sách liên kết vòng đơn


 Tương tự như danh sách liên kết đơn.
 Trường Next của nút cuối chỉ đến nút đầu danh sách.
 Chỉ cho phép di chuyển đến nút kế sau.
 Liên kết nút sau là: Next
Data Next

Tail

A1 A2 A3 An
Head
Trường Next của nút cuối không còn trỏ đến
NULL, mà trỏ đến nút đầu
ThS. Trần Văn Thọ 87

29
30/03/2015

Các thao tác cơ bản


 Khai báo cấu trúc nút
 Khai báo và khởi tạo danh sách rỗng
 Tạo nút mới
 Thêm một nút có khóa x
 Xóa một nút có khóa x
 Tìm một nút có khóa x
 Duyệt danh sách

ThS. Trần Văn Thọ 88

Khai báo nút

typedef int Data


typedef struct tagCNode
{
Data Info; Phần dữ liệu của CNode
tagCNode* Next; trỏ đến nút kế sau
}CNode;

typedef CNode* CNodePtr; Khai báo kiểu con trỏ CNode

ThS. Trần Văn Thọ 89

Khai báo và khởi tạo danh sách

typedef struct tagCList


{
CNode* Head; trỏ đến nút đầu
CNode* Tail; trỏ đến nút cuối
}CList; Khai báo kiểu DSLK vòng

void InitCList(CList &cl)


{
cl.Head=NULL;
cl.Tail=NULL;
}
ThS. Trần Văn Thọ 90

30
30/03/2015

Tạo nút mới


CNode* CreateCNode(Data x)
{
x NULL
CNode* p=new CNode;
if(p==NULL) Info Next
{
printf(“Không đủ bộ nhớ để cấp phát!”);
getch();
return NULL;
}
p→Info=x;
p→Next=NULL;
return p;
}
ThS. Trần Văn Thọ 91

Thêm 1 Nút Vào Đầu Danh Sách

Minh họa hình vẽ

Head
A B C D
p
Tail
X

ThS. Trần Văn Thọ 92

Thêm nút vào đầu danh sách


int InsertHead(CList &cl, CNode* p)
{
if(p==NULL) return 0;
if(cl.Head==NULL)
cl.Head=cl.Tail=p;
else
{
pNext=cl.Head;
cl.Head=p;
}
cl.TailNext=cl.Head;
return 1;
}
ThS. Trần Văn Thọ 93

31
30/03/2015

Thêm Vào Cuối Danh Sách

Minh họa thêm 1 phần tử vào cuối danh sách

Tail
Head

A B C D

X
p

ThS. Trần Văn Thọ 94

Thêm nút ở cuối danh sách


int InsertTail(CList &cl, CNode* p)
{
if(p==NULL) return 0;
if(cl.Head==NULL)
cl.Head=cl.Tail=p;
else
{
cl.TailNext=p;
pNext=cl.Head;
}
cl.Tail=p;
return 1;
}
ThS. Trần Văn Thọ 95

Tìm kiếm một nút có giá trị x


CNode* FindCNode(CList cl, Data x)
{
if(cl.Head==NULL) return NULL;
if(cl.HeadInfo==x) return cl.Head;
CNode *p=cl.HeadNext;
while(p!=cl.Head) {
if(pInfo==x)
return p;
p=pNext;
}
return NULL;
}
ThS. Trần Văn Thọ 96

32
30/03/2015

Xóa phần tử ở đầu danh sách


int DeleteHead(CList &cl, Data &x)
{
if(cl.Head==NULL) return 0;
CNode* p=cl.Head;
if(cl.Head==cl.Tail)
cl.Head=l.Tail=NULL;
else
cl.Head=cl.Head→Next;
x=p→Info; //lưu Data của nút cần hủy
delete p;
return 1;
}
ThS. Trần Văn Thọ 97

See you Next week!

33

You might also like