You are on page 1of 10

CÁC PHÉP TOÁN TRÊN DANH SÁCH LIÊN KẾT ĐƠN

A/. Mô tả, tính chất của danh sách liên kết đơn

- Bên trên chính là hình ảnh mô tả một danh sách liên kết đơn. Trong hình, mỗi một ô
hình chữ nhật được gọi là một "Node". Trong một "Node" chứa 2 thuộc tính:
 Data (dữ liệu): có thể là số nguyên, số thực hay là sinh viên, nhân viên...
 Next: là một con trỏ để lưu địa chỉ của "Node" tiếp theo. Nói đơn giản là nó trỏ
đến phần tử kế tiếp như trong hình. Cũng có thể hiểu nó như một sợi dây buộc
vào Node tiếp theo
- Tính chất danh sách liên kết đơn:
 Là một danh sách sử dụng con trỏ và động.
 Danh sách liên kết có thể thêm phần tử vào thoải mái đến khi nào hết bộ nhớ
máy tính thì thôi.
 Đối với mảng các phần tử trong mảng phải liên tiếp nhau, còn với Danh Sách
Liên Kết thì khác, các "Node" có thể nằm ở bất kì đâu trong bộ nhớ. Chỉ cần
chúng ta liên kết chúng lại với nhau thì sẽ tạo thành một danh sách.
 Danh Sách Liên Kết đơn chỉ được đi tiến chứ không được đi lùi.
Ví dụ: Ta cần truy xuất phần tử thứ 2 trong Danh Sách Liên Kết Đơn, ta phải duyệt
từ đầu đến phần tử thứ 2 chứ không thể duyệt ngược lại từ cuối.
B/. Cài đặt và các phép toán trên Danh Sách Liên Kết Đơn
1/. Dạng cài đặt
 Tạo một cấu trúc struct Node gồm 2 thuộc tính: Data (dữ liệu) và con trỏ Next
kiểu dữ liệu là Node luôn, vì con trỏ Next trỏ đến một Node khác.
Ví dụ: bạn khai báo một con trỏ P trỏ đến một bến kiểu nguyên (int) thì là: int P. Thì
tương tự như vậy Next trỏ đến "Node" thì phải là kiểu Node.
 Khai báo thêm một kiểu cấu trúc struct LinkList để tượng trưng cho cả một
danh sách (gồm nhiều Node).

Danh sách liên kết đơn


1
Khai báo một danh sách L. L luôn phải cầm đầu (ở Node đầu tiên), nếu L mất
hoặc di chuyển chúng ta sẽ mất danh sách.
Ở đây trường data được demo bằng danh sách số nguyên.
1 typedef struct Node
2 {
3 int Data;
4 Node* Next;
5 };
6
7 typedef struct Node* LinkList;
2/. Khởi tạo (Init)
 Để khởi tạo một danh sách rỗng ta chỉ cần gán L = NULL
 Chú ý: L ở đây phải tham trị vì ta cần lưu lại giá trị của L khi thay đổi.
1 void Init(LinkList& L) // tham trị
2 {
3 L = NULL;
4 }

3/. Kiểm tra rỗng (IsEmpty)


 Danh sách rỗng khi L = NULL
1 bool IsEmpty(LinkList L)
2 {
3 if (L == NULL) return true;
4 return false;
5 }
hoặc
1 bool IsEmpty(LinkList L)
2 {
3 return (L == NULL)
4 }
4/. Tạo một Node (AddNode)
Viết hàm tạo ra một node để áp dụng vào phép toán thêm phần tử vào danh sách

1 Node* AddNode(int x) // tạo môt Node có giá trị x


2 {
3 Node* P; // khai báo con trỏ P kiểu Node
4 P = new Node; // cấp phát {dùng cho C++}
5 P->Data = x; // gán Data của Node P (hay con trỏ P) là x
6 P->Next = NULL; // tạo ra một Node nó chưa liên kết với ai cả, nên Next của P là NULL
7
return P; // trả về
8
}

2
5/. Thêm Node vào Danh sách
 Thêm vào Đầu danh sách (AddHead)
Vì L chính là Node đầu tiên vì thế ta chỉ cần cập nhật lại L là xong.
Cho Next của P (như là sợi dây) trỏ hay buộc vào L. Lúc này P chính là Node
đầu tiên thì cập nhật lại L chính là P.

1 void AddHead(LinkList& L, int x)


2 {
3 Node* P; // khai báo con trỏ P
4 P = AddNode(x); // gọi hàm tạo Node P với giá trị là x
5 if (IsEmpty(L) == true)
6 L = P; // nếu danh sách rỗng thì P chính là L vì chỉ có 1 Node
7 else
8 {
9 P->Next = L; // đem Next của Node P vừa tạo trỏ đến L hiện tại
10
L = P; // cập nhật L
11 }
12
}
 Thêm vào Cuối danh sách (AddTail)
