You are on page 1of 22

Vấn đề kiểu dữ liệu tĩnh

6
CHƯƠNG 4
DANH SÁCH LIÊN KẾT 10
15
7 9
5 3 2 1
1 2 3 4 5 6 7 8
Biên soạn: ThS.Phạm Văn Đăng
Email: pvdang@ntt.edu.vn ? Làm sao để chèn thêm số 6 vào vị trí 5 của mảng

Mục tiêu
Vấn đề kiểu dữ liệu tĩnh
 Nắm vững khái niệm về kiểu dữ liệu tĩnh
và động 6
 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
? Giả sử cần thêm tiếp 1 phần tử
15
10 9
5 7
thao tác xử lý trên danh sách liên kết đơn 3 2 1
1 2 3 4 5 6 7 8 9
 Cài đặt minh họa được các thao tác của
danh sách đơn bằng ngôn ngữ Java Bổ sung thêm
2 4
Bài tập Vấn đề kiểu dữ liệu tĩnh

Hãy cài đặt hàm (bằng ngôn ngữ Java) chèn


một phần tử có giá trị x vào vị trí vt trong
mảng số nguyên a, kích thước n, theo mẫu hàm
như sau:
15
10 9
void ChenX(int a[], int n, int x, int vt); 5 7
3 2 1
1 2 3 4 5 6 7 8

5 7

Vấn đề kiểu dữ liệu tĩnh Bài tập

Hãy cài đặt hàm (bằng ngôn ngữ Java) xóa


phần tử có giá trị x (nếu có) trong mảng số
nguyên a, kích thước n (giả sử giá trị các
15 phần tử trong mảng không trùng nhau), theo
10 9
5 7 mẫu hàm như sau:
3 2 1
1 2 3 4 5 6 7 8
void XoaX (int a[], int n, int x);

? Làm sao để xóa phần tử 9


6 8
Vấn đề kiểu dữ liệu tĩnh Cấp phát
 Biến động – Dynamic variable
 Cấp phát bộ nhớ: new int [kích thước]
Độ phức tạp của chèn/ xóa  Ví dụ:
trên mảng 1 chiều là O(n)
int a[];
a=new int [10]; // Cấp phát

9 11

Vấn đề kiểu dữ liệu tĩnh Danh sách liên kết (DSLK)


 Giải quyết vấn đề phức tạp khi chèn/xóa? 1 Các phần tử kết
dính với nhau bằng
 Giải quyết vấn đề giới hạn kích thước vùng “sợi dây liên kết”
nhớ tối đa? 7
2
 Giải quyết vấn đề vùng nhớ không liên tục?
6
 Giải quyết vấn đề giải phóng vùng nhớ khi
không cần dùng đến? 3
10
8
5
DÙNG CẤU TRÚC DỮ LIỆU ĐỘNG 9
10
4 12
1

7 Đặc điểm DSLK


2
6  Thao tác Chèn/Xóa không cần phải dịch
chuyển phần tử mà chỉ cần thay đổi mối liên
3 kết
10  Quản lý phần tử đầu tiên bằng Nodes start
8 Để đơn giản  Quản lý phần tử cuối bằng Nodes end
5 hơn trong việc
9  Có thể truy xuất đến các phần tử khác thông
minh họa qua Nodes liên kết: link
4

13 15

Cấu tạo của DSLK


Đặc điểm DSLK
 Một dãy tuần tự các nút (Node)
 Giữa hai nút có Nodes liên kết
 Các nút không cần phải lưu trữ liên tiếp nhau
trong bộ nhớ
Node
 Có thể mở rộng tuỳ ý (chỉ giới hạn bởi dung
lượng bộ nhớ)

start end
LinkedLists
14 16
Thao tác xóa node khỏi DSLK
Cấu tạo của nút
Cần xóa
 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)
 Nodes liên kết đến phần tử kế tiếp trong
danh sách (Next pointer link): link
 Nếu không chỉ đến phần tử nào thì Nodes
Node
link = null
data
start end
link
17
LinkedLists 19

Thao tác chèn thêm node vào DSLK


Các loại hình DSLK
 “Kết nối” lại sợi dây liên kết theo trình tự
DSLK đơn: Các phần tử kết nối với nhau theo
hướng “chiều đi tới”

