Chương 3 cung cấp kiến thức về danh sách liên kết. Chương này giúp người học nắm vững khái niệm về kiểu dữ liệu tĩnh và động, nắm vững cách tổ chức dữ liệu động bằng danh sách liên kết và minh họa được các thao tác xử lý trên danh sách liên kết đơn, cài đặt minh họa được các thao tác của danh sách đơn bằng ngôn ngữ C/C++. Mời các bạn cùng tham khảo.
Trang 1CHƯƠNG 3
Võ Quang Hoàng Khang
Email: vqhkhang@gmail.com
Trang 2Mục tiêu
Nắm vững khái niệm về kiểu dữ liệu tĩnh
và động
Nắm vững cách tổ chức dữ liệu động bằngdanh sách liên kết và minh họa được cácthao tác xử lý trên danh sách liên kết đơn
Cài đặt minh họa được các thao tác của
Trang 5Bài tập
một phần tử có giá trị x vào vị trí vt trongmảng số nguyên a, kích thước n, theo mẫu hàmnhư sau:
void ChenX(int a[], int &n, int x, int vt);
Trang 8Bài tập
phần tử trong mảng không trùng nhau), theomẫu hàm như sau:
void XoaX (int a[], int &n, int x);
Trang 9Vấn đề kiểu dữ liệu tĩnh
Độ phức tạp của chèn/ xóa trên mảng 1 chiều là O(n)
i
Trang 10Vấn đề kiểu dữ liệu tĩnh
Giải quyết vấn đề phức tạp khi chèn/ xóa?
Giải quyết vấn đề giới hạn kích thước vùng
nhớ tối đa?
Giải quyết vấn đề vùng nhớ không liên tục?
Giải quyết vấn đề giải phóng vùng nhớ khi
không cần dùng đến?
Trang 11Biến tĩnh và biến động trong C++
Biến tĩnh
<kiểu dữ liệu> tên biến;
Vd: int a; float y; char s[20];
Tồn tại trong phạm vi khai báo
Được cấp phát vùng nhớ trong vùng dữ liệu
Kích thước cố định
Trang 12Biến tĩnh và biến động trong C++
Biến động
<kiểu dữ liệu> *tên biến;
Vd: int *a; float *y;
Chứa địa chỉ của một đối tượng dữ liệu
Được cấp phát hoặc giải phóng bộ nhớ tùy
thuộc vào người lập trình
Kích thước có thể thay đổi
Trang 13Biến tĩnh và biến động trong C++
Trang 14Danh sách liên kết (DSLK)
1
7 2 6
3 10 8 5 9
Các phần tử kết dính với nhau bằng
“sợi dây liên kết”
Trang 16Đặc điểm DSLK
Một dãy tuần tự các nút (Node)
Giữa hai nút có con trỏ liên kết
Các nút không cần phải lưu trữ liên tiếp nhautrong bộ nhớ
Có thể mở rộng tuỳ ý (chỉ giới hạn bởi dunglượng bộ nhớ)
Trang 17Đặc điểm DSLK
Thao tác Chèn/Xóa không cần phải dịchchuyển phần tử mà chỉ cần thay đổi mối liênkết
Quản lý phần tử đầu tiên bằng con trỏ pHead
Có thể truy xuất đến các phần tử khác thôngqua con trỏ liên kết
Trang 18Cấu tạo của DSLK
pHead pTail
List
Trang 19Cấu tạo của DSLK
Quản lý toàn bộ danh sách liên kết thông qua
pHead không phải là 1 nút, nó chỉ là “con trỏ
chỉ đến nút” mà thôi
Ta cũng có thể quản lý danh sách bằng cách
sử dụng thêm con trỏ cuối (pTail)
pTail không phải là 1 nút, nó chỉ là “con trỏ
chỉ đến nút” mà thôi
Trang 20Cấu tạo của nút
Tạo lập bằng cách cấp phát bộ nhớ động
Mỗi nút có 2 thông tin:
Dữ liệu (data)
Con trỏ liên kết đến phần tử kế tiếp trong
danh sách (Next pointer link)
Nếu không trỏ đến phần tử nào thì con trỏ
Next = NULL
Trang 21Thao tác chèn thêm node vào DSLK
“Kết nối” lại sợi dây liên kết theo trình tự
pHead pTail
List
Trang 22Thao tác xóa node khỏi DSLK
Cần xóa
pHead pTail
List
Trang 23Các loại DSLK
DSLK đơn: Các phần tử kết nối với nhau theohướng “chiều đi tới”
Trang 24Các loại hình DSLK
DSLK đôi: Các phần tử kết nối với nhau theohướng “chiều đi tới và và đi lui”
Trang 25Các loại hình DSLK
Danh sách liên kết vòng: Các phần tử kết nốivới nhau theo hướng “chiều đi tới” và phần tửcuối cùng có “đường đi vòng trở lại tới” phần
tử đầu danh sách
Trang 26Phải dịch chuyển các
phần tử khi Thêm/Xóa
Chỉ cần thay đổi con trỏliên kết khi Thêm/Xóa
Trang 27DSLK đơn
Cấu trúc 1 node
Data pNext
Data : Dữ liệu của node
pNext : Con trỏ đến node kế tiếp
pHead : Con trỏ đến node đầu
pHead pTail
List
Trang 28Khai báo cấu trúc node
struct tNODE
{
<kiểu dữ liệu> Data;
struct tNODE *pNext;
};
Data
pNext
Trang 29Khai báo cấu trúc node lưu số nguyên
Trang 30Khai báo cấu trúc node lưu thông tin SV
typedef struct tSinhVien SINHVIEN;
ID, hoten, dtb pNext
Trang 31Khai báo cấu trúc DSLK đơn
Trang 32Khai báo cấu trúc DSLK đơn
Trang 33Các thao tác trên DSLK đơn
Thêm 1 nút vào danh sách: đầu, cuối, sau ptử q
Duyệt danh sách
Xóa 1 nút: đầu, cuối, nút có giá trị x
Tìm 1 phần tử
Sắp xếp danh sách
Trang 34Tạo lập danh sách rỗng Nhập dữ liệu vào danh sách Các thao tác xử lý trên danh sách Hủy danh sách
}
4
Trang 35Tạo lập danh sách rỗng
void CreateEmptyList(LIST &L)
{
Sau khi tạo lập
Trang 36Kiểm tra danh sách rỗng
Trang 37Thêm một nút vào danh sách
Trang 38Thêm một nút vào danh sách
TH danh sách đã có phần tử
pHead pTail
pNew
Có 2 trường hợp để thêm pNew
1.Thêm pNew vào đầu (AddHead)
2.Thêm pNew vào cuối (AddTail)
Trang 39TH Thêm một nút vào đầu danh sách
pHead pTail
pNew
1 2
Trang 40TH Thêm một nút vào đầu danh sách
pHead pTail
Vẽ lại
Trang 41TH Thêm một nút vào đầu danh sách
Trang 42TH Thêm một nút vào đầu danh sách
pNew->pNext = list.pHeadlist.pHead = pNew
1
2
Trang 43TH Thêm một nút vào đầu danh sách
Hãy viết hàm thêm phần tử pNew vàođầu danh sách (bằng ngôn ngữ C/C++), theo mẫu sau:
void AddHead(LIST &L, NODE *pNew)
?
Trang 44TH Thêm một nút vào cuối danh sách
Trang 45TH Thêm một nút vào cuối danh sách
Trang 46TH Thêm một nút vào cuối danh sách
Hãy viết hàm thêm phần tử pNew vàocuối danh sách (bằng ngôn ngữ C/C++), theo mẫu sau:
void AddTail (LIST &list, NODE *pNew)
?
Trang 47Nhập dữ liệu vào danh sách
Nhập dữ liệu cho node
Tạo con trỏ node
Trang 48Nhập dữ liệu vào danh sách
Để tạo node mới từ dữ liệu x có sẵn
Đưa dữ liệu có giá trị x vào phần Data
Data
pNew
pNew->pNext = NULL
Trang 49Nhập dữ liệu vào danh sách
VD hàm tạo và trả về con trỏ node có chứa giátrị nguyên x bằng ngôn ngữ C++
NODE *CreateNode (int x)
{
NODE *p;
p = new NODE;
if(p == NULL) {
cout<<“Loi cap phat duoc vung nho!";
exit(0);
} p->Data = x;
p->pNext=NULL;
Trang 50Nhập dữ liệu vào danh sách
VD hàm nhập dữ liệu cho danh sách số nguyên
và đưa vào đầu danh sách
void Input(LIST &list)
Trang 51Xuất dslk
pHead pTail
List
p
Trang 52Chèn node vào DSLK đơn
Chèn vào sau node p
pNew p
Trang 53Chèn node vào sau node p
pNew p
Trang 54Các thao tác trên DSLK (tt)
…
Xóa phần tử trong danh sách (đầu, cuối, giữa)
Sắp xếp danh sách
Trang 55Chèn node vào trước node p – Cách 1
pNew p
pPrev
Trang 56Chèn node vào trước node p – Cách 1
Hãy viết hàm tìm và trả về con trỏ node đứng trước con trỏ node p (bằng ngônngữ C/C++), theo mẫu sau:
NODE *PrevNode (LIST list, NODE *p)
?
Trang 57Chèn node vào trước node p – Cách 2
pNew q
Bước 1 Chèn pNew vào sau q
Bước 2 Hoán vị giá trị pNew và q
Trang 58Xóa một nút trong danh sách
Xóa nút đầu của danh sách Ảnh hưởng
Trang 59Xóa một nút trong danh sách
Xóa nút đầu của danh sách
Trang 60Xóa một nút trong danh sách
Hãy viết hàm xóa nút đầu của danh sách(bằng ngôn ngữ C/C++), theo mẫu sau:
void DeleteHead (LIST &list)
(lưu ý trường hợp danh sách chỉ còn 1 node
trước khi xóa)
?
Trang 61Xóa một nút trong danh sách
Xóa nút cuối của danh sách
pHead pTail
Cần xóa
pDel
NODE *pDel = list.pTail
NODE *pPrev = “Tìm node trước pTail”
pPrev
pPrev->pNext = NULL
Trang 62Xóa một nút trong danh sách
Hãy viết hàm xóa nút cuối của danh sách(bằng ngôn ngữ C/C++), theo mẫu sau:
void DeleteTail (LIST &list)
(lưu ý trường hợp danh sách chỉ còn 1 node
trước khi xóa)
?
Trang 63Xóa một nút trong danh sách
Xóa nút giữa của danh sách
Trang 64Xóa một nút trong danh sách
Hãy viết hàm xóa một node bất kỳ trongdanh sách (bằng ngôn ngữ C/C++),
theo mẫu sau:
void DeleteNode (LIST &L, NODE *pDel)
?
Trang 65Xóa một nút trong danh sách
Hãy viết hàm hủy toàn bộ danh sách(bằng ngôn ngữ C/C++), theo mẫu sau:
void DestroyList (LIST &list)
?
Trang 66Bài tập
Cài đặt các hàm sau trên dslk đơn số nguyên:
1 Đếm số lượng node trong dslk
int DemSL(LIST list);
void InChan(LIST list);
5 Tính giá trị trung bình các node lẻ
Trang 676 Chèn node có giá trị x vào phía sau node cógiá trị lớn nhất
void ChenXSauMax(LIST &list, int x);
7 Xóa node có giá trị x
bool XoaX(LIST &list, int x);
8 Sắp tăng dslk
void SapTang(LIST &list);
Trang 68Sắp xếp
void Doichotructiep ( LIST &L )
{
Node *p,*q;
for (p=L.DAU ; p!= L.CUOI ; p=p->tiep )
for (q=p->tiep; q!= NULL ; q=q->tiep)
if ( p->dulieu > q->dulieu)
Hoanvi ( p->dulieu , q->dulieu );
}