Tải bản đầy đủ (.pdf) (27 trang)

Ghi chép tự học: Cấu trúc dữ liệu và thuật toán

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (2.32 MB, 27 trang )

Chương 1. Các khái niệm cơ bản
1.1. Ví dụ mở đầu
1.1.1. Thuật toán trực tiếp
1.1.2. Thuật toán nhanh hơn
1.1.3. Thuật toán đệ quy
1.1.3. Thuật toán quy hoạch động
1.2. Thuật toán và độ phức tạp
1.2.1. Khái niệm bài toán và thuật toán
1.2.2. Độ phức tạp của thuật toán
1.2.3. Các loại thời gian tính
1.3. Ký hiệu tiệm cận
1.3.1. Ơ nhỏ
1.3.2. Ơ lớn
1.3.3. Ô mê ga
1.3.4. Liên hệ
1.3.5. Một số lớp thuật toán
1.4. Giả ngơn ngữ
1.5. Một số kỹ thuật phân tích thuật tốn
1.5.1. Cấu trúc tuần tự
1.5.2. Phân tích vịng lặp for
1.5.3. Phân tích vịng lặp While, Repeat
1.5.4. Câu lệnh đặc trưng
Chương 2. Thuật toán đệ quy
2.1. Khái niệm đệ quy
2.1.1. Hàm đệ quy
2.1.2. Tập hợp được xác định đệ quy
2.2. Thuật tốn đệ quy
2.3. Ví dụ
2.4. Phân tích thuật tốn đệ quy
2.5. Đệ quy có nhớ
2.6. Chứng minh tính đúng đắn của thuật toán đệ quy


2.7. Thuật toán quay lui
Chương 3. Các cấu trúc dữ liệu cơ bản
3.1. Các khái niệm
3.1.1. Kiểu dữ liệu
3.1.2. Kiểu dữ liệu trừu tượng
3.1.3. Cấu trúc dữ liệu
3.2. Mảng
3.2.1. Kiểu dữ liệu trừu tượng mảng
3.2.2. Phân bổ bộ nhớ cho mảng
3.2.3. Các thao tác với mảng

4
4
4
4
4
5
5
5
5
5
5
5
6
6
6
6
6
6
6

6
6
7
8
8
8
8
8
8
8
8
8
8
9
9
9
9
9
9
9
9
9

1


3.3. Danh sách
3.3.1.Danh sách tuyến tính
3.3.2.Các cách cài đặt danh sách tuyến tính
3.3.2.1. Mảng

3.3.2.2. Danh sách móc nối
3.3.3. Các ví dụ ứng dụng
3.3.3.1. Bài toán Josephus
3.3.3.2. Biểu diễn đa thức
3.3.4. Phân tích sử dụng danh sách móc nối
3.3.5. Một số biến thể của danh sách móc nối
3.4. Ngăn xếp
3.4.1. Kiểu dữ liệu trừu tượng ngăn xếp
3.4.2. Ngăn xếp dùng mảng
3.4.3. Ngăn xếp dùng danh sách móc nối
3.4.3. Một số ứng dụng của ngăn xếp
3.5. Hàng đợi
3.5.1. ADT hàng đợi
3.5.2. Cài đặt dùng mảng
3.5.3. Cài đặt dùng danh sách móc nối
3.5.4. Ứng dụng của hàng đợi
Chương 4. Cây
4.1. Định nghĩa và các khái niệm
4.1.1. Định nghĩa cây
4.1.2. Các thuật ngữ chính
4.1.3. Cây có thứ tự
4.1.4. Cây có nhãn
4.1.5. ADT Cây
4.1.5.1. Biểu diễn cây dùng mảng
4.1.5.2. Danh sách các con
4.2. Cây nhị phân
4.2.1. Định nghĩa và tính chất
4.2.2. Biểu diễn cây nhị phân
4.3. Các ví dụ ứng dụng
4.3.1. Cây nhị phân biểu thức

4.3.2. Cây quyết định
4.3.3. Mã Huffman
Chương 5. Các thuật toán sắp xếp
5.1. Bài toán sắp xếp
5.1.1. Bài toán sắp xếp
5.1.2. Giới thiệu sơ lược về các thuật toán sắp xếp
5.2. Ba thuật toán sắp xếp cơ bản
5.2.1. Sắp xếp chèn
5.2.2. Sắp xếp lựa chọn
5.2.3. Sắp xếp nổi bọt

9
9
9
10
10
10
10
10
10
10
10
10
10
10
10
10
10
10
10

10
10
11
11
11
11
11
11
12
12
12
12
12
12
12
12
12
13
13
13
13
13
13
13
14

2


5.3. Sắp xếp trộn

5.4. Sắp xếp nhanh
5.4.1. Sơ đồ tổng quát
5.4.2. Phép phân đoạn
5.5. Sắp xếp vun đống
5.5.1. Cấu trúc dữ liệu đống
5.5.1.1. Biểu diễn đống bởi mảng
5.5.1.2. Hai dạng đống
5.5.1.3. Các phép toán đối với đống
5.5.2. Sắp xếp vun đống
5.5.3. Hàng đợi có ưu tiên
5.6. Cận dưới cho độ phức tạp tính tốn của bài tốn sắp xếp
5.7. Các phương pháp sắp xếp đặc biệt
5.7.1. Mở đầu
5.7.2. Sắp xếp đếm
5.7.3. Sắp xếp theo cơ số
5.7.4. Sắp xếp phân cụm
Chương 6. Tìm kiếm
6.1. Tìm kiếm tuần tự và tìm kiếm nhị phân
6.1.1. Tìm kiếm tuần tự
6.1.2. Tìm kiếm nhị phân
6.2. Cây nhị phân tìm kiếm
6.2.1. Định nghĩa
6.2.2. Biểu diễn cây nhị phân tìm kiếm
6.2.3. Các phép tốn
6.3. Cây nhị phân tìm kiếm cân bằng AVL
6.3.1. Định nghĩa
6.3.2. Các thao tác với cây AVL
6.4. Tìm kiếm xâu mẫu
6.4.1. Phát biểu bài toán
6.4.2. Thuật toán trực tiếp