Duyệt từ Node đầu tiên (tức L) đến Node cuối cùng trong danh sach hiện tại, để
xác định được Node cuối cùng. Khi xác định được thì chỉ cần dùng Next của Node
cuối đó trỏ vào Node mới
Tạo con trỏ M bằng Node đầu tiên là L rồi cho M tăng đến Node cuối cùng thì
dừng. Node cuối đó chính là M.

1 void AddTail(LinkList& L, int x)


2 {
3 Node* P;
4 P = AddNode(x); // tạo node P với giá trị x

3
5 if (IsEmpty(L) == true)
6 L = P; // nếu danh sách rỗng thì P chính là L luôn
7 else
8 {
9 Node* M; // khai báo node M
10 M = L; // gán M bằng L đầu danh sách
while (M->Next != NULL) // M tăng dần khi M->Next = NULL thì dừng
11 {
12 M = M->Next;
13 }
14 M->Next = P; // xác định được node cuối rồi thì nối vào P
15
P->Next = NULL; // P là node cuối cùng nên Next trỏ đến NULL
16
}
17
}
18
 Đếm số lượng Node hay phần tử trong danh sách (Quantity)
Tạo node M cho nó chạy từ đầu danh sách, mỗi lần tăng lên thì số lượng tăng
thêm 1 đơn vị.
1 int Quantity(LinkList L)
2 {
3 int temp = 0; // khởi tạo ban đầu bằng 0
4 for (Node* M = L; M != NULL; M = M->Next) // M tăng lên bằng NULL thì dừng
5 {
6 temp++; // mỗi lần lặp temp tăng lên
7 }
8 return temp; // trả về temp
9 }
 Thêm vào vị trí k bất kỳ (AddAny)
Kiểm tra vị trí k có thỏa mãn hay không? Nếu thỏa mãn thì xác định Node M
trước vị trí k. Sau đó cho Next của P trỏ vào Node mà Next của M đang trỏ (P->Next
= M->Next). Nối M với P (M->Next = P)
1 void AddAny(LinkList& L, int k, int x)
2 {
3 if (k < 1 || k > Quantity(L)) // kiểm tra vị trí k có thỏa mãn hay không?
4 cout << "Not Add. " << endl;
5 else
6 {
7 if (k == 1) // nếu k = 1 thì chính là thêm vào phần tử đầu tiên
8 AddHead(L, x);
9 else
10 {
11 Node* P;
12 P = AddNode(x); // tạo node P với giá trị x
13 Node* M = L; // tạo node M bằng L
14 int temp = 1; // biến temp để biết điều kiện dừng
15 while (temp != k - 1 && M != NULL)
16 {
17 temp++;
18 M = M->Next; // M tăng dần lên
4
19 }
20 P->Next = M->Next; // P->Next bằng chính là Node mà M->Next trỏ đến
21 M->Next = P; // M->Next là P;
22 }
23 }
24 }

6/. Xóa Node khỏi danh sách


 Xóa đầu (DeleteHead)
Cho L chạy tăng lên Node tiếp theo thì Node đầu sẽ mất
1 void DeleteHead(LinkList& L)
2 {
3 L = L->Next; // Tăng L
4 }
 Xóa cuối (DeleteTail)
Xác định Node sau Node cuối rồi cho Node đó trỏ đến NULL
1 void DeleteTail(LinkList& L)
2 {
3 Node* M = L;
4 while(M->Next->Next != NULL)
5 {
6 M = M->Next;
7 }
8 M->Next = NULL;
9 }
 Xóa vị trí thứ k (DeleteAny)
Xác định Node trước vị trí k rồi cho Node đó trỏ trực tiếp đến Node sau k.
1 void DeleteAny(LinkList& L, int k)
2 {
3 if (k < 1 || k > Quantity(L)) // kiểm tra k
4 cout << "Not Delete." << endl;
5 else
6 {
7 if (k == 1)
8 DeleteHead(L);
9 else
10 {
11 Node* M = L;
12 int temp = 1;
13 while (temp != k - 1 && M != NULL)
14 {
15 temp++;
16 M = M->Next;
17 }
18 M->Next = M->Next->Next;
19 }
20 }
21 }