start end
LinkedLists
18 20
So sánh Mảng và DSLK
Các loại hình DSLK
Mảng Danh sách liên kết
DSLK đôi: Các phần tử kết nối với nhau theo
hướng “chiều đi tới và và đi lui” Số phần tử thay đổi tùy
Kích thước cố định
ý
Các phần tử lưu trữ tuần Các phần tử liên kết với
tự (địa chỉ tăng dần) nhau bằng Nodes liên
trong bộ nhớ kết
Phải dịch chuyển các Chỉ cần thay đổi Nodes
phần tử khi Thêm/Xóa liên kết khi Thêm/Xóa
Truy xuất ngẫu nhiên Truy xuất tuần tự
21
23

DSLK đơn
Các loại hình DSLK

Danh sách liên kết vòng: Các phần tử kết nối link
data
vớ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 Cấu trúc 1 node

start end data : Dữ liệu của Nodes


LinkedLists link : Chỉ đến node kế tiếp DSLK
start : Chỉ đến node đầu DSLK
end : Chỉ đến node cuối DSLK
22
24
Khai báo cấu trúc node lưu thông tin SV
Khai báo cấu trúc Nodes link
ID, hoten, dtb,…

link public class SINHVIEN


data
{
protected String ID, hoten, phai, dc, email;
float dtb;
constructors and methods…
}
public class Nodes public class Nodes
{ {
protected <KDL> data; protected SINHVIEN data;
protected Nodes link; protected Nodes link;
constructors and methods… constructors and methods…
} 25 } 27

Khai báo cấu trúc node lưu số nguyên Khai báo cấu trúc DSLK đơn

link LinkedLists
20

start end
public class Nodes
{ public class LinkedLists
protected int data; {
protected Nodes link; protected Nodes start, end;
constructors and methods… protected int size;
} constructors and methods…
26 } 28
Khai báo cấu trúc DSLK đơn Các thao tác trên DSLK đơn
Lớp Nodes:
 Khai báo biến chứa dữ liệu của Nodes
LinkedLists  Khai báo biến link đến Nodes kế
 Hàm tạo Nodes không tham số
start end  Hàm tạo Nodes có 2 tham số
public class Nodes public class LinkedLists
 Hàm đặt liên kết đến Nodes kế
{ {  Hàm gán giá trị cho Nodes hiện hành
protected int data; protected Nodes start, end;
protected Nodes link; protected int size;
 Hàm trả về link đến Nodes kế
constructors and methods… constructors and methods…  Hàm trả về dữ liệu của Nodes hiện hành
} }
31
29

Khai báo cấu trúc DSLK đơn Các thao tác trên DSLK đơn
Lớp LinkedLists:
 Khai báo Nodes start chỉ đến Nodes đầu DSLK
 Khai báo Nodes end chỉ đến Nodes cuối DSLK
LinkedLists  Khai báo biến cho biết kích thước của DSLK
 Hàm tạo danh sách liên kết rỗng
 Hàm kiểm tra DSLK rỗng
start end
 Hàm lấy kích thước DSLK
public class Nodes public class BTList  Hàm chèn 1 phần tử vào đầu DSLK
{ … {  Hàm chèn 1 phần tử vào cuối DSLK
public static void main(…)  Hàm duyệt DSLK
}
{  Hàm chèn 1 phần tử tại vị trí Pos trong DSLK
public class LinkedLists …
{ …  Hàm xóa 1 phần tử tại vị trí Pos trong DSLK
}
} }
32
30
Các thao tác trên DSLK đơn
Hàm kiểm tra DSLK rỗng
Lớp BTList:
 Gọi các hàm tạo ở lớp Nodes và LinkiedLists LinkedLists
start end
 Gọi các hàm ở lớp Nodes và LinkiedLists
Danh sách rỗng

public boolean isEmpty()


{ if (start==null)
return true;
return start ==null; else
return false;
}
33 35

Chèn 1 phần tử vào đầu DSLK


Hàm tạo danh sách rỗng
start và end chưa start và end trỏ vào TH danh sách rỗng
xác định null (rỗng) start = p

LinkedLists ? ? LinkedLists
start end start end LinkedLists 30
Trước khi tạo lập Sau khi tạo lập start end
end = p p
public LinkedLists()
{
start = end = null;
size = 0;
} 34 36
Chèn một phần tử vào DSLK TH chèn một nút vào đầu danh sách
TH danh sách đã có phần tử