6.4.3. Thuật toán Boyer-Moore
6.4.4. Thuật toán Rabin-Karp
6.4.5. Thuật toán KMP
6.5. Bảng băm
6.5.1. Đặt vấn đề
6.5.2. Địa chỉ trực tiếp
6.5.2. Hàm băm
6.5.2.1. Địa chỉ mở
6.5.2.2. Tạo chuỗi
Chương 7. Đồ thị và các thuật toán đồ thị
7.1. Đồ thị
7.1.1. Các loại đồ thị
7.1.2. Đường đi, chu trình, tính liên thông của đồ thị

14
14
14
14
15
15
15
15
15
15
15
16
16
16
16
16

16
17
17
17
17
17
17
17
18
18
18
18
18
18
19
19
19
19
19
19
19
19
20
20
21
21
21
21

3



7.2. Biểu diễn đồ thị
7.2.1. Dùng ma trận
7.2.2. Dùng danh sách kề
7.3. Các thuật toán duyệt đồ thị
7.3.1. Thuật toán tìm kiếm theo chiều rộng (BFS)
7.3.2. Thuật tốn tìm kiếm theo chiều sâu (DFS)
7.4. Một số ứng dụng của tìm kiếm trên đồ thị
7.4.1. Bài toán đường đi
7.4.2. Bài toán liên thơng
7.4.3. Đồ thị khơng chứa chu trình và bài tốn sắp xếp tơ pơ
7.4.4. Bài tốn tơ màu đỉnh đồ thị
7.5. Bài toán cây khung nhỏ nhất
7.5.1. Thuật toán Kruskal
7.5.2. Cấu trúc dữ liệu biểu diễn phân hoạch
7.6. Bài toán đường đi ngắn nhất
7.6.1. Thuật toán Dijkstra

22
22
22
23
23
24
24
24
24
25
25

25
25
25
25
25

4


Chương 1. Các khái niệm cơ bản
1.1. Ví dụ mở đầu
Bài tốn tìm dãy con lớn nhất
Tổng số lượng dãy con: n^2/2 + n/2

1.1.1. Thuật tốn trực tiếp
Duyệt tồn bộ tất cả các dãy con có thể có
Số lượng phép cộng: n^3/6 + n^2/2 + n/3

1.1.2. Thuật toán nhanh hơn
Tiết kiệm các tính tốn khơng cần thiết, trong trường hợp này là dùng kết quả trước đó cộng
thêm phần tử mới mà khơng cần tính lại từ đầu
Số lượng phép cộng: n^2/2 + n/2

1.1.3. Thuật toán đệ quy
Chia để trị:
- Chia bài toán thành các bài toán con cùng dạng
- Giải mỗi bài toán con một cách đệ quy
- Tổ hợp lời giải của các bài toán con để thu lời giải của bài tốn gốc
Chia đơi dãy:
- Tìm max bên trái

- Tìm max bên phải
- Tìm max của kết hợp giữa nửa trái và nửa phải
- Kết quả là max của 3 giá trị trên
Số lượng phép cộng: n.log(n) (nhanh hơn thuật toán 2)

1.1.3. Thuật toán quy hoạch động
Các bước:
- Chia bài toán thành các bài toán con cùng dạng
- Lưu trữ lời giải của các bài toán con
- Tìm cách xây dựng lời giải cho bài tốn lớn từ lời giải của các bài toán nhỏ hơn
Số lượng phép cộng: n

1.2. Thuật toán và độ phức tạp
1.2.1. Khái niệm bài toán và thuật toán
Bài toán là ánh xạ
Từ tập xâu nhị phân vào tập xâu nhị phân (độ dài hữu hạn)
Thuật toán:
- Đầu vào
5


-

Đầu ra
Chính xác
Hữu hạn
Đơn trị
Tổng quát

1.2.2. Độ phức tạp của thuật toán

Đánh giá lượng tài nguyên các loại mà thuật tốn địi hỏi sử dụng, tiêu biểu
- Thời gian
- Bộ nhớ
Đếm số phép tốn cơ bản => Thời gian tính

1.2.3. Các loại thời gian tính
3 loại:
- Tốt nhất
- Tồi nhất
- Trung bình

1.3. Ký hiệu tiệm cận
1.3.1. Ơ nhỏ
Cho hàm g(n), o(g(n)) là một hàm f(n) và tồn tại 3 hằng số c1, c2, n0 sao cho
0 <= c1.g(n) <= f(n) <= c2.g(n) với mọi n >= n0
Hình ảnh cho thấy f(n) có thể bị bao bởi 1 vùng giữa c1.g(n) và c2.g(n) với mọi n >= n0

1.3.2. Ô lớn
Cho hàm g(n), O(g(n)) là một hàm f(n) và tồn tại 2 hằng số dương c, n0 sao cho
f(n) <= c.g(n) với mọi n >= n0
g(n) gọi là tiệm cận trên của f(n)

1.3.3. Ô mê ga
Cho hàm g(n), Ôm(g(n)) là một hàm f(n) và tồn tại 2 hằng số dương c, n0 sao cho
f(n) >= c.g(n) với mọi n >= n0
g(n) gọi là tiệm cận dưới của f(n)

1.3.4. Liên hệ
f(n) = o(g(n)) khi g(n) vừa là tiệm cận trên vừa là tiệm cận dưới của f(n)


1.3.5. Một số lớp thuật toán
Tên gọi O

6