5
C/. Danh sách số nguyên toàn bộ chức năng trên
1 #include <iostream>
2 using namespace std;
3
4 typedef struct Node
5 {
6 int Data;
7 Node* Next;
8 };
9
10 typedef struct Node* LinkList;
11
12 void Init(LinkList& L)
13 {
14 L = NULL;
15 }
16
17 bool IsEmpty(LinkList L)
18 {
19 if (L == NULL) return true;
20 return false;
21 }
22
23 int Quantity(LinkList L)
24 {
25 int temp = 0;
26 for (Node* M = L; M != NULL; M = M->Next)
27 {
28 temp++;
29 }
30 return temp;
31 }
32
33 Node* AddNode(int x)
34 {
35 Node* P;
36 P = new Node;
37 P->Data = x;
38 P->Next = NULL;
39 return P;
40 }
41
42 void AddTail(LinkList& L, int x)
43 {
44 Node* P;
45 P = AddNode(x);
46 if (IsEmpty(L) == true)
47 L = P;
48 else
49 {
50 Node* M;
51 M = L;

6
52 while (M->Next != NULL)
53 {
54 M = M->Next;
55 }
56 M->Next = P;
57 P->Next = NULL;
58 }
59 }
60
61 void AddHead(LinkList& L, int x)
62 {
63 Node* P;
64 P = AddNode(x);
65 if (IsEmpty(L) == true)
66 L = P;
67 else
68 {
69 P->Next = L;
70 L = P;
71 }
72 }
73
74 void AddAny(LinkList& L, int k, int x)
75 {
76 if (k < 1 || k > Quantity(L))
77 cout << "Not Add. " << endl;
78 else
79 {
80 if (k == 1)
81 AddHead(L, x);
82 else
83 {
84 Node* P;
85 P = AddNode(x);
86 Node* M = L;
87 int temp = 1;
88 while (temp != k - 1 && M != NULL)
89 {
90 temp++;
91 M = M->Next;
92 }
93 P->Next = M->Next;
94 M->Next = P;
95 }
96 }
97 }
98
99 void DeleteHead(LinkList& L)
100 {
101 L = L->Next;
102 }
103
104 void DeleteTail(LinkList& L)
7
105 {
106 Node* M = L;
107 while(M->Next->Next != NULL)
108 {
109 M = M->Next;
110 }
111 M->Next = NULL;
112 }
113
114 void DeleteAny(LinkList& L, int k)
115 {
116 if (k < 1 || k> Quantity(L))
117 cout << "Not Delete." << endl;
118 else
119 {
120 if (k == 1)
121 DeleteHead(L);
122 else
123 {
124 Node* M = L;
125 int temp = 1;
126 while (temp != k - 1 && M != NULL)
127 {
128 temp++;
129 M = M->Next;
130 }
131 M->Next = M->Next->Next;
132 }
133 }
134 }
135
136 void InPut(LinkList& L, int n)
137 {
138 Init(L);
139 int x;
140 for (int i = 0; i < n; i++)
141 {
142 cout << "Value " << i << " : ";
143 cin >> x;
144 AddTail(L, x);
145 }
146 }
147
148 void OutPut(LinkList L)
149 {
150 for (Node* M = L; M != NULL; M = M->Next)
151 {
152 cout << M->Data << " ";
153 }
154 }
155
156 int main()
157 {
8
158 LinkList L;
159 int n, select;
160 cout << "Quantity: ";
161 cin >> n;
162 InPut(L, n);
163 do
164 {
165 cout << endl;
166 cout << "1. Add Head. " << endl;
167 cout << "2. Add Tail. " << endl;
168 cout << "3. Add Any. " << endl;
169 cout << "4. Delete Head. " << endl;
170 cout << "5. Delete Tail. " << endl;
171 cout << "6. Delete Any. " << endl;
172 cout << "9. OutPut. " << endl;
173 cout << "0. Exit." << endl;
174 cin >> select;
175 switch (select)
176 {
177 case 1:
178 {
179 int x;
180 cout << "Value: ";
181 cin >> x;
182 AddHead(L, x);
183 break;
184 }
185 case 2:
186 {
187 int x;
188 cout << "Value: ";
189 cin >> x;
190 AddTail(L, x);
191 break;
192 }
193 case 3:
194 {
195 int x, k;
196 cout << "Possity: ";
197 cin >> k;
198 cout << "Value: ";
199 cin >> x;
200 AddAny(L,k, x);
201 break;
202 }
203 case 4:
204 {
205 DeleteHead(L);
206 break;
207 }
208 case 5:
209 {
210 DeleteTail(L);
9
211 break;
212 }
213 case 6:
214 {
215 int k;
216 cout << "Possity Delete: ";
217 cin >> k;
218 DeleteAny(L, k);
219 break;
220 }
221 case 9:
222 {
223 OutPut(L);
224 break;
225 }
226 }
227 } while (select != 0);
228 }

10

You might also like