You are on page 1of 12

Linked Lists

Danh sách liên kết


Khoa Công nghệ thông tin
Đại học Sài Gòn

z11/2/2009 zThS Nguyễn Quốc Huy z1

Tổng quan
• DSLK
– Abstract data type (ADT)
• Các thao tác cơ bản của DSLK
– Thêm, tìm, xoá, xuất, v.v.
• Các biến thể của DSLK
– DSLK vòng
– DSLK kép

z11/2/2009 zThS Nguyễn Quốc Huy z2


Danh sách liên kết

A B C ∅

Head

• DSLK là một loạt các nút có kết nối với nhau


• Mỗi nút chứa ít nhất
– Các thông tin
– Con trỏ trỏ đến nút kết tiếp của danh sách
• Head: trỏ đến nút đầu node
• Nút cuối trỏ đến NULL A

data pointer
z11/2/2009 zThS Nguyễn Quốc Huy z3

DSLK đơn
• Sử dụng 2 cấu trúc: Node và List
• Khai báo cấu trúc Node cho các nút
– data: double-kiểu dữ liệu cho ví dụ này
– next: con trỏ trỏ đến nút kế trong danh sách

typedef struct Node {


double data; // dữ liệu
Node* next; // trỏ nút kế
};

z11/2/2009 zThS Nguyễn Quốc Huy z4


DSLK đơn
• Khai báo List, chứa
– head: con trỏ trỏ đến nút đấu của danh sách.
Do ban đầu danh sách rỗng, head trỏ đến NULL
– Các thao tác trong List
Node* head;

int IsEmpty() {
if (head==NULL) return 1;
return 0;
}
Node* InsertNode(int index, double x);
int FindNode(double x);
int DeleteNode(double x);
void DisplayList(void);

z11/2/2009 zThS Nguyễn Quốc Huy z5

DSLK đơn
• Các thao tác của List
– IsEmpty: xác định danh sách rổng hay không
– InsertNode: thêm 1 nút mới vào 1 vị trí bất kì
– FindNode: tìm 1 nút với một giá trị cho trước
– DeleteNode: xoá một nút với một giá trị cho
trước
– DisplayList: xuất tất cả các nút trong danh
sách

z11/2/2009 zThS Nguyễn Quốc Huy z6


Thêm một nút mới
• Node* InsertNode(int index, double x)
– Thêm nút có dữ liệu x sau phần tử thứ index. (nghĩa là, khi
index = 0, thêm nút vào đầu;
khi index = 1, thêm nút sau phần tử đầu, và tiếp tục)
– Nếu thêm thành công, trả về nút đã được thêm.
Ngược lại, trả về NULL.
(Nếu index < 0 hay > chiều dài danh sách, việc thêm sẽ thất bại.)

• Các bước
index’th
1. Định vị thành phần thứ index element

2. Cấp phát bộ nhớ cho nút mới


3. Nút mới trỏ đến nút sau thành phần index
4. Nút thành phần thứ index trỏ đến nút mới
newNode

z11/2/2009 zThS Nguyễn Quốc Huy z7

Thêm một nút mới

• Các trường hợp thêm


1. Thêm vào danh sách rỗng
2. Thêm vào trước
3. Thêm vào sau
4. Thêm vào giữa

z11/2/2009 zThS Nguyễn Quốc Huy z8


Thêm một nút mới
Node* InsertNode(int index, double x) { Xác định nút thứ
if (index < 0) return NULL; index. Nếu không
tồn tại, trả về NULL.
int currIndex = 1;
Node* currNode = head;
while (currNode && index > currIndex) {
currNode = currNode->next;
currIndex++;
}
if (index > 0 && currNode == NULL) return NULL;

Node* newNode = new Node;


newNode->data = x;
if (index == 0) {
newNode->next = head;
head = newNode;
}
else {
newNode->next = currNode->next;
currNode->next = newNode;
}
return newNode;
zThS Nguyễn Quốc Huy
}z11/2/2009 z9

Thêm một nút mới


Node* InsertNode(int index, double x) {
if (index < 0) return NULL;

int currIndex = 1;
Node* currNode = head;
while (currNode && index > currIndex) {
currNode = currNode->next;
currIndex++;
}
if (index > 0 && currNode == NULL) return NULL;

Node* newNode = new Node;


newNode->data = x;
if (index == 0) {
newNode->next = head; Tạo một nút mới
head = newNode;
}
else {
newNode->next = currNode->next;
currNode->next = newNode;
}
return newNode;
zThS Nguyễn Quốc Huy
}z11/2/2009 z10
Thêm một nút mới
Node* InsertNode(int index, double x) {
if (index < 0) return NULL;

int currIndex = 1;
Node* currNode = head;
while (currNode && index > currIndex) {
currNode = currNode->next;
currIndex++;
}
if (index > 0 && currNode == NULL) return NULL;

Node* newNode = new Node;


newNode->data = x;
Thêm vào đầu
if (index == 0) { head
newNode->next = head;
head = newNode;
}
else {
newNode->next = currNode->next; newNode
currNode->next = newNode;
}
return newNode;
zThS Nguyễn Quốc Huy
}z11/2/2009 z11

Thêm một nút mới


Node* InsertNode(int index, double x) {
if (index < 0) return NULL;

int currIndex = 1;
Node* currNode = head;
while (currNode && index > currIndex) {
currNode = currNode->next;
currIndex++;
}
if (index > 0 && currNode == NULL) return NULL;

Node* newNode = new Node;


newNode->data = x;
if (index == 0) {
newNode->next = head;
head = newNode; Thêm sau currNode
} currNode
else {
newNode->next = currNode->next;
currNode->next = newNode;
}
return newNode;
zThS Nguyễn Quốc Huy
}z11/2/2009 z12
newNode
Tìm một nút
• int FindNode(double x)
– Tìm nút có giá trị x trong danh sách.
– Nếu tìm thấy, trả về vị trí. Ngược lại, trả về 0.