- O(1): hằng số
- O(log(n))
- O(n): tuyến tính
- O(n.log(n)): trên tuyến tính
- O(n^2): bình phương
- O(n^3): bậc ba
- O(a^n): hàm mũ (a > 1)
- O(n^k): đa thức (k >= 1)
Bài toán dễ giải: giải được nhờ thuật toán đa thức
Bài tốn khó giải: khơng thể giải được nhờ thuật tốn đa thức
Bài tốn khó giải: chưa tìm được thuật tốn đa thức
Bài tốn khơng giải được: khơng tồn tại thuật tốn để giải

1.4. Giả ngơn ngữ
Khơng có gì

1.5. Một số kỹ thuật phân tích thuật tốn
1.5.1. Cấu trúc tuần tự
1.5.2. Phân tích vịng lặp for
1.5.3. Phân tích vịng lặp While, Repeat
Thời gian tính của tìm kiếm nhị phân là O(log(n))

1.5.4. Câu lệnh đặc trưng
Đếm số câu lệnh đặc trưng để tìm thời gian tính


7


Chương 2. Thuật toán đệ quy
2.1. Khái niệm đệ quy
Đối tượng bao gồm chính nó hoặc được định nghĩa dưới dạng chính nó

2.1.1. Hàm đệ quy
2.1.2. Tập hợp được xác định đệ quy

2.2. Thuật toán đệ quy
Là thuật toán tự gọi đến chính mình với đầu vào kích thước nhỏ hơn

2.3. Ví dụ
2.4. Phân tích thuật tốn đệ quy
2.5. Đệ quy có nhớ
Có 1 số bài tốn con bị giải nhiều lần, ý tưởng là lưu lời giải của bài tốn con tại lần đầu tiên
giải nó, cách làm này địi hỏi về bộ nhớ

2.6. Chứng minh tính đúng đắn của thuật toán đệ quy
Dùng quy nạp toán học

2.7. Thuật toán quay lui
Xây dựng dần thành phần của lời giải
- Bắt đầu từ lời giải rổng
- Xây dựng tập ứng cử viên 1
- Chọn 1 phần từ trong tập ứng cử viên cho vào lời giải
- Giả sử đã giải đến tập ứng cử viên k-1
- Xây dựng tập ứng cử viên k

- Nếu có tập này thì chọn 1 phần tử cho vào lời giải
- Nếu k = n: ghi nhận lời giải
- Nếu khơng có tập ứng cử viên k thì quay lại chọn phần tử khác của tập ứng cử viên
k-1 rồi xây lại tập ứng cử viên k
- Nếu quay lại đến lời giải rỗng hết rồi mà cũng khơng được thì bài tốn khơng có lời
giải
Bài toán xếp hậu

8


Chương 3. Các cấu trúc dữ liệu cơ bản
3.1. Các khái niệm
3.1.1. Kiểu dữ liệu
Đặc trưng:
- Tập giá trị
- Cách biểu diễn chung
- Tập các phép toán

3.1.2. Kiểu dữ liệu trừu tượng
Đặc trưng:
- Tập giá trị
- Tập các phép toán

3.1.3. Cấu trúc dữ liệu
Là một họ các biến, có thể có kiểu dữ liệu khác nhau, được liên kết theo một cách nào đó
- Cơ sở: integer, char, …
- Tuyến tính: Mảng, danh sách liên kết, ngăn xếp, hàng đợi
- Phi tuyến: Cây, đồ thị, bảng băm


3.2. Mảng
3.2.1. Kiểu dữ liệu trừu tượng mảng
3.2.2. Phân bổ bộ nhớ cho mảng
3.2.3. Các thao tác với mảng

3.3. Danh sách
3.3.1.Danh sách tuyến tính
Dãy các phần tử cùng kiểu

3.3.2.Các cách cài đặt danh sách tuyến tính
Cơ bản:
- Mảng
- Danh sách móc nối
- Địa chỉ khơng trực tiếp: dùng bảng để lưu trữ vị trí của phần tử thứ i

9


3.3.2.1. Mảng
3.3.2.2. Danh sách móc nối

3.3.3. Các ví dụ ứng dụng
3.3.3.1. Bài tốn Josephus
3.3.3.2. Biểu diễn đa thức

3.3.4. Phân tích sử dụng danh sách móc nối
3.3.5. Một số biến thể của danh sách móc nối

3.4. Ngăn xếp
3.4.1. Kiểu dữ liệu trừu tượng ngăn xếp

3.4.2. Ngăn xếp dùng mảng
3.4.3. Ngăn xếp dùng danh sách móc nối
3.4.3. Một số ứng dụng của ngăn xếp

3.5. Hàng đợi
3.5.1. ADT hàng đợi
3.5.2. Cài đặt dùng mảng
3.5.3. Cài đặt dùng danh sách móc nối
3.5.4. Ứng dụng của hàng đợi

10


Chương 4. Cây
4.1. Định nghĩa và các khái niệm
4.1.1. Định nghĩa cây
Cây bao gồm các nút, có một nút đặc biệt được gọi là gốc (root) và các cạnh nối các nút.
Cây có thể định nghĩa theo kiểu đệ quy.
Ví dụ thực tế:
- Biểu đồ lịch thi đấu
- Cây gia phả
- Biểu đồ phân cấp quản lý hành chính
- Cây thư mục
- Cấu trúc quyển sách
- Cây biểu thức
- Cây phân hoạch tập hợp

4.1.2. Các thuật ngữ chính
Thuật ngữ:
- Nút

- Gốc
- Lá
- Con
- Cha
- Tổ tiên
- Hậu duệ
- Anh em
- Nút trong
- Chiều cao, chiều sâu

4.1.3. Cây có thứ tự
Là đối tượng chính được đề cập xử lý trong giáo trình
Đưa ra 3 cách duyệt cây
- Thứ tự trước
- Thứ tự sau
- Thứ tự giữa

4.1.4. Cây có nhãn
Sau khi chọn 1 loại thứ tự để đánh số thứ tự thì có thể có cách kiểm tra xem 1 nút có phải
hậu duệ hay tổ tiên của một nút khác hay không dựa vào số thứ tự và số lượng hậu duệ
chính

