You are on page 1of 21

DANH SÁCH LIÊN KẾT KÉP

(DOUBLY LINKED LIST)


Nhóm 8:
Nguyễn Đình Sơn
Nguyễn Thành Tài
Bùi Văn Thi
Nguyễn Minh Lộc
Lê Trần Nguyên Khang
Danh sách liên kết kép là danh sách liên kết, trong đó mỗi phần tử của danh sách có 3 trường:
- Trường liên kết đến phần tử trước nó: Lưu địa chỉ phần tử đứng trước, bằng NULL nếu là phần
tử đầu danh sách
- Trường liên kết đến phần tử sau nó: Lưu địa chỉ phần tử đứng sau, bằng NULL nếu là phần tử
cuối danh sách
- Trường chứa nội dung của phần tử: Lưu thông tin về bản thân phần tử

0xb80 0xb81 0xb82 0xb83


0xb8 0xb8 0xb8 0xb8 0xb8 0xb8
NULL 5 9 0 11 NULL
1 0 2 1 3 2

Ví dụ: Danh sách liên kết kép lưu các giá trị số nguyên: {5, 9, 0, 11}
Cấu trúc của một node trong danh sách liên kết kép

pPrev 9 pNext struct NODE{


int info;
NODE *pNext;
NODE *pPrev;
Trường lưu địa
};
Trường lưu giá Trường lưu địa
chỉ node đứng chỉ node đứng
trị của node
trước sau

Ví dụ: node được khởi tạo lưu Code C++ về cấu trúc của 1 node
giá trị số nguyên 9
Cấu trúc của danh sách liên kết kép:

0xb80 0xb81 0xb82


0xb8 0xb8 0xb8 0xb8
NULL 5 9 0 NULL
1 0 2 1
struct LIST{
NODE
*pHead;
NODE *pTail;
pHea pTail
};
d
0xb80 0xb82
Code C++ về cấu
Ví dụ: Danh sách liên kết kép chứa trúc của 1 danh
các giá trị nguyên: {5, 9, 0} sách liên kết kép
NODE *CreateNODE(int info){
void CreateEmptyLIST(LIST NODE *p = new NODE;
&L){ p->info = info;
L.pHead = NULL; p->pNext = NULL;
L.pTail = NULL; p->pPrev = NULL;
} return p;
}

Hàm khởi tạo danh sách liên


kết kép rỗng (địa chỉ node Hàm khởi tạo
đầu và node cuối đều không node có giá trị là
có) info
Thêm 1 node vào đầu danh sách:

0xb79 0xb80 0xb81 0xb82


0xb8 0xb8 0xb8 0xb8
NULL 11 NULL NULL 5 9 0 NULL
1 0 2 1

Ví dụ: Thêm node Q có


giá trị 11 vào đầu danh
sách 0xb80 0xb82

pHea pTail
d
Thêm 1 node vào đầu danh sách:

0xb79 0xb80 0xb81 0xb82


0xb8 0xb7 0xb8 0xb8 0xb8 0xb8
NULL 11 NULL NULL 5 9 0 NULL
0 9 1 0 2 1

B1: pNext của Q trỏ đến pHead 1. Q->pNext = pHead


hiện tại
B2: pPrev của pHead hiện tại trỏ đến Q 0xb79
0xb80 0xb82 2. pHead->pPrev = Q

B3: Cập nhật lại pHead là Q pHea pTail


d
3. pHead = Q
void AddHead(LIST &L, NODE *p){
if (L.pTail == NULL){
L.pHead = p;
L.pTail = p;
}
else{
p->pNext = L.pHead;
p->pPrev = NULL;
L.pHead->pPrev = p;
L.pHead = p;
}
}

Code C++ thêm 1 node vào đầu danh


sách liên kết kép
Thêm 1 node vào cuối danh sách:

0xb80 0xb81 0xb82 0xb83


0xb8 0xb8 0xb8 0xb8
NULL 5 9 0 NULL NULL 11 NULL
1 0 2 1

0xb80 0xb82

pHea pTail Ví dụ: Thêm node Q có


d giá trị 11 vào cuối danh
sách
Thêm 1 node vào cuối danh sách:

0xb80 0xb81 0xb82 0xb83


0xb8 0xb8 0xb8 0xb8 0xb8 0xb8
NULL 5 9 0 NULL NULL 11 NULL
1 0 2 1 3 2

B1: pPrev của Q trỏ đến pTail hiện tại


1. Q->pPrev = pTail
0xb80 0xb82
0xb83 B2: pNext của pTail hiện tại trỏ đến Q

2. pTail->pNext = Q pHea pTail B3: Cập nhật lại pTail là Q


d