int FindNode(double x) {
Node* currNode= head;
int currIndex = 1;
while (currNode && currNode->data != x) {
currNode = currNode->next;
currIndex++;
}
if (currNode) return currIndex;
return 0;
}
z11/2/2009 zThS Nguyễn Quốc Huy z13

Xoá một nút


• int DeleteNode(double x)
– Xoá nút có giá trị x từ danh sách.
– Nếu nút được tìm thấy, trả về vị trí. Ngược lại, trả về 0.
• Các bước
– Tìm nút cần xoá (giống như FindNode)
– Giải phóng bộ nhớ
– Trỏ con trỏ của nút trước nút bị xoá vào nút sau.
• Giống như InsertNode, có 2 trường hợp đặc biệt
– Xoá nút đầu
– Xoá nút giữa hoặc cuối danh sách

z11/2/2009 zThS Nguyễn Quốc Huy z14


Xoá một nút
Int DeleteNode(double x) {
Tìm nút có giá trị x
Node* prevNode = NULL;
Node* currNode = head;
int currIndex = 1;
while (currNode && currNode->data != x) {
prevNode = currNode;
currNode = currNode->next;
currIndex++;
}
if (currNode) {
if (prevNode) {
prevNode->next = currNode->next;
delete currNode;
}
else {
head = currNode->next;
delete currNode;
}
return currIndex;
}
return 0;
}
z11/2/2009 zThS Nguyễn Quốc Huy z15

Xoá một nút


int DeleteNode(double x) {
Node* prevNode = NULL;
Node* currNode = head;
int currIndex = 1;
while (currNode && currNode->data != x) {
prevNode = currNode;
currNode = currNode->next;
currIndex++; prevNode currNode
}
if (currNode) {
if (prevNode) {
prevNode->next = currNode->next;
delete currNode;
}
else {
head = currNode->next;
delete currNode;
}
return currIndex;
}
return 0;
}
z11/2/2009 zThS Nguyễn Quốc Huy z16
Xoá một nút
int DeleteNode(double x) {
Node* prevNode = NULL;
Node* currNode = head;
int currIndex = 1;
while (currNode && currNode->data != x) {
prevNode = currNode;
currNode = currNode->next;
currIndex++;
}
if (currNode) {
if (prevNode) {
prevNode->next = currNode->next;
delete currNode;
}
else {
head = currNode->next;
delete currNode;
}
return currIndex;
} head currNode
return 0;
}
z11/2/2009 zThS Nguyễn Quốc Huy z17

Xuất tất cả các thành phần


• void DisplayList(void)
– Xuất dữ liệu của các thành phần
– Xuất số nút trong danh sách
void DisplayList()
{
int num = 0;
Node* currNode = head;
while (currNode != NULL){
cout << currNode->data << endl;
currNode = currNode->next;
num++;
}
cout << "Number of nodes in the list: " << num << endl;
}
z11/2/2009 zThS Nguyễn Quốc Huy z18
Huỷ danh sách
• DList()
– Huỷ toàn bộ danh sách.
– Xoá từng nút.

void DList() {
Node* currNode = head, *nextNode = NULL;
while (currNode != NULL)
{
nextNode = currNode->next;
// destroy the current node
delete currNode;
currNode = nextNode;
}
}
z11/2/2009 zThS Nguyễn Quốc Huy z19

6
7 KQ
Sử dụng List 5
Số nút trong danh sách: 3
5.0 found
4.5 not found
6
int main(void) 5
{ Số nút trong danh sách: 2

InsertNode(0, 7.0); // successful


InsertNode(1, 5.0); // successful
InsertNode(-1, 5.0); // unsuccessful
InsertNode(0, 6.0); // successful
InsertNode(8, 4.0); // unsuccessful
// print all the elements
DisplayList();
if(FindNode(5.0) > 0) cout << "5.0 found" << endl;
else cout << "5.0 not found" << endl;
if(FindNode(4.5) > 0) cout << "4.5 found" << endl;
else cout << "4.5 not found" << endl;
DeleteNode(7.0);
DisplayList();
return 0;
} z11/2/2009 zThS Nguyễn Quốc Huy z20
Các biến thể của DSLK
• DSLK vòng
– Nút cuối trỏ đến nút đầu của danh sách

A B C

Head

– Vậy thì duyệt danh sách như thế nào? (Xem con
trỏ nút hiện hành có là Head chưa.)

z11/2/2009 zThS Nguyễn Quốc Huy z21

Các biến thể của DSLK


• DSLK kép
– Mỗi nút trỏ đến nút trước và nút sau
– Có 2 NULL: một đầu, một cuối
– Ưu điểm: cho một nút, dễ dàng thăm các nút trước.
Thuận tiện thăm các nút sau.

∅ A B C ∅

z11/2/2009 Head zThS Nguyễn Quốc Huy z22


Mảng so với DSLK

• DSLK phức tạp hơn mảng, nhưng có một số ưu điểm.


– Tính động: DSLK dễ dàng tăng hay giảm kích thước.
• Không cần biết có bao nhiêu nút trong danh sách. Số nút được
tạo nếu cần.
• Tuy nhiên, kích thước mảng C++ thì cố định lúc biên dịch.
– Thêm và xoá dễ dàng và nhanh chóng
• Thêm và xoá một thành phần trong mảng, ta cần copy vào biến
tạm.
• Với DSLK, không cần di chuyển các nút khác. Chỉ cần sử dụng
các con trỏ.

z11/2/2009 zThS Nguyễn Quốc Huy z23

You might also like