11


4.1.5. ADT Cây
4.1.5.1. Biểu diễn cây dùng mảng
Phần tử thứ i chứa con trỏ đến cha của nút i

4.1.5.2. Danh sách các con

Với mỗi một nút chứa danh sách các con của nó

4.2. Cây nhị phân
4.2.1. Định nghĩa và tính chất
Cây nhị phân mỗi nút có nhiều nhất 2 con
- Cây nhị phân đầy đủ
- Cây nhị phân hoàn chỉnh
- Cây nhị phân cân đối

4.2.2. Biểu diễn cây nhị phân
Xét 2 phương pháp:
- Mảng
- Con trỏ

4.3. Các ví dụ ứng dụng
4.3.1. Cây nhị phân biểu thức
Duyệt cây theo thứ tự trước => Ký pháp tiền tố
Duyệt cây theo thứ tự giữa => Ký pháp trung tố
Duyệt cây theo thứ tự sau => Ký pháp hậu tố

4.3.2. Cây quyết định
Mỗi đỉnh tương ứng với một truy vấn dữ liệu
Cạnh thể hiện cho khả năng trả lời câu hỏi
Mỗi lá tương ứng với một đầu ra
Bài toán tra từ điển
- Thuật toán tìm kiếm nhị phân là thuật tốn nhanh nhất trong số các thuật toán chỉ sử
dụng phép so sánh để giải quyết bài toán tra từ điển
Bài toán sắp xếp
- Mọi thuật toán sắp xếp chỉ sử dụng phép so sánh đều địi hỏi thời gian Ơm(n.log(n))


4.3.3. Mã Huffman

12


Chương 5. Các thuật toán sắp xếp
D. Knuth: “40% thời gian hoạt động của máy tính là dành cho sắp xếp”

5.1. Bài toán sắp xếp
5.1.1. Bài toán sắp xếp
Tổ chức lại họ các dữ liệu theo thứ tự giảm dần hoặc tăng dần theo khóa sắp xếp
Loại thuật tốn sắp xếp:
- Sắp xếp trong: toàn bộ dữ liệu đưa vào bộ nhớ
- Sắp xếp ngoài: một phần dữ liệu được đưa vào bộ nhớ, từ từ
2 phép toán cơ bản
- Đổi chỗ
- So sánh
Đặc trưng:
- Tại chỗ: không gian nhớ phụ mà thuật tốn địi hỏi là O(1)
- Ổn định: các phần tử cùng giá trị vẫn giữ nguyên thứ tự tương đối như trước khi sắp
xếp

5.1.2. Giới thiệu sơ lược về các thuật toán sắp xếp
Phân loại:
- Thuật toán đơn giản O(n^2): chèn, chọn, nổi bọt
- Thuật toán hiệu quả O(n.log(n)): vun đống, trộn, nhanh
- Cận dưới cho sắp xếp so sánh Ơm(n.log(n))
- Thuật tốn đặc biệt O(n): phân cụm, cơ số
- Xử lý các tập dữ liệu lớn: sắp xếp ngồi
Phương pháp:

- Hốn đổi
- Chọn
- Chèn
- Trộn
- Phân chia
- Lai

5.2. Ba thuật toán sắp xếp cơ bản
5.2.1. Sắp xếp chèn
Mô phỏng phong cách của người chơi bài khi cần chèn thêm một con bài vào bộ bài đã
được sắp xếp trên tay
Đặc tính
- Tại chỗ và ổn định
- Thuật toán sắp xếp tốt đối với dãy đã gần được sắp xếp

13


5.2.2. Sắp xếp lựa chọn
Thuật tốn
- Tìm phần tử nhỏ nhất đưa vào vị trí 1
- Tìm phần tử nhỏ tiếp theo đưa vào vị trí 2
- Tìm phần tử nhỏ tiếp theo đưa vào vị trí 3
- …
Đặc tính:
- Đổi chỗ ít, có ý nghĩa nếu như việc đổi chỗ là tốn kém

5.2.3. Sắp xếp nổi bọt
Thuật toán:
- Duyệt tử đầu đến cuối, nếu thấy chưa đúng thứ tự thì đổi chỗ => Phần tử lớn nhất bị

đẩy về cuối
- Lặp lại cho đến khi không cần đổi chỗ nữa
Đặc tính:
- Kém hiệu quả nhất so với 2 thuật toán trên

5.3. Sắp xếp trộn
Thuật toán:
- Chia: chia dãy n phần tử thành 2 dãy, mỗi dãy có n/2 phần tử
- Trị:
- Sắp xếp mỗi dãy con một cách đệ quy sử dụng sắp xếp trộn
- Dãy còn 1 phần tử thì trả về phần tử đó
- Tổ hợp: trộn 2 dãy con đã được sắp xếp để thu được kết quả
Đặc tính:
- Thời gian tính: o(n.log(n))

5.4. Sắp xếp nhanh
5.4.1. Sơ đồ tổng quát
Là thuật toán sắp xếp nhanh nhất hiện nay
Có tính tại chỗ, khơng có tính ổn định
Thuật tốn:
- Neo đệ quy: dãy có 1 phần tử là đã được sắp xếp
- Chia:
- Chọn một phần tử trong dãy làm chốt p
- Chia dãy làm 2 theo phần từ chốt L, R. L dãy những phần tử không lớn hơn
phần tử chốt, R dãy những phần tử không nhỏ hơn phần tử chốt
- Trị: lặp lại đệ quy cho 2 dãy con L, R
- Tổng hợp: Dãy được sắp xếp là L, p, R

5.4.2. Phép phân đoạn
Các cách chọn phần tử chốt


14


-

Chọn phần tử đứng đầu
Chọn phần tử đứng cuối
Chọn phần tử giữa
Chọn phần tử trung vị trong 3 phần tử đầu, giữa cuối
Chọn ngẫu nhiên

