Sắp xếp bằng cách chèn trực tiếp Theo cách sắp xếp “chèn trực tiếp” này thì ở bước lặp thứ j, đã có sự sắp xếp của j-1 phần tử trước, ta so sánh phần tử thứ j dần về phía trước với các p
Trang 1PHÂN TÍCH MỘT SỐ THUẬT TOÁN
- Thuật toán M: Tìm giá trị lớn nhất trong dãy x[1], x[2], …, x[N]
Begin
j:=1; m := x[1];
for i:=2 to N do
if x[i] > m then
m := x[i];
j := i;
end if end do End
Có thể chứng minh thuật toán M là đúng bằng nguyên lý qui nạp
Nếu gọi α là thời gian thực hiện một phép so sánh và β là thời gian thực hiện một phép gán thì thời gian thực hiện thuật toán M là:
T= 2 β + (N-1) α + 2 A Nβ
Trong đó A N là số lần mà điều kiện x[i] > m được thỏa trong vòng lặp for
Nói cách khác A N số những i thỏa điều kiện sau đây:
x[i] = Max {x[k], 1 ≤ k ≤ i}
Có thể thấy rằng 0 ≤ A N ≤ N-1 Từ đó ta suy ra độ phức tạp (trung bình) của thuật toán M là O(ln(n)) vì dựa trên kỹ thuật tính toán dùng hàm sinh ta có thể
chứng minh được rằng
mean( A N ) = H n – 1 = O( ln(n) )
và độ lệch là
Trang 2σ = ( 2 )
N
N H
Chứng minh:
Ta tính giá trị trung bình của AN dựa trên 2 giả thiết sau:
(i) dãy các x[i] đôi một khác nhau, và
(ii) mọi phép hoán vị đều có thể xảy ra với xác suất như nhau (là 1/N!)
Ký hiệu pNk là xác suất để AN = k
Ta có:
pNk = (số hoán vị mà AN = k) / N!
Có thể kiểm tra được công thức sau đây (bài tập):
pNk =
n
1
.pN-1,k-1 +
n
n 1− pN-1,k
Xét hàm sinh
)
k
k Nk
n z p z
G
Ta có thể kiểm tra thấy rằng:
) (
1 )
(z z n 1 z
n
n
Suy ra
2 1
2
1
−
−
−
z
n
n n
n
Do đa thức
1
+
−
−
+
k n
k n
z
là hàm sinh của dãy {
1
+
−
−
k n
k n
,
1
1
+
−k
Ave(
1
+
−
−
+
k n
k n
z
) =
1
1
+
−k
Từ đó
Ave(G n(z)) = ∑ −1 +1
k n k = Hn-1
2 Số nghịch thế của một phép hon vị
Trang 3- Định nghĩa:
Cho π là một hoán vị của n phần tử 1, 2, …, n Một nghịch thế
là một cặp (π(i),π(j)) thỏa
π(i) > π(j) và i < j
Với j = 1, 2, …, n đặt
b j = số các nghịch thế có thành phần thứ hai là j
Bảng b 1 , b 2 , …, b n được gọi là bảng nghịch thế của hoán vị π
Số các nghịch thế của π là:
I(π) = ∑
=
n j j b
1
Ví dụ: Giả sử một hoán vị π viết dưới dạng dòng như sau
(π(1) π(2) … π(n)) = (5 9 1 8 2 6 4 7 3)
⇒ bảng nghịch thế là (2 3 6 4 0 2 2 1 0)
- Định lý:
Có một tương ứng 1-1 giữa tập hợp các hoán vị n phần tử và các bảng nghịch thế.
- Tính chất:
Đặt
I n (k) = số các hoán vị có k nghịch thế
và qui ước In(k) = 0 nếu k < 0 hay k > 2
n
Ta có các tính chất:
(i) In(0) = 0
(ii) In(1) = n-1
(iii)In n2 −k
= In(k)
Trang 4(iv)In(k) = In-1(k) + In-1(k-1) + + In-1(k-n+1)
- Số nghịch thế trung bình:
Xét hàm sinh Gn(z) của phân bố xác suất
=
)
(
!
1
0
k
I n
Do tính chất của In(k) ta có:
Gn(z) =
n
1
(1 + z + + zn-1) Gn-1(z)
⇒ Gn(z) = n1(1−−z z n)Gn-1(z)
⇒ Gn(z) =
) 1 ( 2 ) 1 )(
1 (
1 )
1 (
2 1 1
1
z z
n
n z
n
z
−
−
−
−
−
−
−
và
hk(z) =
) 1 (
1
z k
k
z
−
k
1
(1 + z + + zk-1)
là hàm sinh của phân bố xác suất
k k k
1 , ,
1 ,
1
nên có thể tính toán được
mean(hk) =
2
1
−
k
Var(hk) =
12
1
2−
k
Suy ra:
Mean(Gn) = ∑
=
−
n k
k
1 =
4
) 1 (n−
n
Var(Gn) = ∑
=
−
n
k
k
2
2
12
1 =
72
) 5 2 )(
1
n
Tóm lại ta có định lý sau đây:
Định lý: Số nghịch thế trúng bình là
4
) 1 (n−
n
= O(n 2 ) với độ lệch σ = O(
n
n ).
Trang 5Xét bài toán sắp xếp các record R[1], R[2], , R[N]
với các khóa tương ứng là K[1], K[2], , K[N]
(không làm mất tính tổng quát, ta có thể giả sử các khóa đôi một khác nhau)
Ta dùng một dãy phụ
Count[1], count[2], , count[N]
với count[i] = số record có khóa nhỏ hơn K[i]
- Thuật toán C: (sắp xếp bằng cách đếm)
Bước 1: đặt mọi count[i] là 0 ứng với I = 1, 2, …, N
Bước 2:
For I := N downto 2 do
For j := i-1 downto 1 do
If K[i] < K[j] then
count[j] := count[j] + 1 Else
count[i] := count[i] + 1 End if
End do End do
Bước 3: Đặt R[i] ở vị trí count[i] + 1
- Phân tích:
Ở bước 1 và bước 3 số thao tác có cở N: O(N) Đối với vòng lặp ở bước 2 ta có số phép so sánh = số phép gán Dễ thấy rằng số phép so sánh là:
2
) 1 ( 2
−
=
Từ đó suy ra độ phức tạp của thuật toán là O(N2)
4 Sắp xếp bằng cách chèn trực tiếp
Theo cách sắp xếp “chèn trực tiếp” này thì ở bước lặp thứ j, đã có sự sắp xếp của j-1 phần tử trước, ta so sánh phần tử thứ j dần về phía trước với các phần tử khác để chèn vào đúng vị trí
Trang 6- Thuật toán S:
For j := 2 to N do
I := j-1;
K := K[j];
R := R[j];
While (I > 0) and (K < K[i]) do
R[i+1] := R[i];
I := i-1;
End do;
R[i+1] := R;
End do
- Phân tích:
Ở ngoài vòng lặp while ta thực hiện 3(N-1) phép gán
Trong vòng lặp while ta thực hiên A phép gán mẩu tin và A phép gán biến nguyên (Bookeeping) trong đó A chính là số cặp khoá không đúng chỗ, nghĩa là số nghịch thế của phép hoán vị π sao cho
K[π(1) ] < K[π(2) ] < … < K[π(n) ]
khi chưa sắp xếp
Số phép so sánh trong vòng lặp while là A + (N-1) phép so sánh khoá và A + (N-1) + B phép so sánh i > 0 (bookeeping)
Ở đây B là số lần mà chỉ số i giảm đến 0 nghĩa là khi
K[j] = min{K[i]; 1≤i≤j}
Đại lượng A có giá trị cực tiểu là 0 khi mảng ban đầu đã được sắp xếp
và giá trị cực đại là N(N2−1) khi mảng ban đầu được xếp theo thứ tự
ngược Giá trị trung bình của A là N(N4−1) với độ lệch )
2
5 )(
1 ( 6
1 n n− n+
Trang 7Cuối cùng đại lượng B có thể được tính toán tương tự như trong thuật toán tìm MAX với giá trị cực tiểu là 0, cực đại là N – 1 và giá trị trung bình
là HN – 1 với độ lệch ( 2 )
N
N H
Tóm lại thuật toán S chạy nhanh nhất với độ phức tạp O(N) khi mảng đã
có thứ tự Trường hợp xấu nhất và trung bình độ phức tạp là O(N 2 ) Số phép so sánh khoá trung bình của thuật toán S chỉ còn bằng một nửa số phép
so sánh khoá trung bình của thuật toán C Tuy nhiên, số phép gán đã tăng cao hơn trước
5 Sắp xếp nhanh (Quick sort)
Sự cải tiến của thuật toán S so với thuật toán C không lớn lắm do ở mỗi bước lặp, số nghịch thế chỉ giảm được một đơn vị Do đó độ phức tạp có cùng cỡ với số nghịch thế của phép toán hoán vị cấp N mà giá trị trung bình đã được chứng minh là O(N2)
Để cải tiến hơn, ở mỗi bước cần làm giảm số nghịch thế càng nhiều càng tốt Gọi K là giá trị khoá ở giữa, ta sẽ tìm cách chia mảng M ban đầu thành 2 mảng con M1, M2, trong đó M1 là mảng con bên trái gồm các mẫu tin có khoá ≤ K và M2
là mảng con bên phải gồm các mẩu tin có khoá > K Phép chia này cần N phép so sánh và tối đa N phép dời chỗ Sau khi chia, một cặp (K[i], K[j]), i < j, chỉ có thể là một nghịch thế nếu 2 mẫu tin tương ứng cùng thuộc M1 hay cùng thuộc M2 Như thế
số nghịch thế tối đa có thể có sẽ được giảm từ
2
) 1 (N−
N
xuống còn:
4
) 2 ( ) 1 2
( 2 2
1
2 N N − = N N −
x x
nghĩa là đã giảm được hơn một nữa Ở bước tiếp theo, hai mảng con M1, M2 lại tiếp tục được chia đôi và số nghịch thế tối đa có thể có lại được giảm hơn một nữa Như
thế chỉ cần tối đa 2 N N ) 2 log2 N
2
) 1 ( ( log − ≈ bước, mảng sẽ không chứa nghịch thế.
Trang 8Nói cách khác mảng đã được sắp thứ tự Số phép so sánh tối đa sẽ là 2Nlog2 N và
số phép dời chỗ còn ít hơn nữa
Để trình bày thuật toán Q, ta sẽ sử dụng một stack có chiều dài log2N mà mỗi phần tử của … là một cặp (l,r) để trỏ tới phần tử đầu tiên và phần tử cuối cùng của mảng con tương ứng Ngoài ra để giảm bớt bookeeping, ta … thêm một mẩu tin giả R[N+1] có khóa là +∞ (lớn hơn mọi giá trị khóa trong mảng) Để đơn giản hóa thuật toán, ngoài hai thủ tục Push và Pop có sẵn của stack ta cũng đưa vào thủ tục giả cho hoán vị hai phần tử trong mảng, cũng như các … chiều dài và so sánh để trả
về chiều dài r hay so sánh chiều dài hai mảng Hàm so sánh trả về một cặp giá trị: giá trị đầu là các con trỏ chỉ đến mảng dài hơn và giá trị sau là các con trỏ chỉ đến mảng ngắn hơn trong … mảng đem so sánh
- Thuật toán Quick sort:
Bước 1: Push (1,N) vào stack;
Bước 2:
While stack <> φ do
(l,r) := Pop stack;
i:=l+1; j:=r;
K:=K[r]; R:=R[l];
Repeat
While K[i] ≤ K do i:=i+1 end do;
While K[i] > K do j:=j-1 end do;
If j ≤ i then hoán vị R[l] và R[j]
Else hoán vị R[i] và R[j]
End if;
Trang 9until j ≤ i ;
(M1, M2):= so sánh ((l,j-1),(j+1,r))
If chiều dài (M1) > 1 then Push M1 vào stack end if
If chiều dài (M2) > 1 then Push M2 vào stack end if
End do
- Phân tích:
Cũng như trong các thuật toán sắp xếp khác, hai yếu tố đóng vai trò quyết định trong việc đánh giá độ phức tạp của Thuật toán Q là AN, số phép so sánh khóa, và BN, số phép đổi chỗ (hoán vị 2 mẫu tin) Ta sẽ phân tích hai đại lượng này dưới đây:
Trường hợp trung bình
a) A N =mean A( N)
Gọi P Nklà xác suất để A N =k Trong bước phân chia đầu tiênl= 1 ,r=N Số
phép so sánh khóa trong vòng lặp Repeat…Until là N+1 nên P N k = 0 nếu
r
N
k< + Cũng trong bước này, nếu giả thiết dữ liệu hoàn toàn ngẫu nhiên, mẫu
tin R[1] sẽ được dời đến đúng vị trí S với xác suất N1 Khi ấy ta được 2 mảng
con cần xử lý tiếp là (1, S-1) và (S+1, N) Trong việc sắp xếp mảng con (1, S-1)
số phép so sánh cần thiết có thể lấy giá trị tùy ý 0 ≤h≤k−N− 1 với xác suất
1,
S h
P− Đồng thời việc sắp xếp mảng (S+1, N) cần đúng k-N-1-h phép so sánh.
Do đó ta có công thức truy chứng:
(7)
1
1 N k N
Nk S h N S k N h
S h
N
− −
− − − − −
= =
Gọi A N (z)là hàm sinh của phân bố xác suất {P } Nk k
Ta có do (7)
1
1
1
( )
1
1
k
k N
S h N S k N h
S k N h
S h N S k h
S k h
N
N
≥ +
− −
− − − − −
+
=
=
=
∑
∑ ∑∑
1 1
1
s
N
+
=
Trang 10Suy ra:
1 1
1
1
1
N
S
N
=
∑
1 0
2
S
N
−
=
Đây chính là công thức truy chứng Giải ta được kết quả là
1
3
2
A = N+ H + − ≈ NLn N
Vậy A N =O N( log )N
Mặt khác ta có:
1 1
1
( '' (1) '' (1))
N
S N S N
S
N
N
N
=
+
+
∑
Với điều kiện đầu A''1 =0 thì ta có
1
2 1
1 1 1
1
2
N
k
N
k
+
+
=
− +
=
+ −
∑
∑ Suy ra:
Trang 112 1 1
1 1 1
1 1 1
( ) '' (1)
1
2
2
N N
N
k
N
k
N N
N
k h k
+
=
− +
=
+ +
= >
+ −
+ −
∑
∑
∑∑
1 2
1
1
2
N
k
k
h N
− +
=
+
∑
Do đó:
1
1 2
N
k
−
=
∑
Như thế độ lệch б=O(N) khá bé so với A N =O N( log )N
b) B N =mean( )B n
Gọi bNst là xác xuất để trong phép phân chia mảng (1,N), mẩu tin X[1] được dời đến
vị trí đúng là S, và có t mẩu tin bên trái được đổi chỗ với t mẩu tin bên phải Ta có:
( )( )N S t
S t
N
b = ( − 1 )! ( − )! − 1 −
!
1
( )( ) ( 1)
1
1
−
−
−
−
S
S N t S t N
Tương tự như trong a) ta có:
∑∑
=
−
=
−
− + +
= N
S
S t
S N S
Nst
B
1
1 0
1
Thay thế giá trị của bNst vào ta được:
t S
t
S t N
S
S N S
S N t N
S
S t
S t N
N
=
−
=
−
−
−
=
−
=
−
−
0
1 1
1 1
1 0
1 1
1
Trang 12Với N,S cố định sao cho 1≤S≤N, số cách chọn tùy ý một tập con S-1 phần tử của {1,2,…,N-1} cũng là số cách chọn 1 tập con E có S-1-t phần tử của {1,2,…,S-1} và
1 tập con có t phần tử của {S,…,N-1} với 0≤t≤S-1 tùy ý Do đó:
1 1
0
1
−
−
=
−
−
−
S S
t
S N t
S t S
hay:
1 1
0
−
−
−
=
S S
N t S
t
S t
Mặt khác:
0
1
0
1
t
t S N S N t
t S t
S N t S
t
S
t
−
−
−
=
−
−
=
∑
( ) 1( ) ( 1 ( ) ( 1)! )
0
1
−
−
−
−
−
−
=
−
t
t S N S N
S
t
S t
( ) ( )(N S)
t S
t
S t
S
−
−
=
−
∑
−
1 1
0 1
Lý luận tương tự như trên ( )(N S )
t S
t
S
−
−
=
−
1 1
0
1
là số cách chọn tập hợp con S-i phần tử của tập hợp N-2 phần tử Do:
2 1
0
−
−
−
=
S S
N t S
t
S
t
( )( ) ( )1
1
1
−
−
−
−
S
N
S N S
Từ (9), (10), (11), ta có:
( )( )
∑
=
−
−
−
−
−
S
S N S
N
S N S N
B
1
1
1
1 1
=
=
=
+
−
−
−
−
−
0 1
2 1
2 1 1
1 1
S
N S
N S
B N N
N S
N N
S N
N
N
∑−
=
+
−
0
2 6
S S
N
N
B
Đây là hệ thức truy chứng, và ta có thể giải hệ thức này để được kết quả là:
3
1 1 3 4
1 1
3
1
1 − + ≈ +
Tóm lại độ phức tạp trung bình của thuật tóan Q là O(N logN)
Trường hợp xấu nhất và tốt nhất:
Khi mảng đã được xếp thứ tự tăng thì ở mỗi bước phân chia, phần tử bé nhất được giữ nguyên chỗ và ta được một mảng con với 1 phần tử ít hơn trước Do đó cần đến
N bước mới chấm dứt thuật tóan Suy ra số phép so sánh là N(N+1)=O(N2) Đó
Trang 13chính là trường hợp xấu nhất đối với phép so sánh trong khi số phép dời chỗ lại ít nhất và bằng N
Để tránh nghịch lý trên, ta có thể chọn khóa cầm canh cho phép phân chia là khóa của phần tử giữa +2
r l
K của mảng con (l,r) Khi ấy chỉ có log2N bước chia nếu mảng ban đầu đã có thứ tự Do đó số phép so sánh là (N+1)log2N trong khi số phép dời chỗ chỉ là log2N Đây chính là trường hợp tốt nhất cho cả số phép so sánh và phép dời chỗ Chú ý rằng nếu mảng được sắp xếp thứ tự giảm, với cách chọn phần
tử cầm canh như trên, số phép so sánh vẫn là (N+1)log2N trong khi số phép dời chỗ không tệ lắm: N+log2N
Ta cũng có thể xây dựng ví dụ trong đó cả số phép so sánh lẫn dời chỗ đều là O(N2) bằng cách chọn phần tử ở giữa của mảng con tận cùng bên phải là phần tử lớn nhất trong khi phần tử ở giữa của các mảng con khác được đặt đúng chỗ
Trang 14BÀI TẬP
Trình bày thuật toán và phân tích thuật toán
1 Thuật toán sắp xếp dãy “selection sort”
2 Thuật toán sắp xếp dãy “merge sort”
3 Thuật toán sắp xếp dãy “heap sort”
4 Thuật toán tìm kiếm tuần tự
5 Thuật toán tìm kiếm nhị phân
6 Thuật toán tìm kiếm trên “cây nhị phân tìm kiếm”
7 Các thuật toán duyệt đồ thị: DFS, BFS
8 Thuật toán tính giá trị của một đa thức
Trang 15Đề thi (phần phân tích thuật toán)
Câu 1: Trình bày một thuật toán sắp xếp dãy và phân tích độ phức tạp của thuật toán Câu 2: Phân tích độ phức tạp của thuật toán tìm kiếm trên một cây nhị phân, và nêu lên một cách để cải thiện thuật toán cho hiệu quả hơn