3. pTail = Q
void AddTail(LIST &L, NODE *p){
if (L.pTail == NULL){
L.pHead = p;
L.pTail = p;
}
else{
L.pTail->pNext = p;
p->pPrev = L.pTail;
p->pNext = NULL;
L.pTail = p;
}
}

Code C++ thêm 1 node vào cuối danh


sách liên kết kép
Thêm 1 node vào giữa danh sách:

0xb80 0xb81 0xb82


0xb8 0xb8 0xb8 0xb8
NULL 5 9 0 NULL
1 0 2 1

0xb83
pHea pTail
d NULL 11 NULL
0xb80 0xb82
Q
Ví dụ: Thêm node Q có
giá trị 11 vào giữa danh
sách (sau node P)
Thêm 1 node vào giữa danh sách:

0xb80 0xb81 0xb83 0xb82


0xb8 0xb8 0xb8 0xb8 0xb8 0xb8
NULL 5 9 NULL 11 NULL 0 NULL
1 0 23 1 2 3

P Q P -> pNext

B1: pNext của Q trỏ đến pNext của P


1. Q->pNext = P->pNext
B2: pPrev của P -> pNext trỏ đến Q
0xb80 0xb82
2. P->pNext->pPrev = Q
B3: pPrev của Q trỏ đến P
3. Q->pPrev = P

4. P->pNext = Q B4: pNext của P trỏ đến Q


void addnode_afterp(LIST &L, NODE *p, NODE *q){
if (p == L.pTail){
AddTail(L,q);
}
else{
q->pNext = p->pNext;
p->pNext->pPrev = q;
q->pPrev = p;
p->pNext = q;
}
}

Code C++ thêm node q vào sau node p


trong sách liên kết kép
Duyệt danh sách kiên kết kép:

void PrintList(LIST L){


if (L.pHead == NULL){
cout << "Empty List."; B1: Đặt p là node đầu tiên của danh sách L
return; B2: In ra màn hình giá trị của p (p->info)
} B3: Gán p bằng node tiếp theo (p = p->pNext)
NODE *p = L.pHead; và lặp lại B1 cho đến khi hết danh sách (p =
while(p){ NULL)
cout << p->info << " ";
p = p->pNext; Ý tưởng
}
}

Code C++ duyệt và in ra màn hình giá


trị các node của danh sách
Trường hợp danh sách chỉ có 1 node
(pHead = pTail = NULL)

0xb83

NULL 11 NULL

Xóa 1 node: Q

=> Xóa nút Q


Xóa 1 node: Trường hợp Q là pHead

1. pHead = pHead->pNext
0xb80 0xb81 0xb82
2. Q->pNext = NULL
0xb8 0xb8 0xb8 0xb8
NULL 5 NULL NULL 9 0 NULL
3. pHead->pPrev = NULL 1 0 2 1

4. delete Q
Q

B1: Cập nhật lại pHead->pNext thành pHead pHea pTail


d
B2: Gán Q->pNext bằng NULL 0xb80
0xb81 0xb82

B3: Gán pHead->pPrev bằng NULL

B4: Xóa Q
Xóa 1 node: Trường hợp Q là pTail

1. pTail = pTail->pPrev
0xb80 0xb81 0xb82
2. pTail->pNext = NULL
0xb8 0xb8 0xb8 0xb8
3. Q->pPrev = NULL NULL 5
1 0
9 NULL
2
NULL
1
0 NULL

4. delete Q
Q

B1: Cập nhật lại pTail->pPrev thành pTail pHea pTail


d
B2: Gán pTail->pNext bằng NULL 0xb80 0xb82
0xb81

B3: Gán Q->pPrev bằng NULL

B4: Xóa Q
Xóa 1 node C++: Trường hợp Q ở giữa danh sách, sau P

1. P->pNext = Q->pNext

2. Q->pNext->pPrev = P 0xb80 0xb81 0xb82


3. Q->pPrev = NULL 0xb8 0xb8 0xb8 0xb8
NULL 5 NULL 9 NULL 0 NULL
1 0 2 1
4. Q->pNext = NULL
P Q
5. delete Q

B1: Gán P->pNext = Q->pNext


pHea pTail
B2: Gán Q->pNext->pPrev bằng P d
0xb80 0xb82
B3: Gán Q->pPrev bằng NULL

B4: Gán Q->pPnext bằng NULL

B5: Xóa Q
Code C++ xóa 1 node p
void deleteNODEp(NODE *p, LIST &L){
if (p == NULL)
return;
if (L.pHead == L.pTail && p == L.pHead){
delete p;
L.pHead = NULL;
L.pTail = NULL;
p = NULL;
}
else if (p == L.pHead){
L.pHead = L.pHead->pNext;
L.pHead->pPrev = NULL;
p->pNext = NULL;
delete p;
p = NULL;
}

You might also like