5.5. Sắp xếp vun đống
5.5.1. Cấu trúc dữ liệu đống
Là cây nhị phân
- Tất cả các mức đầy, trừ mức cuối, mức cuối điền từ trái qua phải
- Tính chất đống: với mỗi nút x, parent(x) > x

5.5.1.1. Biểu diễn đống bởi mảng
5.5.1.2. Hai dạng đống
Dạng:
- Phần tử lớn nhất ở gốc
- Phần tử nhỏ nhất ở gốc

5.5.1.3. Các phép tốn đối với đống
Thuật tốn khơi phục tính chất đống
Giả thiết cây con trái và phải của 1 root đều là max-heap
Tìm max giữa root, root con trái, root con phải
Nếu max không phải là root thì đổi chỗ max cho root
Tiếp tục thực hiện đối với cây con mà root nắm dữ cho đến khi max là root hoặc root là lá


5.5.2. Sắp xếp vun đống
Thuật toán:
- Tạo max-heap
- Đổi chỗ gốc (phần tử lớn nhất) và phần tử cuối
- Loại bỏ phần tử cuối
- Vun lại đống
- Lặp lại cho đến khi chỉ còn 1 nút
Đặc tính:
- Độ phức tạp O(n.log(n))

5.5.3. Hàng đợi có ưu tiên
Tập S, mỗi phần tử có 1 chỉ số khóa độ ưu tiên
Cần cấu trúc dữ liệu hỗ trợ hiệu quả các thao tác:
- Bổ sung 1 phần tử x vào S
- Trả lại phần tử lớn nhất
- Loại bỏ và trả lại phần tử lớn nhất
- Tăng khóa của x thành k

15


Cấu trúc đống có thể đáp ứng được yêu cầu trên

5.6. Cận dưới cho độ phức tạp tính tốn của bài toán sắp xếp
Độ phức tạp của bài toán sắp xếp chỉ dựa trên phép so sánh là o(n.log(n))

5.7. Các phương pháp sắp xếp đặc biệt
5.7.1. Mở đầu
Với việc thêm giả thiết đầu vào, có thể làm tốt hơn sắp xếp chỉ dựa vào phép so sánh

Giả thiết:
- Các số nguyên nằm trong khoảng [0, k], k = O(n)
- Các số thực phân bố đều trong khoảng [0, 1)

5.7.2. Sắp xếp đếm
Input: n số nguyên dương nằm trong khoảng [0, k], k là số nguyên và k = O(n)
Ý tưởng:
- Với mỗi phần tử x của dãy đầu vào, ta xác định rank của nó như là số lượng phần tử
nhỏ hơn x
- Nếu đã biết hạng r của x, ta có thể xếp nó vào vị trí r + 1
Đặc tính:
- Độ phức tạp o(n)
- Chỉ tốt nhất nếu k = O(n)

5.7.3. Sắp xếp theo cơ số
Input: đầu vào gồm n số nguyên, mỗi số có d chữ số, hệ cơ số k
Ý tưởng: sắp xếp theo thứ tự từ điển
- Sắp xếp các số theo chữ số thứ 1
- Sắp xếp các số thu được theo chữ số thứ 2 (sử dụng sắp xếp ổn định)
- …
- Sắp xếp các số thu được theo chữ số thứ d (sử dụng sắp xếp ổn định)
Đặc tính:
- Thời gian tính o(n) nếu d là hằng số và k = O(n)

5.7.4. Sắp xếp phân cụm
Input: n số thực có phân bố đều trong khoảng [0, 1] (các số có xác suất xuất hiện như nhau)
Ý tưởng:
- Chia đoạn [0, 1) làm n cụm: 0, 1/n, 2/n, … (n-1)/n
- Đưa mỗi phần tử a[j] vào đúng cụm của nó i/n <= a[j] < (i+1)/n
- Do phân bố đều nên khơng có q nhiều số rơi cùng vào 1 cụm

- Sắp xếp chèn trong nội bộ các cụm

16


Chương 6. Tìm kiếm
6.1. Tìm kiếm tuần tự và tìm kiếm nhị phân
Cho một danh sách, tìm vị trí trong danh sách có giá trị tương ứng với giá trị muốn tìm

6.1.1. Tìm kiếm tuần tự
Thuật tốn:
- Duyệt từ phần tử đầu, cho đến khi tìm được
Đặc tính:
- Độ phức tạp: O(n)
- Khơng địi hỏi cần phải sắp xếp
- Làm việc được với cả danh sách móc nối

6.1.2. Tìm kiếm nhị phân
Điều kiện:
- Danh sách phải được sắp xếp không giảm
- Phải cho phép trực truy (không dùng được với danh sách móc nối)
Đặc tinh:
- Độ phức tạp: O(log(n))

6.2. Cây nhị phân tìm kiếm
Nhu cầu: cấu trúc dữ liệu biểu diễn tập động có tính chất:
- Các phần tử có khóa và thơng tin đi kèm
- Hỗ trợ truy vấn:
- Tìm phần tử có khóa k
- Tìm phần tử có khóa nhỏ nhất, lớn nhất

- Tìm phần tử kế cận trước, kế cận sau
- Bổ sung phần tử mới
- Xóa bỏ phần tử

6.2.1. Định nghĩa
Là cây nhị phân có các tính chất
- Mỗi nút x (ngồi thơng tin đi kèm) có các trường
- left: con trỏ đến con trái
- right: con trỏ đến con phải
- parent: con trỏ đến cha
- key: khóa (giả thiết là khác nhau từng đơi)
- Tính chất
- x là gốc của một cây con thì với mọi nút y thuộc cây con trái thì key(y) <
key(x), với mọi nút y thuộc cây con phải thì key(y) > key(x)
- Duyệt cây theo thứ tự giữa sẽ ra dãy khóa được sắp xếp

