Tùy cách liên kết giữa các phần tử, danh sách liên kết chia thành các loại khác nhau: ◦ Danh sách liên kết đơn ◦ Danh sách liên kết đôi/kép ◦ Danh sách đa liên kết ◦ Danh sách liên k
Trang 1Môn: CẤU TRÚC DỮ LIỆU
Chương 6: DANH SÁCH (LIST)
Trang 24 Danh sách liên kết (Linked List)
4.1 Định nghĩa
4.2 Danh sách liên kết đơn (Simply Linked List)
4.3 Danh sách liên kết kép (Doubly Linked List)
4.4 Danh sách liên kết vòng
4.5 Ưu nhược điểm của danh sách liên kết
Trang 34 Danh sách liên kết (tt)
4.1 Định nghĩa
Là tập hợp các phần tử mà giữa chúng có một sự nối
kết với nhau thông qua vùng liên kết của chúng.
Tùy cách liên kết giữa các phần tử, danh sách liên kết
chia thành các loại khác nhau:
◦ Danh sách liên kết đơn
◦ Danh sách liên kết đôi/kép
◦ Danh sách đa liên kết
◦ Danh sách liên kết vòng (vòng đơn, vòng đôi)
Mỗi loại danh sách có cách biểu diễn theo các cấu
trúc dữ liệu và thao tác trên dữ liệu khác nhau.
Trang 44.2 Danh sách liên kết đơn (SLL)
Trang 54.2 Danh sách liên kết đơn (SLL)
Trang 64.2 Danh sách liên kết đơn (SLL)
4.2.1 Cấu trúc dữ liệu
Trang 74.2 Danh sách liên kết đơn
(tt)
4.2.1 Cấu trúc dữ liệu (tt)
Để quản lý danh sách liên kết có thể dùng nhiều
phương pháp khác nhau, mỗi phương pháp sẽ có
Trang 84.2 Danh sách liên kết đơn (tt)
4.2.1 Cấu trúc dữ liệu (tt)
Trang 94.2 Danh sách liên kết đơn (tt)
4.2.2 Các thao tác trên danh sách liên kết đơn
a Khởi tạo danh sách SLL
b Tạo mới 1 phần tử (nút) trong danh sách SLL
c Thêm 1 phần tử vào danh sách SLL
Thêm vào đầu | cuối | giữa danh sách liên kết đơn
d Duyệt qua các nút trong danh sách
e Tìm kiếm phần tử trong danh sách
f Hủy bỏ 1 phần tử trong danh sách
g Hủy danh sách
h Tạo mới danh sách/Nhập danh sách
i Tách 1 danh sách thành nhiều danh sách
j Nhập nhiều danh sách thành 1 danh sách
k Sắp xếp thứ tự các phần tử trong danh sách
h Sao chép 1 danh sách
Trang 104.2 Danh sách liên kết đơn (tt)
4.2.2 Các thao tác trên danh sách liên kết đơn:
Giả sử ta có các định nghĩa sau:
Trang 114.2 Danh sách liên kết đơn
(tt)
4.2.2.a Khởi tạo danh sách SLL
Thao tác khởi tạo danh sách liên kết đơn là cho giá
trị con trỏ quản lý địa chỉ đầu của danh sách về con trỏ NULL
Hàm khởi tạo danh sách liên kết đơn:
void Init(node *pHead)
{
pHead = NULL;
return;
}
Trang 124.2 Danh sách liên kết đơn
(tt)
4.2.2 b Tạo mới 1 phần tử (nút) trong danh sách SLL
Giả sử tạo mới 1 phần tử có thành phần dữ liệu =x
Thuật toán
B1: p = new node //cấp phát bộ nhớ cho con trỏ p
B2: IF(p == NULL) // cấp phát không thành công
Thực hiện BKT
B3: p->data=x;
B4: p->link=NULL
BKT: Kết thúc
Trang 134.2 Danh sách liên kết đơn (tt) (Hàm tạo node)
Trang 144.2 Danh sách liên kết đơn
(tt)
4.2.2.c Thêm 1 phần tử vào danh sách SLL (Thêm đầu
DS)
Trang 154.2 Danh sách liên kết đơn
Trang 164.2 Danh sách liên kết đơn (tt)
p->link=l.pHead;
l.pHead=p;
}}
Trang 174.2 Danh sách liên kết đơn
(tt)
Như vậy một danh sách bằng cách chèn đầu ta có thể
viết hàm như sau:
void create_list_head(list &l, int n)
{
node *p;
for (int i=1;i<10;i++) // nen dung vong lap do while de viet
{p=get_node(n);
insert_head(l,p);
}}
Trang 184.2 Danh sách liên kết đơn
(tt)
4.2.2.c Thêm 1 phần tử vào danh sách SLL (tt)
(Thêm giữa DS)
Trang 194.2 Danh sách liên kết đơn
(tt)
4.2.2.c Thêm 1 phần tử vào danh sách SLL (tt)
(Thêm giữa DS)
Trang 204.2 Danh sách liên kết đơn
Trang 214.2 Danh sách liên kết đơn (tt)
void insert_after(List &l, node *q, int n){
Trang 224.2 Danh sách liên kết đơn
(tt)
4.2.2.c Thêm 1 phần tử vào danh sách SLL (Thêm cuối
DS)
Trang 234.2 Danh sách liên kết đơn
Trang 244.2 Danh sách liên kết đơn (tt)
void insert_tail(List &l, node *p){
if (l.pHead==NULL){
l.pHead=p;
l.pTail=p;
}else{
l.pTail->link=p;
l.pTail=p;
}
}
Trang 254.2 Danh sách liên kết đơn
(tt)
4.2.2.d Duyệt qua các nút trong danh sách liên kết đơn
Là thao tác thường dùng trong các loại danh sách
Tùy theo từng trường hợp cụ thể để xử lý trong khi
duyệt DS
Thuật toán:
B1: p = pHead //cho con trỏ p trỏ đến phần tử đầu danh sách
B2: Trong khi danh sách chưa hết thì thực hiện
B21: Xử lý phần tử p
B22: p = p->link //cho p trỏ đến phần tử kế tiếp
Trang 264.2 Danh sách liên kết đơn (tt)
Trang 274.2 Danh sách liên kết đơn (tt)
4.2.2.e Tìm kiếm phần tử trong danh sách
Giả sử cần tìm kiếm trong danh sách liên kết đơn
phần tử có phần dữ liệu X
Dùng thuật toán tìm tuyến tính
Thuật toán
B1: p=pHead // cho p trỏ đến phần tử đầu danh sách
B2: Trong khi (p!= NULL) và (p->data != X)
Thực hiện p = p->link; // cho p trỏ tới phần tử kế
B3:
Nếu p!=NULL thi p trỏ tới phần tử cần tìm
Ngược lại: không có phần tử cần tìm
Trang 284.2 Danh sách liên kết đơn (tt)
4.2.2.e Tìm kiếm phần tử trong danh sách (tt)
Trang 294.2 Danh sách liên kết đơn (tt)
4.2.2.f Xoá 1 phần tử trong danh sách
Xoá đầu DS
Trang 304.2 Danh sách liên kết đơn (tt)
4.2.2.f Xoá 1 phần tử trong danh sách
Trang 314.2 Danh sách liên kết đơn (tt)
Trang 324.2 Danh sách liên kết đơn (tt)
4.2.2.f Xoá1 phần tử trong danh sách
Xoá phần tử ngay sau phần tử q:
Trang 334.2 Danh sách liên kết đơn (tt)
4.2.2.f Xoá1 phần tử trong danh sách
Xoá phần tử ngay sau phần tử q:
Trang 344.2 Danh sách liên kết đơn (tt)
void delete_node(List &l, node *q){
Trang 354.2 Danh sách liên kết đơn
Báo không có k;
Trang 364.2 Danh sách liên kết đơn (tt)
int delete_node_keyk(List &l,int k){
q->pNext=p->link;
delete p;
}
Trang 374.2 Danh sách liên kết đơn (tt)
else{
l.pHead=p->link;
if(l.pHead==NULL)l.pTail=NULL;
}return (1);
}
Trang 384.2 Danh sách liên kết đơn (tt)
Trang 394.2 Danh sách liên kết đơn (tt)
void XoaDs (List &l)
Trang 404.2 Danh sách liên kết đơn (tt)
4.2.2.h Tạo mới danh sách/Nhập danh sách
Tạo mới 1 danh sách thực chất là liên tục thêm 1
phần tử vào danh sách mà danh sách ban đầu là rỗng
Tạo DS bằng cách thêm vào đầu DS
Trang 414.2 Danh sách liên kết đơn (tt)
4.2.2.h Tạo mới danh sách/Nhập danh sách
void TaoDSdau(List &l, int x)
Trang 424.2 Danh sách liên kết đơn (tt)
Tạo DS bằng cách thêm vào cuối DS
void TaoDScuoi(List &l, int x)
Trang 434.2 Danh sách liên kết đơn (tt)
4.2.2.i Tách 1 danh sách thành nhiều danh sách
Trang 444.2 Danh sách liên kết đơn (tt)
4.2.2.j Nhập nhiều danh sách thành 1 danh sách
Trang 454.2 Danh sách liên kết đơn (tt)
4.2.2.k Sắp xếp thứ tự các phần tử trong danh sách
Thuật toán sắp xếp trộn tự nhiên:
B1: IF (SLLSplit(SLList, TempList) == NULL)
Thực hiện BKT
B2: SLLMerge(SLList, TempList, SLList)
B3: Lặp lại B1
BKT: Kết thúc
Trang 464.2 Danh sách liên kết đơn (tt)
void SLLNaturalMergeSort(SLLType &SList)
{ SLLType TempList = NULL, List = NULL;
while (SLLSplit(SList,TempList) != NULL){ SLLMerge(SList, TempList, List);
SList = List;
}
return;
}
Trang 474.2 Danh sách liên kết đơn (tt)
4.2.2.h Sao chép 1 danh sách
Sao chép 1 danh sách thực chất là tạo mới danh sách
NewList bằng cách duyệt qua các nút của SLList để lấy
thành phần dữ liệu để tạo thành 1 nút mới & bổ sung nút
mới này vào danh sách NewList.
Trang 484.2 Danh sách liên kết đơn
(tt)
4.2.2.h Sao chép 1 danh sách (tt)
Cài đặt thuật toán:
SLLType SLLCopy (SLLType SList, SLLType &NewList)
{ NewList = NULL;
SLLType CurrNode = SList;
while (CurrNode != NULL)
{ SLLType NewNode= SLLAddLast (NewList,CurrNode->Key);
Trang 494.2 Danh sách liên kết đơn (tt)
Trang 50DANH SÁCH LIÊN KẾT ĐÔI
(KÉP)
(DOUBLE LINKED LIST)
Trang 514.3 Danh sách liên kết đôi
(DLL)
Các phần tử của danh sách liên kết đôi có 2 mối liên
kết với các phần tử khác trong danh sách
data
Trang 524.3 Danh sách liên kết đôi (tt)
Cấu trúc dữ liệu của danh sách liên kết đôi:
typedef struct Node
Trang 534.3 Danh sách liên kết đôi (tt)
4.3.1 Quản lý danh sách liên kết liên kết đôi:
Để quản lý danh sách ta quản lý địa chỉ đầu và cuối
Trang 544.3 Danh sách liên kết đôi (tt)
Giả sử ta có các khai báo sau:
typedef struct Node
Trang 554.3 Danh sách liên kết đôi (tt)
4.3.2 Thao tác trên danh sách liên kết đôi
a. Khởi tạo danh sách liên kết đôi
b. Tạo mới 1 phần tử
c. Thêm 1 phần tử vào danh sách
d. Duyệt qua các nút trong 1 danh sách
e. Tìm kiếm 1 phần tử trong danh sách
f. Loại bỏ 1 phần tử trong danh sách
g. Hủy toàn bộ danh sách
h. Tạo 1 danh sách mới/Nhập danh sách
i. Tách 1 danh sách thành nhiều danh sách
j. Nhập nhiều danh sách thành 1 danh sách
k. Sắp xếp thứ tự thành phần dữ liệu trong danh sách
l. Sao chép 1 danh sách thành 1 danh sách mới
Trang 564.3 Danh sách liên kết đôi (tt)
4.3.2.a Khởi tạo danh sách liên kết đôi
Cho giá trị các con trỏ quản lý địa chỉ 2 nút đầu và cuối
danh sách liên kết đôi về NULL
void init(List &L)
{
L.First = NULL;
L.Last = NULL;
}
Trang 574.3 Danh sách liên kết đôi (tt)
4.3.2.b Tạo mới 1 phần tử
Tạo nút mới có thành phần dữ liệu là x
Thuật toán
B1: p = new Node //cấp phát bộ nhớ cho con trỏ p
B2: IF(p == NULL) // cấp phát không thành công
Trang 584.3 Danh sách liên kết đôi (tt)
4.3.2.b Tạo mới 1 phần tử: Cài đặt:
Node* getnode(int x)
Trang 594.3 Danh sách liên kết đôi (tt)
4.3.2.c Thêm 1 phần tử vào danh sách (Thêm đầu)
Trang 604.3 Danh sách liên kết đôi (tt)
4.3.2.c Thêm 1 phần tử vào danh sách (Thêm đầu)
B4: NewNode ->Next = L.First
B5: L First ->Pre = NewNode
// chuyển vai trò đứng đầu của NewNode cho First
B6: L.First = NewNode
BKT: Kết thúc
Trang 614.3 Danh sách liên kết đôi (tt)
4.3.2.c Thêm 1 phần tử vào danh sách (Thêm đầu)
Void addfirst (List &L, int x)
NewNode ->Next = L.First;
L.First ->Pre = NewNode;
L.First = NewNode;
} }
}
Trang 624.3 Danh sách liên kết đôi (tt)
4.3.2.c Thêm 1 phần tử vào danh sách (Thêm cuối)
Trang 634.3 Danh sách liên kết đôi (tt)
4.3.2.c Thêm 1 phần tử vào danh sách (Thêm cuối)
B4: L Last ->Next = NewNode
B5: NewNode ->Pre = L.Last
// chuyển vai trò đứng đầu của NewNode cho First
B6: L Last = NewNode
BKT: Kết thúc
Trang 644.3 Danh sách liên kết đôi (tt)
4.3.2.c Thêm 1 phần tử vào danh sách (Thêm cuối)
void insertlast(List &L, int X){
Node* NewNode = getnode(X);
if (NewNode != NULL){
if (l.Last == NULL)
L.First = L.Last = NewNode;
else{
L.Last ->Next = NewNode;
NewNode ->Pre = L.Last;
L.Last = NewNode;
}}
}
Trang 654.3 Danh sách liên kết đôi (tt)
4.3.2.c Thêm 1 phần tử vào danh sách (Thêm giữa)
Chèn một phần tử có data là X vào ngay sau nút
được trỏ bởi q:
Trang 664.3 Danh sách liên kết đôi (tt)
4.3.2.c Thêm 1 phần tử vào danh sách (Thêm giữa)
Thêm vào sau nút đang trỏ bởi q
B4: NewNode ->Next = q ->Next
B5: q ->Next ->Pre = NewNode
B6: q ->Next = NewNode
B7: NewNode ->Pre = q
BKT: Kết thúc
Trang 674.3 Danh sách liên kết đôi (tt)
Node* NewNode = getnode (X);
NewNode ->Next = q ->Next;
q ->Next ->Pre = NewNode;
q ->Next = NewNode;
NewNode ->Pre = q;
} }
}
Trang 684.3 Danh sách liên kết đôi (tt)
4.3.2.c Thêm 1 phần tử vào danh sách (Thêm giữa)
Chèn một phần tử có trường data là X vào trước
nút được trỏ bởi q:
Trang 694.3 Danh sách liên kết đôi (tt)
4.3.2.d Duyệt qua các nút trong 1 danh sách
Trang 704.3 Danh sách liên kết đôi (tt)
4.3.2.d Duyệt qua các nút trong 1 danh sách
Cài đặt thuật toán:
void ouput (List L)
{
Node* P = L.First;
while (P!= NULL){
cout<<P->data<<setw(5);
P = P ->Next;
}}
Trang 714.3 Danh sách liên kết đôi (tt)
4.3.2.e Tìm kiếm 1 phần tử trong danh sách
Giả sử cần tìm kiếm trong danh sách liên kết đơn
Trang 724.3 Danh sách liên kết đôi (tt)
4.3.2.e Tìm kiếm 1 phần tử trong danh sách
Cài đặt thuật toán:
Node* search(List L, int X)
{
Node* P = L.First;
while (P!= NULL){
if (P->data == X)
break;
P = P ->Next}
return (P);
}
Trang 734.3 Danh sách liên kết đôi (tt)
4.3.2.f Loại bỏ 1 phần tử trong danh sách
Thuật toán
B1: Del = Timkiem(L, X) // Tìm kiếm nút DelData
B2: IF(Del== NULL)
Thực hiện BKT
B3: IF(Del->Pre=NULL AND Del->Next=NULL)
B3.1: L.First = L.Last = NULL
B3.2: Thực hiện B8
B4: IF (Del ->Pre = NULL) // Loại nút đầu tiên trong DS
B4.1: L.First = L.First ->Next
B4.2: L.First ->Pre = NULL
B4.3: Thực hiện B8
Trang 744.3 Danh sách liên kết đôi (tt)
4.3.2.f Loại bỏ 1 phần tử trong danh sách
Thuật toán
B5: IF (Del ->Next = NULL) // Loại nút cuối trong DS
B4.1: L.Last = L.Last ->Pre
B4.2: L.Last ->Next= NULL
B4.3: Thực hiện B8
// Liên kết giữa nút trước và sau nút bị xóa
B6: Del->Pre ->Next = Del->Next
B7: Del->Next->Pre= Del->Pre
// Bỏ mối liên kết giữa Del giữa 2 nút trước & sau
B8: Del->Next = Del ->Pre= NULL
B9: delete Del
BKT: Kết thúc
Trang 754.3 Danh sách liên kết đôi (tt)
Cài đặt thuật toán:
int DeleteNode (List &L, int X){
Node* Del = search(L, X)
Trang 764.3 Danh sách liên kết đôi (tt)
if (Del ->Next ==NULL){
L.Last = L.Last ->Pre ; L.Last ->Next = NULL;
}else{
Del ->Pre ->Next = Del ->Next;
Del ->Next ->Pre = Del ->Pre ;}
del->next=del->pre=NULL;
free(del);
return 1;
}
Trang 774.3 Danh sách liên kết đôi (tt)
4.3.2.g Hủy toàn bộ danh sách
Thực hiện nhiều lần thao tác hủy một nút
B5: L.First ->Pre = NULL
B6: Temp ->Next = NULL
B7: delete Temp
B8: Lặp lại B1
BKT: Kết thúc
Trang 784.3 Danh sách liên kết đôi (tt)
4.3.2.g Hủy toàn bộ danh sách (tt)
Cài đặt thuật toán
void DeleteList (List &L){
Node* Temp = L.First;
while (Temp!= NULL){
L.First = L.First ->Next;
Temp ->Next = NULL;
Trang 794.3 Danh sách liên kết đôi (tt)
4.3.2.h Tạo 1 danh sách mới/Nhập danh sách
Trang 804.3 Danh sách liên kết đôi (tt)
4.3.2.h Tạo 1 danh sách mới/Nhập danh sách
Cài đặt thuật toán
void CreateList(List &L, int n)
Trang 814.3 Danh sách liên kết đôi (tt)
void DLLBubbleSort (List &L){
Node* Inode = L.First;
if (Inode == NULL)
return;
while (Inode != L.Last){
Node* Jnode = L.Last;
while (Jnode != Inode){
if (Jnode->Key < Jnode ->Pre->Key)
Trang 824.3 Danh sách liên kết đôi (tt)
4.3.2.l Sao chép 1 danh sách thành 1 danh sách mới
Trang 834.3 Danh sách liên kết đôi (tt)
4.3.2.l Sao chép 1 danh sách thành 1 danh sách mới
Cài đặt thuật toán
List DLLCopy (List &L, List &NewList)
return (NewList);
}
Trang 844 Danh sách liên kết
4.4 Ưu nhược điểm của danh sách liên kết
Nhược điểm
◦ Mật độ sử dụng bộ nhớ của danh sách liên kết
không tối ưu tuyệt đối (<100%)
◦ Việc truy xuất và tìm kiếm các phần tử trong
danh sách liên kết mất nhiều thời gian vì phải duyệt tuần tự qua các phần tử trong danh sách
◦ Bộ nhớ cần nhiều vì phải lưu thêm phần tử liên
kết, nếu vùng dữ liệu là lớn thì tỷ lệ mức sử dụng bộ nhớ là cao
Trang 85◦ Việc thêm, xóa phần tử trong danh sách liên kết
là dễ dàng, chỉ cần thay đổi mối liên kết của các phần tử với nhau