Professional Documents
Culture Documents
Nội dung:
I/. Giới thiệu Danh sách liên kết (Linked List)
II/. Danh sách liên kết và mảng
III/. Mô tả DSLK đơn
IV/. Các thao tác trên DSLK đơn (Singly Linked List)
V/. Danh Sách Liên Kết Vòng (Circular Linked List)
VI/. Danh Sách Liên Kết Đôi (Doubly Linked List)
1
I/. Giới thiệu Danh sách liên kết (Linked List):
Một danh sách liên kết là một cấu trúc dữ liệu tuyến tính, trong đó các phần tử không được lưu trữ tại
các vị trí bộ nhớ tiếp giáp nhau. Các phần tử trong danh sách liên kết được liên kết bằng cách sử dụng
con trỏ như được hiển thị trong hình dưới đây:
Một góc nhìn khác, một danh sách liên kết bao gồm các Node trong đó mỗi Node chứa một thành phần
dữ liệu và một thành phần tham chiếu (liên kết) đến Node tiếp theo trong danh sách.
Danh sách liên kết theo hình trên là DSLK đơn II/.
Danh sách liên kết và mảng:
Cả hai mảng và danh sách liên kết đều có thể được sử dụng để lưu trữ dữ liệu tuyến tính, nhưng mỗi
thứ đều có một số ưu điểm và nhược điểm so với nhau.
2
Khuyết điểm của DSLK:
• Truy cập ngẫu nhiên là không thể trong DSLK, phải truy cập từ Node đầu tiên trở đi.
• Cần thêm không gian cấp cho con trỏ của mỗi phần tử (Node).
• Mảng có vị trí liên tục nên thuận lợi cho bộ nhớ Cache tốt hơn DSLK và mảng có hiệu suất cao
hơn DSLK.
III/. Mô tả DSLK đơn:
Một danh sách liên kết được biểu diễn bằng một con trỏ chỉ đến Node đầu tiên của danh sách liên kết.
Node đầu tiên được gọi là Head (đầu). Nếu danh sách liên kết trống, thì giá trị của đầu là NULL.
Mỗi nút trong danh sách bao gồm ít nhất hai phần:
• Phần dữ liệu
• Phần liên kết dùng tham chiếu đến một node tiếp theo
Trong Java, LinkedList có thể được biểu diễn như một lớp (Class) và một Node như một lớp riêng biệt.
Lớp LinkedList chứa một tham chiếu của kiểu lớp Node.
class LinkedList
{ Node head; // head của DSLK
// Khai báo Linked list Node
class Node
{ int data; //phần dữ liệu
Node next; //phần tham chiếu đến Node kế
// Hàm Constructor dùng khởi tạo 1 node mới
// phần tham chiếu được mặc định là NULL
Node(int d)
{ data = d;}
}
Các hàm thao tác khác (các phương thức)…
}
class LinkedList
{ Node head; // phần tử head của DSLK
/* Khai báo lớp cho Node */
3
static class Node
{ int data;
Node next;
1 2 3
1/. Định nghĩa DSLK: định nghĩa Node, định nghĩa DSLK và các phương thức / hàm cơ bản
A/. Phần khai báo cho Node: là phần khai báo cho 1 phần tử gọi là node, còn cần thêm các hàm
Constructor, setlink, setdata, getlink, getdata,… Tạo 1 Class mô tả cho Node.
4
/* Hàm Constructor */
public Nodes()
{
link = null;
data = 0;
}
/* Hàm Constructor */
public Nodes(int d,Nodes n)
{
data = d;
link = n;
}
/* Hàm đặt liên kết đến Node kế */
public void setLink(Nodes n)
{
link = n;
}
/* Hàm gán dữ liệu cho Node hiện hành */
public void setData(int d)
{
data = d;
}
/* Hàm trả về Link đến node kế */
public Nodes getLink()
{
return link;
}
/* Hàm trả về dữ liệu của node hiện hành */
public int getData()
{
return data;
}
}
B/. Phần khai báo cho DSLK: để quản lý DSLK, người cần nắm giữ phần tử start, end và sử dụng
thêm thuộc tính size để theo dõi số phần tử trong DSLK.
Tạo 1 Class định nghĩa danh sách liên kết (đầy đủ)
class linkedLists
{
protected Nodes start; //Chỉ đến phần tử đầu của DSLK
protected Nodes end ; //Chỉ đến phần tử cuối của DSLK public
int size ; //cho biết kích thước của DSLK
5
/* Hàm Constructor */
public linkedLists() //Khởi tạo DSLK rỗng
{
start = null;
end = null; size
= 0;
}
/* Hàm kiểm tra DSLK rỗng */
public boolean isEmpty()
{
return start == null;
}
/* Hàm trả về kích thước của DSLK */
public int getSize()
{
return size;
}
/* Định nghĩa các hàm thực hiện các thao tác trên DSLK*/
}
5 8 12 … 72
start
end
Size: 9
6
3/. Kiểm tra DSLK rỗng:
7
6/. Chèn 1 phần tử vào đuôi DSLK:
/* Thêm 1 phần tử vào đuôi DSLK */
public void insertAtEnd(int val)
{
Nodes nptr = new
Nodes(val,null); size++ ;
if(start == null)
{
start = nptr;
end = start;
}
else
{
end.setLink(nptr);
end = nptr;
}
}
8
7/. Chèn 1 phần tử tại vị trí Pos trong DSLK:
/* Thêm 1 phần tử tại vị trí pos */
public void insertAtPos(int val , int pos)
{
Nodes nptr = new Nodes(val, null); //khởi tạo Node mới
Nodes ptr = start;
pos = pos - 1 ;
for (int i = 1; i < size; i++) // vị trí tính là 1,2,3…
{
if (i == pos)
{
Nodes tmp = ptr.getLink() ;
ptr.setLink(nptr); //ptr trỏ đến nptr
nptr.setLink(tmp); //nptr trỏ đến tmp
break;
}
ptr = ptr.getLink(); //tiến tới node kế
}
size++ ; }
9
start = start.getLink();
size--; //giảm kích thước 1
return ;
}
if (pos == size) //xóa tại vị trí end
{
Nodes s = start;
Nodes t = start;
while (s != end) //đi dần đến phần tử end
{
t = s;
s = s.getLink();
} end
= t;
end.setLink(null);
size --; //giảm kích thước 1
return;
}
Nodes ptr = start; //xóa tại vị trí giữa
pos = pos - 1 ;
for (int i = 1; i < size - 1; i++)
{
if (i == pos)
{
Nodes tmp =
ptr.getLink(); tmp =
tmp.getLink();
ptr.setLink(tmp); break;
}
ptr = ptr.getLink();
}
size-- ; //giảm kích thước 1
}
Vẽ hình ở đây: Sinh viên tự vẽ hình cho trường hợp xóa ở đầu, cuối ptr: phần tử
đứng trước phần tử cần xóa; tmp là phần tử (vị trí pos) cần xóa
10
9/. Duyệt DSLK:
/* Hàm duyệt DSLK */
public void display()
{
System.out.print("\nSingly Linked List = ");
if (size == 0)
{
System.out.print("Danh sách liên kết rỗng!\
n"); return; }
if (start.getLink() == null) //DSLK có 1 phần tử
{
System.out.println(start.getData() );
return;
}
Nodes ptr = start; //duyệt từ start
end System.out.print(start.getData()+ "-
>"); ptr = start.getLink(); while
(ptr.getLink() != null)
{
System.out.print(ptr.getData()+ "->");
ptr = ptr.getLink();
}
System.out.print(ptr.getData()+ "\n");
}
Bài tập DSLK 1: Viết chương trình cài đặt DSLK đơn, có menu chọn công việc như sau:
1. Thêm phần tử ở đầu
2. Thêm phần tử ở đuôi
3. Thêm phần tử theo vị trí (2,3..)
4. Xóa phần tử theo vị trí
5. Duyệt DSLK
6. Kết thúc
Bài tập DSLK 2: Bài tập Stack 2: Viết chương trình khai báo Stack (dùng danh sách liên kết) có chứa
các số nguyên, với menu thực hiện như sau:
1. Push vào Stack
2. Pop ra khỏi Stack
3. Xem phần tử trên đỉnh Stack
4. Kiểm tra Stack rỗng
5. Số phần tử trong Stack
6. Duyệt Stack
7. Thoát
11
Bài tập DSLK 3: Bài tập Queue 2: Viết chương trình khai báo Queue (dùng danh sách liên kết) có
chứa các số nguyên, với menu thực hiện như sau:
1. Thêm vào Queue (EnQueue)
2. Lấy ra khỏi Queue (DeQueue)
3. Xem phần tử đầu Queue
4. Kiểm tra Queue rỗng
5. Kích thước Queue
6. Duyệt Queue
7. Thoát
12
V/. Danh Sách Liên Kết Vòng (Circular Linked List):
Danh sách liên kết vòng là một biến thể của danh sách liên kết, trong đó tất cả các nút được kết nối để
tạo thành một vòng tròn. Không có null ở cuối. Danh sách liên kết vòng, có thể là danh sách liên kết
vòng đơn (singly circular linked list) hoặc danh sách được liên kết vòng đôi (doubly circular linked
list).
13
Ưu điểm so với danh sách liên kết đơn:
i. Một DSLK đôi có thể được di chuyển theo cả hai hướng tiến và lùi. ii.
Các hoạt động xóa, chèn thêm trong DSLK đôi là hiệu quả hơn.
14
return prev;
}
/* Hàm gán giá trị Data cho node */
public void setData(int d)
{
data = d;
}
/* Hàm trả về Data của node */
public int getData()
{
return data;
} }
B/. khai báo cho DSLK: để quản lý DSLK, người cần nắm giữ phần tử start, end và sử dụng thêm
thuộc tính size để theo dõi số phần tử trong DSLK.
Tạo 1 Class định nghĩa DSLK đôi.
/* Class linkedList */ class linkedList
{ 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 public int
size; //Cho biết kích thước của DSLK
/* hàm khởi tạo DSLK rỗng */ public
linkedList()
{
start = null; end =
null; size = 0;
}
/* Hàm kiểm tra DSLK rỗng */ public
boolean isEmpty()
{
return start == null;
}
/* Hàm trả về kích thước của DSLK */ public int
getSize()
{
return size;
}
15
… /* định nghĩa các hàm thao tác khác trên DSLK
đôi*/
5 16 16 … 58
start
end
Size: 10
public linkedList()
{
start = null; end = null; size = 0;
}
16
/* Hàm thêm 1 phần tử vào đầu */
public void insertAtStart(int val)
{
Node nptr = new Node(val, null, null);
if(start == null)
{
start = nptr;
end = start;
}
else
{
start.setLinkPrev(nptr);
nptr.setLinkNext(start); start
= nptr;
}
size++;
}
insertAtStart(val);
return; }
Node ptr = start;
for (int i = 2; i <= size; i++)
{
if (i == pos)
{
Node tmp = ptr.getLinkNext();
ptr.setLinkNext(nptr);
nptr.setLinkPrev(ptr);
nptr.setLinkNext(tmp);
tmp.setLinkPrev(nptr);
}
ptr = ptr.getLinkNext();
}
size++ ;
}
18
8/. Xóa 1 phần tử tại vị trí Pos trong DSLK:
/* Hàm xóa 1 phần tử tại vị trí pos */
public void deleteAtPos(int pos)
{
if (pos == 1)
{
if (size == 1)
{
start = null;
end = null; size
= 0; return;
}
start =
start.getLinkNext();
start.setLinkPrev(null);
size--; return ;
}
if (pos == size)
{
end = end.getLinkPrev();
end.setLinkNext(null); size--
;
}
Node ptr = start.getLinkNext();
for (int i = 2; i <= size; i++)
{
if (i == pos)
{
Node p = ptr.getLinkPrev();
Node n = ptr.getLinkNext();
p.setLinkNext(n);
n.setLinkPrev(p);
19
size-- ;
return;
}
ptr = ptr.getLinkNext();
}
}
20
Bài tập thêm về DSLK đơn (Điểm A)
1/. Viết hàm đảo ngược DSLK (chỉ dùng 1 DSLK) 2/. Viết hàm sắp xếp danh sách liên kết theo thứ tự
tăng dần (dùng giải thuật bất kỳ)
21