17


6.2.2. Biểu diễn cây nhị phân tìm kiếm
Sử dụng cấu trúc cây nhị phân

6.2.3. Các phép toán
Cơ bản:
- Tạo nút mới
- Tìm nút có giá trị khóa k
- Tìm nút có khóa nhỏ nhất
- Tìm nút có khóa lớn nhất
- Tìm nút kế cận sau của nút x
- Tìm nút kế cận trước của nút x

- Chèn một nút vào cây
- Xóa nút có khóa k

6.3. Cây nhị phân tìm kiếm cân bằng AVL
6.3.1. Định nghĩa
Là cây nhị phân tìm kiếm có chiều cao của cây con trái và cây con phải của gốc chỉ sai khác
nhau không quá 1 và cả cây con trái và cây con phải đều là cây AVL
Cây cân bằng thì các thao tác truy xuất tìm kiếm sẽ tối ưu nhất
Có cách để khơi phục cân bằng cho cây mất cân bằng bằng cách quay

6.3.2. Các thao tác với cây AVL
Bổ sung:
- Làm giống như cây BST
- Lần theo đường đi từ nút mới về gốc, với mỗi nút x kiểm tra chỉ số cân bằng
- Nếu bị mất cân bằng thì khơi phục cân bằng
- Khi đã khơi phục tính cân bằng của nút x thì cũng khơi phục được tính cân bằng của
tổ tiên => chỉ cần xử lý tối đa một nút vi phạm
Xóa:
- Làm giống cây BST
- Lần theo đường đi từ nút mới về gốc, với mỗi nút x kiểm tra chỉ số cân bằng
- Nếu bị mất cân bằng thì khơi phục cân bằng
- Khi đã khơi phục tính cân bằng của nút x thì vẫn cần đi tiếp về gốc khác với thao tác
bổ sung
Tất cả các phép toán với cây AVL đều được thực hiện với thời gian O(log(n))

6.4. Tìm kiếm xâu mẫu
6.4.1. Phát biểu bài tốn
Cho xâu T có độ dài n, và xấu P có độ dài m, tìm tất cả các vị trí khớp của P trong T
Các ứng dụng của bài toán:
- Thu thập thông tin


18


-

Soạn thảo văn bản
Tính tốn sinh học

6.4.2. Thuật tốn trực tiếp
Thuật toán:
- Trượt từ đầu đến n-m, so sánh xem xâu mẫu có xuất hiện khơng
Đặc tính:
- Thời gian tính tồi nhất: O(n.m)

6.4.3. Thuật tốn Boyer-Moore
Mục đích là trượt cóc, giảm tải số lần phải so sánh
Sử dụng ký tự tồi

6.4.4. Thuật toán Rabin-Karp
Biến đổi chuỗi P thành số, và các chuỗi con trong T cũng thành số
Nếu 2 số bằng nhau thì là khớp

6.4.5. Thuật tốn KMP
Sử dụng hàm tiền tố để xác định số bước có thể skip khi trượt
Đặc tính:
- Thời gian tính o(n+m)

6.5. Bảng băm
6.5.1. Đặt vấn đề

Cho bảng T và bản ghi x, với khóa và dữ liệu đi kèm, cần hỗ trợ các thao tác:
- Insert(T, x);
- Delete(T, x);
- Search(T, x);
Muốn thực hiện nhanh chóng mà khơng cần phải sắp xếp
=> Dùng bảng băm
Ứng dụng:
- Xây dựng chương trình dịch
- Xây dựng từ điển
- Tìm kiếm hiệu quả, trong điều kiện thơng thường là O(1)
- Có thể xem như sự mở rộng của mảng thơng thường

6.5.2. Địa chỉ trực tiếp
Mỗi khóa tương ứng với 1 chỉ số trong bảng
Khơng khác gì mảng có key bất kỳ như trong PHP
Nhưng phải khởi tạo hết nên nếu như giả sử khóa là số nguyên 32 bit thì bảng địa chỉ trực
tiếp phải có hơn 4 tỉ phần tử (chắc cái này là do đặc điểm implement ở tầng thấp gần với

19


phần cứng hoặc ngày xưa, chứ hiện nay lập trình bậc cao có phải tạo sẵn nhiều thế đâu, trừ
khi dữ liệu thực tế có 4 tỉ phần tử thật)

6.5.2. Hàm băm
Mục đích giảm kích thước của bảng băm
Ánh xạ khóa vào 1 giá trị có kích thước nhỏ hơn, kiểu dùng 1 cách làm nào đó biến đổi giá
trị 100 ký tự về chuỗi 10 ký tự. Do đó sẽ có khả năng có 2 khóa khác nhau thơng qua hàm
hash thì trả về cùng 1 giá trị, xử lý như nào?


6.5.2.1. Địa chỉ mở
Mọi phần tử sẽ đều được cất giữ vào bảng (do bảng kích thước nhỏ nên chắc chắn có thể
bị full)
Bước làm:
- Thơng qua hàm hash xác định được ơ để chèn khóa vào
- Nếu ơ đã có giá trị rồi thì dị cho đến khi tìm được ơ trống
- Tất nhiên khơng phải là dị lần lượt, nó khơng đem lại lợi ích
- Phải dị theo quy tắc, mà quy tắc đó chỉ phụ thuộc vào khóa, tức là với mỗi
khóa, ta có được 1 quy tắc duy nhất (?) để dị
Để tìm kiếm thì cũng phải thực hiện dị theo quy tắc như lúc thêm mới, chứ khơng thì tìm
lung tung à.
3 kỹ thuật dị thường được dùng:
- Dị tuyến tính
- Dị tồn phương
- Hàm băm kép

6.5.2.2. Tạo chuỗi
Tạo danh sách móc nối để chứa các phần tử được gắn với cùng một vị trí trong bảng

20