LinkedLists 30 25
start end

LinkedLists 30 25
start end
p
Vẽ lại
Có 2 trường hợp để chèn p
1.Chèn p vào đầu (insertAtStart)
2.Chèn p vào cuối (insertAtEnd) LinkedLists 25 30
start end
37 39

TH chèn một nút vào đầu danh sách TH chèn một nút vào đầu danh sách
2
1
2 LinkedLists 30 25
1 start end
p
LinkedLists 30 25
start end
p
1 p.setLink(start)
2 start = p
38 40
TH chèn một nút vào đầu danh sách TH chèn một nút vào đầu danh sách
1
Hãy viết hàm thêm phần tử p vào
LinkedLists 30 25 đầu danh sách (bằng ngôn ngữ Java),
start end theo mẫu sau:
p public void insertAtStart(int val)
2

1 start = p
2 p.setLink(start)
41 43

TH chèn một nút vào đầu danh sách TH chèn một nút vào cuối danh sách

Hãy vẽ lại “đường kết nối” theo


thứ tự thích hợp khi thêm p
vào đầu danh sách LinkedLists 30 1 25
start end
p
2

25 30 42 1 end.setLink(p)
start end
LinkedLists p 2 end = p
42 44
TH chèn một nút vào cuối danh sách TH chèn một nút tại vị trí Pos trong DSLK

Hãy vẽ lại “đường kết nối” theo


thứ tự thích hợp khi thêm p
vào cuối danh sách

30 25 42
start end
LinkedLists p
45 47

TH chèn một nút vào cuối danh sách TH chèn một nút tại vị trí Pos trong DSLK
public void insertAtPos(int val , int pos) {
Nodes nptr = new Nodes(val, null);
Nodes ptr = start;
Hãy viết hàm thêm phần tử p vào pos = pos - 1;
if(pos==0) { nptr.setLink(start); start = nptr;}
cuối danh sách (bằng ngôn ngữ Java), else
for (int i = 1; i < size; i++)
theo mẫu sau: {
public void insertAtEnd(int val) if (i == pos)
{
Nodes tmp = ptr.getLink();
ptr.setLink(nptr);
nptr.setLink(tmp);
break;
}
ptr = ptr.getLink();
}
size++;
46 48
}
TH xóa một nút tại vị trí Pos trong DSLK TH xóa một nút tại vị trí Pos trong DSLK
Nodes ptr = start; //xóa tại vị trí Pos
pos = pos - 1;
for (int i = 1; i < size - 1; i++){
if (i == pos){
Nodes tmp = ptr.getLink();
tmp = tmp.getLink();
TH3 ptr.setLink(tmp);
break;
}
ptr = ptr.getLink();
}
size-- ;
}

49 51

