Các thao tác cơ bản của danh sách liên kết đơn.. Các thao tác cơ bản của danh sách liên kết vòng.. Danh sách liên k ết đơn 3/23 Để quản lý danh sách liên kết, thông thường cần: • Start
Trang 1Gi ảng viên: TS Ngo Huu Phuc
Tel: 0438 326 077 Mob: 098 5696 580
Bài 15 Danh sách liên k ết
Trang 2Bài 15: Danh sách liên k ết
15.1 Gi ới thiệu chung.
15.2 Danh sách liên k ết đơn.
15.2.1 Khái ni ệm về danh sách liên kết đơn.
15.2.2 Các thao tác cơ bản của danh sách liên kết đơn.
15.3 Danh sách liên k ết vòng.
15.3.1 Khái ni ệm về danh sách liên kết vòng.
15.3.2 Các thao tác cơ bản của danh sách liên kết vòng.
15.4 Danh sách liên k ết kép.
15.4.1 Khái ni ệm về danh sách liên kết kép.
15.4.2 Các thao tác cơ bản của danh sách liên kết kép.
15.5 M ột số ví dụ về danh sách liên kết.
Tham kh ảo:
1. Deshpande Kakde: C and Data structures.chm, Chapter 20: Linked Lists
2. Elliz Horowitz – Fundamentals of Data Structures.chm, Chapter 4: Linked Lists
3. Kyle Loudon: Mastering Algorithms with C.chm, Chapter 5 Linked Lists
4. Bài giảng TS Nguyễn Nam Hồng
Trang 315.1 Gi ới thiệu chung (1/2)
V ới CTDL dạng mảng, bộ nhớ được sử dụng là m ột dãy liền
k ề và có kích thước cố định
Tuy nhiên, CTDL này có m ột số nhược điểm:
Th ời gian cho việc thêm hay b ớt phần tử trong mảng khá lâu vì
ph ải thay đổi cả các phần tử còn lại trong mảng.
dư thừa bộ nhớ xuất hiện
Trang 415.1 Gi ới thiệu chung (2/2)
Để khắc phục nhược điểm trên, có thể s ử dụng danh sách liên
k ết như là cấu trúc dữ liệu thay thế
Trong c ấu trúc này, không c ần xác định kích thước cho các
ph ần tử trước
Ta có th ể định nghĩa phần tử bất cứ lúc nào , sau đó liên kết
ph ần tử đó với danh sách đã có trước đó
Như vậy, mỗi phần tử sẽ bao gồm thông tin cần lưu trữ và liên
k ết với các phần tử khác.
Trang 515.2 Danh sách liên k ết đơn (1/23)
Trong r ất nhiều trường hợp cần sử dụng đến danh sách liên kết động, danh sách liên kết động cần dùng đến khi kích thước danh sách chưa biết tại thời điểm biên dịch chương trình
Khi đó, danh sách có thể mở rộng hoặc thu hẹp lại tại thời
điểm chạy chương trình
C ấu trúc dữ liệu linked list s ử dụng mô hình liên kết động.
M ột số dạng của danh sách liên kết:
Danh sách liên k ết kép.
Trang 615.2 Danh sách liên k ết đơn (2/23)
Trang 715.2 Danh sách liên k ết đơn (3/23)
Để quản lý danh sách liên kết, thông thường cần:
• Start là con tr ỏ chỉ đến phần tử đầu tiên của danh sách liên kết.
• Ph ần tử cuối của danh sách liên kết với vùng liên kết có nội dung NULL.
Trang 815.2 Danh sách liên k ết đơn (4/23)
Khai báo c ấu trúc một Node của danh sách:
template < class ListEntry>
struct node {
Trang 915.2 Danh sách liên k ết đơn (5/23)
15.2.2 Các thao tác cơ bản của danh sách liên kết đơn
Trang 1015.2 Danh sách liên k ết đơn (6/23)
class LList {
public:LList();
int LAdd(ListEntry entry);
int LInsert(ListEntry value, ListEntry entry);
int LAppend(ListEntry entry);
int LFind(ListEntry value);
int LDelete(ListEntry value);
int LLength();
void LMakeEmpty();
int LGet(int pos, ListEntry *value);
template<typename ListEntry> friend void LPrint(LList<ListEntry> list);
private:node<ListEntry> *start;
15.2.2 Các thao tác cơ bản của danh sách liên kết đơn
Trang 1115.2 Danh sách liên k ết đơn (7/23)
Kh ởi tạo danh sách:
template < class ListEntry>
Trang 1215.2 Danh sách liên k ết đơn (8/23)
Thêm m ột node đầu danh sách:
N ếu danh sách rỗng, cấp phát ô nhớ và
cho start tr ỏ vào ô nhớ đó.
N ếu danh sách không rỗng:
C ấp phát ô nhớ cho biến temp.
Ph ần liên kết của temp trỏ vào đầu danh
sách.
Con tr ỏ start trỏ vào temp.
15.2.2 Các thao tác cơ bản của danh sách liên kết đơn
Trang 1315.2 Danh sách liên k ết đơn (9/23)
Thêm m ột node đầu danh sách:
template<classListEntry>
intLList<ListEntry>::LAdd(ListEntry entry) {
malloc(sizeof(node<ListEntry>));
if(temp==NULL) {printf("Loi cap phat bo nho!\n");
return kt; }kt=1;
Trang 1415.2 Danh sách liên k ết đơn (10/23)
Chèn 1 node vào danh sách:
Nh ập thông tin về node đứng trước node thêm mới.
S ử dụng con trỏ temp để đến được node đứng trước đó.
C ấp phát ô nhớ cho biến temp1.
Ph ần liên kết của temp1 trỏ vào phần liên kết của con trỏ temp.
Ph ần liên kết của con trỏ temp trỏ vào temp1.
15.2.2 Các thao tác cơ bản của danh sách liên kết đơn
Trang 1515.2 Danh sách liên k ết đơn (11/23)
Chèn 1 node vào danh sách :
template<classListEntry>
intLList<ListEntry>::LInsert(ListEntry value,
ListEntry entry) {
int kt=0;
node<ListEntry> *temp, *temp1;
if(start==NULL) printf("Danh sach rong!");
if(temp1==NULL) {printf("Loi cap phat bo nho!\n");
return kt; }kt=1;
temp1->data=entry;
temp1->link=temp->link;
temp->link=temp1;
}}
return kt; }
Trang 1615.2 Danh sách liên k ết đơn (12/23)
Thêm m ột node cuối danh sách:
N ếu danh sách rỗng, cấp phát ô nhớ và
cho start tr ỏ vào ô nhớ đó.
N ếu danh sách không rỗng:
S ử dụng con trỏ temp đi đến cuối danh
Trang 1715.2 Danh sách liên k ết đơn (13/23)
Thêm m ột node cuối danh sách:
template<classListEntry>
intLList<ListEntry>::LAppend(ListEntry entry) {
while(temp->link!=NULL)temp=temp->link;
temp->data=entry;
temp->link=NULL; }
returnkt;
Trang 1815.2 Danh sách liên k ết đơn (14/23)
Tìm m ột node trong danh sách:
S ử dụng con trỏ temp để duyệt qua
danh sách.
S ử dụng thêm biến pos để lưu vị trí
c ủa node trong danh sách Nếu danh
sách r ỗng hoặc không tìm thấy trả về
0, ngược lại trả về vị trí của node.
15.2.2 Các thao tác cơ bản của danh sách liên kết đơn
Trang 1915.2 Danh sách liên k ết đơn (15/23)
Tìm m ột node trong danh sách:
template < class ListEntry>
int LList<ListEntry>::LFind(ListEntry value) {
Trang 2015.2 Danh sách liên k ết đơn (16/23)
Xóa m ột node trong danh sách:
S ử dụng 2 con trỏ prev và curr để tìm
node c ần xóa Con trỏ prev trỏ vào node
trước node cần xóa Con trỏ curr trỏ vào
node c ần xóa.
N ếu curr = start, cho start trỏ vào
start->link và gi ải phóng ô nhớ của curr.
N ếu không, prev->link trỏ tới
curr->link và gi ải phóng ô nhớ của curr.
15.2.2 Các thao tác cơ bản của danh sách liên kết đơn
Trang 2115.2 Danh sách liên k ết đơn (17/23)
Xóa một node trong danh sách :
intLList<ListEntry>::LDelete(ListEntry value) {
node<ListEntry> *prev, *curr;
break; }
else {prev=curr;
free(curr); }
else {prev->link=curr->link;
free(curr);
}}}
returnkt;
}
Trang 2215.2 Danh sách liên k ết đơn (18/23)
L ấy thông tin một node ở vị trí nào đó:
S ử dụng con trỏ temp để duyệt qua
danh sách.
Duy ệt cho đến khi đến node thứ pos,
l ấy thông tin tại node đó và trả lại cho
Cho trước pos = 3
Trang 2315.2 Danh sách liên k ết đơn (19/23)
L ấy thông tin một node ở vị trí nào đó :
template <classListEntry>
int LList<ListEntry>::LGet(intpos, ListEntry *value) {
15.2.2 Các thao tác cơ bản của danh sách liên kết đơn
Trang 2415.2 Danh sách liên k ết đơn (20/23)
Xác định số phần tử trong danh sách:
S ử dụng con trỏ temp để duyệt qua
danh sách, cho đến khi temp =NULL.
Trang 2515.2 Danh sách liên k ết đơn (21/23)
Trang 2615.2 Danh sách liên k ết đơn (22/23)
Làm r ỗng danh sách:
Xóa t ừng phần tử trong danh sách.
S ử dụng con trỏ temp để xác định
ph ần tử cần xóa (từ đầu danh sách).
D ịch chuyển con trỏ start sang ph ần
t ử kế tiếp.
Thu h ồi ô nhớ ứng với con trỏ temp
Th ực hiện cho đến khi start =NULL.
15.2.2 Các thao tác cơ bản của danh sách liên kết đơn
Trang 2715.2 Danh sách liên k ết đơn (23/23)
Làm r ỗng danh sách :
template < class ListEntry>
void LList<ListEntry>::LMakeEmpty() {
node<ListEntry> *temp;
while (start!=NULL) {
temp=start;
start=start->link;
free(temp);
} }
15.2.2 Các thao tác cơ bản của danh sách liên kết đơn
Trang 2815.3 Danh sách liên k ết vòng (1/20)
vào ph ần tử đầu tiên
Trang 2915.3 Danh sách liên k ết vòng (2/20)
• Start là con tr ỏ chỉ đến một phần tử của danh sách liên kết.
• Ph ần tử “cuối” của danh sách, liên kết với phần tử do start qu ản lý.
• Như vậy, từ bất kỳ vị trí nào trong danh sách cũng có thể duyệt hết danh sách.
Lưu ý : khi thêm hay b ớt phần tử nào trong danh sách cần đảm bảo rằng sau thao tác đó vẫn giữ được tính liên kết vòng.
15.3.1 Khái ni ệm về danh sách liên kết vòng
Trang 3015.3 Danh sách liên k ết vòng (3/20)
template <class ListEntry>
class CLList {
public:CLList();
int CLAdd(ListEntry entry);
int CLInsert(ListEntry value, ListEntry entry);
int CLAppend(ListEntry entry);
int CLFind(ListEntry value);
int CLDelete(ListEntry value);
int CLLength();
void CLMakeEmpty();
int CGet(int pos, ListEntry *value);
template<typename ListEntry> friend void LPrint(CLList<ListEntry> list);
private:
15.3.2 Các thao tác cơ bản của danh sách liên kết vòng
Trang 3115.3 Danh sách liên k ết vòng (4/20)
Kh ởi tạo danh sách LKV:
template < class ListEntry>
Trang 32 N ếu danh sách không rỗng:
S ử dụng biến temp để duyệt qua danh
sách, khi temp →link <> start
C ấp phát ô nhớ cho temp →link
Ph ần liên kết của ô nhớ mới trỏ vào
start
Start tr ỏ vào vùng ô nhớ mới trên.
15.3.2 Các thao tác cơ bản của danh sách liên kết vòng
Trang 3315.3 Danh sách liên k ết vòng (6/20)
Thêm m ột node đầu danh sách LKV:
template< classListEntry>
intCLList<ListEntry>::CLAdd(ListEntry entry)
while (temp->link!=start)temp=temp->link;
temp->link=(node<ListEntry> *)malloc(sizeof(node<ListEntry>));
if(temp->link==NULL) {printf("Loi cap phat bo nho!\n");
returnkt; }kt=1; temp=temp->link;
Trang 3415.3 Danh sách liên k ết vòng (7/20)
Chèn 1 node vào danh sách LKV:
Nh ập thông tin về node đứng trước node thêm mới.
S ử dụng con trỏ temp để đến được node đứng trước đó.
C ấp phát ô nhớ cho biến temp1
Ph ần liên kết của temp1 tr ỏ vào phần liên kết của con trỏ temp
Ph ần liên kết của con trỏ temp tr ỏ vào temp1
15.3.2 Các thao tác cơ bản của danh sách liên kết vòng
Trang 3515.3 Danh sách liên k ết vòng (8/20)
Chèn 1 node vào danh sách LKV :
template<classListEntry>
intCLList<ListEntry>::CLInsert(ListEntry value,
ListEntry entry) {
int kt=0;
node<ListEntry> *temp, *temp1;
if(start==NULL) printf("Danh sach rong!");
temp1->data=entry;
temp1->link=temp->link;
temp->link=temp1;
}}
return kt;
}
Trang 36 N ếu danh sách không rỗng:
S ử dụng biến temp để duyệt qua danh
sách, khi temp →link <> start
C ấp phát ô nhớ cho temp →link
Ph ần liên kết của ô nhớ mới trỏ vào
Trang 3715.3 Danh sách liên k ết vòng (10/20)
Thêm m ột node cuối danh sách LKV:
template<classListEntry>
intCLList<ListEntry>::CLAppend(ListEntry entry) {
while (temp->link!=start)temp=temp->link;
temp->link=(node<ListEntry> *) malloc(sizeof(node<ListEntry>));
if(temp->link==NULL) {printf("Loi cap phat bo nho!\n");
returnkt; }kt=1;
Trang 3815.3 Danh sách liên k ết vòng (11/20)
Tìm m ột node trong danh sách LKV:
S ử dụng con trỏ temp để duyệt qua
danh sách, khi temp →link <> start
S ử dụng thêm biến pos để lưu vị trí
c ủa node trong danh sách Nếu danh
sách r ỗng hoặc không tìm thấy trả về
0, ngược lại trả về vị trí của node.
15.3.2 Các thao tác cơ bản của danh sách liên kết vòng
Trang 3915.3 Danh sách liên k ết vòng (12/20)
Tìm m ột node trong danh sách LKV:
template < class ListEntry>
int CLList<ListEntry>::CLFind(ListEntry value) {
int pos=0;
node<ListEntry> *temp=start;
if (temp!=NULL) {
do { pos++;
if (temp->data==value) break ; temp=temp->link;
Trang 4015.3 Danh sách liên k ết vòng (13/20)
Xóa m ột node trong danh sách LKV:
Sử dụng 2 con trỏ prev và curr để tìm node
cần xóa Con trỏ prev trỏ vào node trước
node cần xóa Con trỏ curr trỏ vào node cần
xóa
Nếu curr=curr->link, danh sách có 1 phần
tử, cho start trỏ NULL, giải phóng ô nhớ
Nếu curr <> start, cho prev->link trỏ vào
curr->link và giải phóng ô nhớ của curr
Nếu curr=start, thay đổi start, prev->link
trỏ curr->link và giải phóng ô nhớ của curr
15.3.2 Các thao tác cơ bản của danh sách liên kết vòng
Trang 4115.3 Danh sách liên k ết vòng (14/20)
Xóa một node trong danh sách LKV:
template<classListEntry>
intCLList<ListEntry>::CLDelete(ListEntry value) {
node<ListEntry> *prev, *curr;
else {prev=curr;
curr=curr->link; }}
else {prev=start; curr=start->link;
while (curr!=start) {prev=curr;
curr=curr->link; }prev->link=curr->link;
start=prev->link;
free(curr);
}}}}
return kt;
}
Trang 4215.3 Danh sách liên k ết vòng (15/20)
L ấy thông tin một node ở vị trí nào đó LKV:
S ử dụng con trỏ temp để duyệt qua danh
sách.
Duy ệt cho đến khi đến node thứ pos , l ấy
thông tin t ại node đó và trả lại cho nơi gọi
hàm.
15.3.2 Các thao tác cơ bản của danh sách liên kết vòng
Cho trước pos = 3
Trang 4315.3 Danh sách liên k ết vòng (16/20)
L ấy thông tin một node ở vị trí nào đó :
template<classListEntry>
intCLList<ListEntry>::CGet(intpos, ListEntry *value)
else
return0;
}
Trang 4415.3 Danh sách liên k ết vòng (17/20)
Xác định số phần tử trong danh sách:
S ử dụng con trỏ temp để duyệt qua
danh sách, khi temp<> start
Trang 4515.3 Danh sách liên k ết vòng (18/20)
Xác định số phần tử trong danh sách LKV:
template < class ListEntry>
int CLList<ListEntry>::CLLength() { int length=0;
Trang 46 Lưu ý: tính vòng của danh sách.
15.3.2 Các thao tác cơ bản của danh sách liên kết vòng
start temp
data link
Trang 4715.3 Danh sách liên k ết vòng (20/20)
Làm r ỗng danh sách LKV:
template < class ListEntry>
void CLList<ListEntry>::CLMakeEmpty() {
node<ListEntry> *temp;
while (start!=NULL) {
temp=start;
start=start->link;
CLDelete(temp->data);
} }
15.3.2 Các thao tác cơ bản của danh sách liên kết vòng
Trang 4815.4 Danh sách liên k ết kép (1/22)
V ới danh sách liên kết đơn, chỉ cho phép duyệt danh sách theo một
chi ều.
Để xóa một node cần lưu node đứng trước đó
N ếu một liên kết bị hỏng, các phần tử sau đó không dùng được.
k ết như vậy, danh sách liên kết được gọi là có liên k ết kép
Trang 4915.4 Danh sách liên k ết kép (2/22)
• Start là con tr ỏ chỉ đến phần tử đầu tiên của danh sách liên kết kép.
• End là con tr ỏ chỉ đến phần tử cuối cùng của danh sách liên kết kép.
• Thông thường, phần tử cuối có liên kết right trỏ tới NULL.
• B ằng cách sử dụng hợp lý liên kết left hay right, có thể đi về trước hay sau.
Lưu ý : khi thêm hay b ớt phần tử nào trong danh sách cần đảm bảo rằng sau thao tác đó vẫn giữ được tính liên kết vòng.
15.4.1 Khái ni ệm về danh sách liên kết kép
Trang 5115.4 Danh sách liên k ết kép (4/22)
Khai báo c ấu trúc một Node của danh sách liên kết kép:
template < class ListEntry>
struct dnode {
Trang 5215.4 Danh sách liên k ết kép (5/22)
template <class ListEntry>
class DLList {
public:DLList();
int DLAdd(ListEntry entry);
int DLInsert(ListEntry value, ListEntry entry);
int DLAppend(ListEntry entry);
int DLFind(ListEntry value);
int DLDelete(ListEntry value);
int DLLength();
void DLMakeEmpty();
int DGet(int pos, ListEntry *value);
template<typename ListEntry> friend void LPrint(DLList<ListEntry> list);
private:
15.4.2 Các thao tác cơ bản của danh sách liên kết kép
Trang 5315.4 Danh sách liên k ết kép (6/22)
Kh ởi tạo danh sách LK kép:
template < class ListEntry>
Trang 5415.4 Danh sách liên k ết kép (7/22)
Thêm m ột node đầu danh sách LK kép:
N ếu danh sách rỗng, cấp phát ô nhớ và
cho start và end tr ỏ vào ô nhớ đó.
N ếu danh sách không rỗng:
C ấp phát ô nhớ cho con trỏ temp
T ạo các liên kết left và right tương ứng
(liên k ết temp->left tr ỏ vào NULL, liên
k ết temp->right tr ỏ vào start ).
Start tr ỏ vào vùng ô nhớ mới trên.
15.4.2 Các thao tác cơ bản của danh sách liên kết kép
1
2
start
data right left
1
2 3 4