Chương 7. Đồ thị và các thuật toán đồ thị
7.1. Đồ thị
Đồ thị G (graph) là cấu trúc rời rạc gồm 2 tập:
- Tập đỉnh V(G) (vertex) là tập hữu hạn khác rỗng
- Tập cạnh E(G) (edge) là tập hữu hạn có thể rỗng các cặp (u, v), u, v thuộc V
Phụ thuộc vào kiểu của cạnh và số lượng cạnh giữa 2 đỉnh mà phân biệt các loại đồ thị khác
nhau


7.1.1. Các loại đồ thị
Loại:
- Đơn (đa) đồ thị vô hướng: không phân biệt hướng của cạnh
- Đơn (đa) đồ thị có hướng: có phân biệt hướng của cạnh
Đa đồ thị là đồ thị có cạnh lặp (giữa 2 đỉnh có > 1 cạnh)

7.1.2. Đường đi, chu trình, tính liên thông của đồ thị
Đường đi độ dài n
là dãy các cạnh nối 2 đỉnh bất kỳ
Loại đường đi:
- Đường đi đơn: khơng có đỉnh bị lặp
- Đường đi cơ bản: khơng có cạnh nào bị lặp
Chu trình:
- Là đường đi cơ bản có đỉnh đầu trùng với đỉnh cuối
- Gọi là đơn nếu ngoại trừ đỉnh đầu và cuối thì khơng có đỉnh nào bị lặp lại
Liên thơng:
- Đồ thị vơ hướng gọi là liên thơng nếu ln tìm được đường đi giữa hai đỉnh bất kỳ
của nó
- Đồ thị có hướng gọi là liên thơng mạnh nếu ln tìm được đường đi nối hai đỉnh bất
kỳ của nó
- Đồ thị có hướng gọi là liên thơng yếu nếu đồ thị vô hướng thu được bằng việc bỏ
qua hướng của tất cả các cạnh là đồ thị vô hướng liên thơng
Các phép tốn cơ bản:
- Khởi tạo đồ thị
- Hủy đồ thị
- Lấy số cạnh
- Lấy số đỉnh
- Cho biết đồ thị là có hướng hay vơ hướng
- Bổ sung cạnh, loại bỏ cạnh
- Có cạnh nào nối giữa 2 đỉnh cho trước không

- Duyệt các đỉnh kề của một đỉnh cho trước
- Bài tốn phức tạp hơn:
- Tính giá trị của một số đặc trưng số của đồ thị (số liên thơng, sắc số,...)
- Tìm một số tập con cạnh đặc biệt (cặp ghép, bè, chu trình, cây khung,...)
- Tìm một số tập con đỉnh đặc biệt (phủ đỉnh, phủ cạnh, tập độc lập,...)

21


-

- Trả lời truy vấn về một số tính chất của đồ thị (song liên thơng, phẳng,…)
Bài tốn tối ưu:
- Cây khung nhỏ nhất
- Đường đi ngắn nhất
- Luồng cực đại trong mạng

7.2. Biểu diễn đồ thị
Có nhiều cách, phụ thuộc vào bài toán cụ thể và thuật toán cụ thể
Vấn đề cần quan tâm:
- Bộ nhớ
- Thời gian truy vấn

7.2.1. Dùng ma trận
Ma trận kề:
- Kích thước V x V
- Có cạnh nối giữa 2 đỉnh thì giá trị là 1, khơng có thì là 0
- Mở rộng biểu diễn đa đồ thị vô hướng: không phải là số 1 như trên nữa mà là số
cạnh
Ma trận trọng số:

- Dùng khi cạnh có thêm thơng tin trọng số
Ma trận liên thuộc đỉnh cạnh:
- Biểu diễn đơn đồ thị có hướng
- Mà ma trận V x E chứ không phải là V x V như trên nữa
- Giá trị:
- 1: đỉnh đang xét là đỉnh đầu
- -1: đỉnh đang xét là đỉnh cuối
- 0: đỉnh đang xét không phải là đầu mút cảu cạnh

7.2.2. Dùng danh sách kề
Đồ thị thưa (|E| <= k|V| với k< 10) thì thường dùng danh sách kề để biểu diễn
Sử dụng n danh sách liên kết, mỗi danh sách chưa các đỉnh kề của một đỉnh của đồ thị
(danh sách đỉnh)
Tiết kiệm bộ nhớ đáng kể so với ma trận kề
Loại:
- Danh sách đỉnh
- Danh sách cạnh
Các thao tác cơ bản
- Duyệt các đỉnh kề của đỉnh v
- 2 đỉnh u và w có kề nhau không
- Bổ sung đỉnh z
- Bổ sung cạnh e
- Loại bỏ đỉnh
- Loại bỏ cạnh

22


7.3. Các thuật toán duyệt đồ thị
Duyệt đồ thị là việc duyệt qua mỗi đỉnh và mỗi cạnh của đồ thị

Ứng dụng:
- Khảo sát tính chất của đồ thị
- Là thành phần cơ bản của nhiều thuật toán
Hai thuật toán duyệt cơ bản
- Theo chiều rộng BFS
- Theo chiều sâu DFS
Ý tưởng chung:
- Trong q trình chạy thuật tốn, mỗi đỉnh ở một trong 3 trạng thái:
- Chưa thăm
- Đã thăm nhưng chưa duyệt xong
- Đã duyệt xong
- Quá trình duyệt được bắt đầu từ một đỉnh v nào đó. Ta sẽ khảo sát các đỉnh đạt tới
được từ v
- Ban đầu mỗi đỉnh đều là chưa thăm
- Đỉnh được thăm
- Tất cả cách đỉnh kề của một đỉnh đã được thăm