TH xóa một nút tại vị trí Pos trong DSLK Yêu cầu:
public void deleteAtPos(int pos) { Sinh viên vẽ hình cho trường hợp xóa
if (pos == 1) { //xóa tại vị trí start
Nodes tmp = start; ở đầu, ở cuối.
start = start.getLink();
TH1 tmp.setLink(null);
size--;
return ;
}
if (pos == size) { //xóa tại vị trí end
Nodes s = start;
Nodes t = start;
while (s != end) {
t = s;
s = s.getLink();
TH2 }
end = t;
end.setLink(null);
size --;
return; 50 52

}
Nhập dữ liệu vào danh sách
Nhập dữ liệu vào danh sách
Hàm tạo Nodes có 2 tham số
public Nodes(int d, Nodes n)
{
Nhập kích thước DSLK data = d;
link = n;
}

Nhập dữ liệu cho node Cách sử dụng:


Nodes p = new Nodes(30, null);

Thêm node vào DSLK 30

53 55

Nhập dữ liệu vào danh sách


Nhập dữ liệu vào danh sách Hàm chèn 1 phần tử vào đầu DSLK
public void insertAtStart(int val)
Để tạo node mới từ dữ liệu d có sẵn {
Nodes p = new Nodes(val, null);
 Đưa dữ liệu có giá trị d vào phần data ++size;
 Nodes link chỉ đến null if(start==null)
{
start = p;
data = d end = p;
}
data d else
{
link = null p.setLink(start);
start = p;
54
} 56
}
Nhập dữ liệu vào danh sách Bài tập 1
Hàm nhập dữ liệu cho danh sách số nguyên và đưa vào
đầu danh sách: Cài đặt các hàm sau trên DSLK đơn số nguyên:
public void NhapDL()
1. Chèn phần tử ở đầu DSLK
{ 2. Chèn phần tử ở đuôi DSLK
Scanner sc = new Scanner(System.in);
System.out.print("Nhập kích thước của DSLK: "); 3. Chèn phần tử tại vị trí (2,3,4,…)
int n = sc.nextInt(); 4. Xóa phần tử tại vị trí bất kỳ
for(int i=1; i<=n; i++)
{ 5. Tính kích thước DSLK
System.out.print("Nhập node vào DSLK: "); 6. Xuất các node của DSLK
int val = sc.nextInt();
insertAtStart(val); 7. Chèn một nút tại vị trí Pos trong DSLK
} 8. Xóa một nút tại vị trí Pos trong DSLK
}
57 59

Bài tập 2
Xuất dslk
Cài đặt các hàm sau trên DSLK đơn số nguyên:
p 1. Đếm số lượng node trong DSLK
2. Tìm node có giá trị lớn nhất
3. Tìm node có giá trị x
4. In những node có giá trị chẵn
5. Tính giá trị trung bình cộng các node lẻ
6. Tìm node có giá trị âm nhỏ nhất
start end 7. Tìm node có giá trị dương lớn nhất
LinkedLists
8. Sắp xếp danh sách tăng dần
58 60
Đoạn chương trình mẫu: class Nodes Đoạn chương trình mẫu: class LinkedLists

61 63

Đoạn chương trình mẫu: class Nodes Đoạn chương trình mẫu: class LinkedLists

62 64
Đoạn chương trình mẫu: class LinkedLists Đoạn chương trình mẫu: class LinkedLists

65 67

Đoạn chương trình mẫu: class LinkedLists Đoạn chương trình mẫu: class BTList

66 68
Đoạn chương trình mẫu: class BTList
Bài tập 3
Sử dụng DSLK đơn để quản lý thông tin SV gồm: Masv,
Hoten, Ngaysinh, Gioitinh, DTB,…
1. Xây dựng cấu trúc lớp SINHVIEN
2. Xây dựng cấu trúc lớp Nodes
3. Xây dựng cấu trúc LinkedList
4. Nhập danh sách sinh viên
5. Xuất danh sách sinh viên
6. Tìm sinh viên theo mã số sinh viên
7. Tìm sinh viên có DTB lớn nhất
8. Tìm sinh viên có DTB nhỏ nhất
9. Sắp xếp danh sách sinh viên giảm dần theo DTB
69 71

Đoạn chương trình mẫu: class BTList DANH SÁCH LIÊN KẾT ĐÔI
Doubly Linked List
Đặc điểm:
 DSLK có 2 liên kết, một chỉ đến phần tử đứng trước và
một chỉ đến phần tử đứng sau.

Ưu điểm:
 DSLK đôi có thể di chuyển theo cả hai hướng tiến và lùi.
 Thao tác xóa, chèn trong DSLK đôi là hiệu quả hơn.

70 72
DANH SÁCH LIÊN KẾT ĐÔI Tổ chức các lớp cho DSLK đôi
Doubly Linked List
Lớp Node:
 Khai báo biến chứa dữ liệu
1. Xây dựng lớp Node
 Khai báo Node liên kết sau, trước 2. Xây dựng lớp LinkedList
 Hàm tạo DSLK rỗng 3. Xây dựng lớp BTDList
 Hàm tạo DSLK gồm data, liên kết sau, trước
 Hàm tạo liên kết đến Node kế (sau)
 Hàm tạo liên kết đến Node trước
 Hàm lấy liên kết đến Node kế (sau)
 Hàm lấy liên kết đến Node trước
 Hàm gán dữ liệu cho data
 Hàm lấy dữ liệu từ data
73 75

DANH SÁCH LIÊN KẾT ĐÔI Đoạn chương trình mẫu: class Node
Doubly Linked List /* Khai báo Class Node */
class Node
Lớp LinkedList: {
protected int data; //Khai báo phần dữ liệu
 Khai báo biến chứa dữ liệu protected Node next, prev; //Khai báo phần liên kết sau, trước
 Khai báo Node liên kết sau, trước
/* hàm Constructor */
 Hàm tạo DSLK rỗng public Node()
 Hàm tạo DSLK gồm data, liên kết sau, trước {
next = null;
 Hàm tạo liên kết đến Node kế (sau) prev = null;
 Hàm tạo liên kết đến Node trước data = 0;
}
 Hàm lấy liên kết đến Node kế (sau) /* hàm Constructor */
 Hàm lấy liên kết đến Node trước public Node(int d, Node n, Node p)
{
 Hàm gán dữ liệu cho data data = d;
next = n;
 Hàm lấy dữ liệu từ data prev = p;
74 } 76
Đoạn chương trình mẫu: class Node Đoạn chương trình mẫu: class LinkedList
/* Function to set link to next node */ /* Class linkedList */
public void setLinkNext(Node n) class linkedList
{ {
next = n; protected Node start; //Chỉ đến phần tử đầu của DSLK
} protected Node end ; //Chỉ đến phần tử cuối của DSLK
/* Function to set link to previous node */ public int size; //Cho biết kích thước của DSLK
public void setLinkPrev(Node p) public linkedList() /* hàm khởi tạo DSLK rỗng */
{ {
prev = p; start = null;
} end = null;
/* Funtion to get link to next node */ size = 0;
public Node getLinkNext() }
{ /* Function to check if list is empty */
return next; public boolean isEmpty()
} {
/* Function to get link to previous node */ return start == null;
public Node getLinkPrev() }
{ public int getSize() /* Function to get size of list */
return prev; {
} return size;
77 79
}

Đoạn chương trình mẫu: class Node Đoạn chương trình mẫu: class LinkedList
/* Function to set data to node */ /* Function to insert element at begining */
public void setData(int d) public void insertAtStart(int val)
{ {
data = d; Node nptr = new Node(val, null, null);
} if(start == null)
/* Function to get data from node */ {
public int getData() start = nptr;
{ end = start;
return data; }
} else
} {
start.setLinkPrev(nptr);
nptr.setLinkNext(start);
start = nptr;
}
size++;
}

78 80
Đoạn chương trình mẫu: class LinkedList Đoạn chương trình mẫu: class LinkedList
/* Function to insert element at end */ /* Function to delete node at position */
public void insertAtEnd(int val) public void deleteAtPos(int pos)
{ {
Node nptr = new Node(val, null, null); if (pos == 1) {
if(start == null) if (size == 1) {
{ start = null;
start = nptr; end = null;
end = start; size = 0;
} return;
else }
{ start = start.getLinkNext();
nptr.setLinkPrev(end); start.setLinkPrev(null);
end.setLinkNext(nptr); size--;
end = nptr; return ;
} }
size++; if (pos == size){
} end = end.getLinkPrev();
end.setLinkNext(null);
size-- ;
}
81 83

Đoạn chương trình mẫu: class LinkedList Đoạn chương trình mẫu: class LinkedList
/* Function to insert element at position */ Node ptr = start.getLinkNext();
public void insertAtPos(int val , int pos) for (int i = 2; i <= size; i++) {
{ if (i == pos) {
Node nptr = new Node(val, null, null); Node p = ptr.getLinkPrev();
if (pos == 1) { Node n = ptr.getLinkNext();
insertAtStart(val);
return; p.setLinkNext(n);
} n.setLinkPrev(p);
Node ptr = start; size-- ;
for (int i = 2; i <= size; i++) { return;
if (i == pos) { }
Node tmp = ptr.getLinkNext(); ptr = ptr.getLinkNext();
ptr.setLinkNext(nptr); }
nptr.setLinkPrev(ptr); }
nptr.setLinkNext(tmp);
tmp.setLinkPrev(nptr);
}
ptr = ptr.getLinkNext();
}
size++ ; 82 84

}
Đoạn chương trình mẫu: class LinkedList
/* Function to display status of list */
public void display() {
System.out.print("\nDoubly Linked List = ");
if (size == 0) {
System.out.print("Danh sách liên kết rỗng!\n");
return;
}
if (start.getLinkNext() == null) {
System.out.println(start.getData() );
return;
}
Node ptr = start;
System.out.print(start.getData()+ " <-> ");
ptr = start.getLinkNext();
while (ptr.getLinkNext() != null) {
System.out.print(ptr.getData()+ " <-> ");
ptr = ptr.getLinkNext();
}
System.out.print(ptr.getData()+ "\n");
}
85
}

You might also like