7.3.1. Thuật tốn tìm kiếm theo chiều rộng (BFS)
Input: đồ thị G = (V, E), đỉnh xuất phát s thuộc V
Output:
- Với mọi v thuộc V
- d[v] = khoảng cách từ s đến v
- r[v] đỉnh đi trước v trong đường đi ngắn nhất từ s đến v
- Xây dựng cây BFS gốc tại s chứa tất cả các đỉnh đạt đến được từ v
Thuật toán thăm:
- Đánh dấu đỉnh gốc s chưa thăm, cho vào queue
- Dequeue lấy đỉnh ra thăm gọi là đỉnh u
- Với mỗi đỉnh kề v của s, đánh dấu là đang thăm
- d[v] = d[u] + 1
- r[v] = u

- Cho đỉnh lại vào queue
- Trong lúc queue vẫn cịn phần tử thì lấy ra thăm
Thuật toán duyệt:
- Duyệt tất cả các đỉnh
- Nếu đỉnh nào chưa được thăm thì thăm
Cây BFS:
- Gốc là s
- Các nút khác v là các nút mà r[v] khác rỗng (thể hiện là có thể đi được đến từ s)
- Một nút bất kỳ v trừ s có cha chính là r[v]
Đặc tính:
- Độ phức tạp: O(|V|^2)

23


7.3.2. Thuật tốn tìm kiếm theo chiều sâu (DFS)
Input: đồ thị G = (V, E)
Output:
- Với mọi v thuộc V
- d[v] = thời điểm bắt đầu thăm
- f[v] = thời điểm kết thúc thăm
- r[v] = đỉnh từ đó thăm đến đỉnh v
Rừng tìm kiếm theo chiều sâu
- Gr = (V, Er)
- Er = {(r[v], v), v thuộc V và r[v] khác null}
Thuật toán thăm:
- Đánh dấu u là đang thăm
- time++
- d[u] = time
- Với mỗi đỉnh kề v của u

- Nếu chưa thăm
- r[v] = u
- Thăm v
- Đánh dấu đã thăm u xong
- time++
- f[u] = time
Thuật toán duyệt:
- Với mỗi đỉnh u thuộc V
- Đánh dấu là chưa thăm
- r[u] = null
- time = 0
- Với mỗi đỉnh u thuộc V
- Nếu chưa thăm thì thăm
Tính chất DFS:
- Rừng DFS phụ thuộc vào thứ tự các đỉnh được duyệt trong DFS(G) và DFS_Visit(u)
- Điểm khác biệt cơ bản của DFS và BFS là các đỉnh đang được thăm trong DFS
được cất giữ vào ngăn xếp thay vì hàng đợi trong BFS
- Các khoảng thăm d[v], f[v] của các đỉnh có cấu trúc lồng nhau
- Độ phức tạp: O(|V|^2) tương tự BFS

7.4. Một số ứng dụng của tìm kiếm trên đồ thị
7.4.1. Bài tốn đường đi
Bài tốn: cho đồ thị G = (V, E) và 2 đỉnh s, t. Hỏi có tồn tại đường đi từ s đến t không.
Chỉ cần thực hiện DFS_Visit(s) hoặc BFS_Visit(s), nếu cuối cùng t được thăm thì là có tồn
tại đường đi từ s đến t và ngược lại.
Đường đi: dựa vào thông tin r[]
Đường đi từ s đến t theo BFS là đường đi ngắn nhất từ s đến t theo số cạnh

24



7.4.2. Bài tốn liên thơng
7.4.3. Đồ thị khơng chứa chu trình và bài tốn sắp xếp tơ pơ
7.4.4. Bài tốn tơ màu đỉnh đồ thị

7.5. Bài tốn cây khung nhỏ nhất
G = (V, E) là đồ thị vô hướng liên thơng có trọng số trên cạnh c(e), e thuộc E
Cây T = (V, Et) với Et tập con của E gọi là cây khung của G.
Độ dài của cây khung T là tổng trọng số trên các cạnh của nó.
Bài tốn: tìm cây khung có độ dài nhỏ nhất

7.5.1. Thuật toán Kruskal
Xây dựng tập cạnh theo từng bước
- Sắp xếp các cạnh theo thứ tự không giảm của độ dài
- Mỗi bước duyệt lần lượt các cạnh đã sắp xếp, để tìm ra cạnh mà việc bổ sung nó
vào tập Et khơng tạo thành chu trình

7.5.2. Cấu trúc dữ liệu biểu diễn phân hoạch
Dùng để cải tiến thuật toán Krusal

7.6. Bài tốn đường đi ngắn nhất
Đồ thị có trọng số trên cạnh
Tìm đường đi từ A đến B có tổng trọng số trên cạnh nhỏ nhất

7.6.1. Thuật toán Dijkstra
Để giải bài tốn tìm đường đi ngắn nhất từ 1 đỉnh s đến tất cả các đỉnh còn lại trên đồ thị với
trọng số khơng âm trên cạnh
Thuật tốn:
Mỗi đỉnh v sẽ có 3 nhãn:
- k[v] cho biết đã tìm được đường đi ngắn nhất từ s đến v chưa, khởi tạo là false

- d[v] cho biết độ dài đường đi ngắn nhất hiện tại đã biết từ s đến v: mọi đỉnh sẽ được
gán là dương vô cùng, riêng d[s] = 0;
- p[v] đỉnh đi trước v trong đường đi có độ dài d[v], khởi tạo là null
Lặp lại thao tác sau cho đến khi tất cả các đỉnh đã khảo sát xong (k[v] = true với mọi v)
- Trong tập k[v], chọn v có d[v] nhỏ nhất
- Đánh dấu k[v] = true, tại vì nếu có đi từ s đến v thơng qua đỉnh w thì do d[w] > d[v]
nên khơng thể chọn đi qua đó được
- Trong các đỉnh kề của w của w, xét các đỉnh có k[w] = false
- So sánh d[w] với d[v] + c(v, w)
- Nếu d[w] > d[v] + c(v, w) thì gán d[w] = d[v] + c(v, w) và p[w] = v

25


×