Mức hao phí trường hợp xấu nhất của một phép toán MULTIPOP trong dãy là On, bởi kích cỡ stack tối đa là n.. Do đó, thời gian trường hợp xấu nhất của bất kì phép toán stack nào là On và n
Trang 1ĐẠI HỌC HUẾ TRƯỜNG ĐẠI HỌC KHOA HỌC
TIỂU LUẬN MÔN HỌC
THIẾT KẾ VÀ PHÂN TÍCH THUẬT TOÁN
Đề tài:
PHÂN TÍCH KHẤU TRỪ
(AMORTIZED ANALYSIS)
Nguyễn Quang
Hồ Văn Lâm Phạm Vinh Trần Thị Quế Vy
Nhóm 2-CHKHMT - Khóa 09-14
Trang 2Huế, tháng 11/2014
Trang 3MỤC LỤC
A LỜI NÓI ĐẦU 4
B NỘI DUNG 5
1.Giới thiệu một số bài toán 5
1.1 Bài toán 1: Các phép toán trên Stack 5
1.2 Bài toán 2: Tăng bộ đếm nhị phân 6
2.Các phương pháp của phân tích khấu trừ 7
2.1 Phương pháp kết tập: The Aggregate Method 8
2.2 Phương pháp kế toán: The accounting method 13
2.3 Phương pháp thế: The potential method 16
3.Bảng động (Dynamic tables) 20
3.1 Mở rộng bảng (Table expansion) 21
3.2 Thu gọn và mở rộng bảng 25
C KẾT LUẬN 29
D TÀI LIỆU THAM KHẢO 30
Trang 4A LỜI NÓI ĐẦU
Có nhiều phương pháp để đánh giá chi phí của một thuật toán, trong giới hạn của tiểu luận môn học chúng tôi xin giới thiệu một phương pháp đó là phương pháp phân tích khấu trừ để đánh giá chi phí của thuật toán
Nội dung tiểu luận gồm có:
1 Giới thiệu một số bài toán
2 Các phương pháp của phân tích khấu trừ: trong phần này sẽ giới thiệu 3 phương pháp: phương pháp kết tập, phương pháp kế toán và phương pháp tiềm năng Với mỗi phương pháp sẽ chỉ ra đặc điểm và ứng dụng phương pháp vào
để xác định độ phức tạp của các bài toán được giới thiệu ở phần 1
3 Bảng động: Giới thiệu một cách lưu trữ mới dựa vào bảng động, ở đó ta
có thê tùy ý thay đổi kích thước của bảng sao cho thích hợp với các mục dữ liệu lưu trữ
Trang 5B NỘI DUNG
1 Giới thiệu một số bài toán
1.1 Bài toán 1: Các phép toán trên Stack
Chúng ta đã biết hai phép toán cơ bản stack đó là PUSH và POP, mỗi phép kéo theo dài O(1) thời gian, trong đó:
PUSH(S,x) bỏ đối tượng x vào stack S
POP(S) lấy một đối tượng ra từ đầu stack S
Bởi từng phép toán này trong O(1) thời gian, ta hãy xem mức hao phí của mỗi phép toán là 1 Do đó, tổng mức hao phí của một day n phép toán PUSH và POP là n, và như vậy thời gian thực hiện thực tế cho n phép toán là Θ(n)
Có một tình huống xảy ra nếu ta bổ sung phép toán stack MULTIPOP(S,k)
để lấy k đối tượng ra khỏi stack S với k có thể lớn hơn số đối tượng trong stack
S Trong thuật toán MULTIPOP dưới đây, hàm STACK-EMPTY trả về TRUE nếu không có đối tượng nào thực hiện nằm trên stack và bằng không là FALSE
lặp While là số min(s,k) các đối tượng được kéo ra khỏi stack Với mỗi lần lặp
lại vòng lặp, một lệnh gọi được thực hiện cho POP trong dòng 2 Như vậy, tổng mức hao phí của MULTIPOP là min(s,k), và thời gian thực hiện thực tế là một hàm tuyến tính của mức hao phí này
Ví dụ: Thực hiện MULTIPOP trên một stack S, thọat đầu nêu trong (a) 4 đối tượng đầu được kéo ra bởi MULTIPOP(S,4) mà kết quả của nó được nêu
Trang 6trong (b) Phép toán kế tiếp là MULTIPOP(S,6) sẽ xả trống stack-được nêu trong (c)-bởi chỉ còn lại ít hơn 6 đối tượng.
Ta hãy phân tích một dãy n phép toán PUSH, POP và MULTIPOP trên một stack trống từ đầu Mức hao phí trường hợp xấu nhất của một phép toán MULTIPOP trong dãy là O(n), bởi kích cỡ stack tối đa là n Do đó, thời gian trường hợp xấu nhất của bất kì phép toán stack nào là O(n) và như vậy một dãy
n phép toán sẽ có mức hao phí là O(n2), bởi ta có thể có O(n) phép toán MULTIPOP, mỗi phép có mức hao phí là O(n) Mặc dù kiểu phân tích này là đúng đắn, kết quả O(n2) có được nhờ xét mức hao phí trường hợp xấu nhất của mỗi phép toán riêng lẻ, là không chặt
1.2 Bài toán 2: Tăng bộ đếm nhị phân
Ta hãy xét bài toán thực thi một bộ đếm nhị phân k bít đếm lên từ 0 Ta
dùng một mảng A[0 k-1] bit, ở đó length[A] = k, là bộ đếm Một số nhị phân x được lưu trữ trong bộ đếm có k bit cấp thấp nhất của nó trong A[0] và bit cao nhất trong A[k-1], sao cho Thoạt đầu, x=0, như vậy A[i]=0 với
i=0,1,…k-1 Để cộng 1 (modulo 2k) vào giá trị trong bộ đếm ta dùng thủ tục dưới
hao phí
Trang 7Hình 1.1(ở trang liền trước) Một đếm nhị phân 8-bit khi giá trị của nó đi từ
0 đến 16 theo một dãy 16 phép toán INCREMENT Các bít lật để đựơc giá trị kế tiếp được tô bóng Mức hao phí thực hiện để lật các bít được nêu ở bên phải Lưu
ý, tổng mức hao phí không bao giờ lớn hơn hai lần tổng phép toán INCREMENT
Thuật toán INCREMENT
6 Chi phí cho mỗi phép toán INCREMENT là tuyến tính với số bit được lật.Giống như trong ví dụ stack, một sự phân tích nhanh cho ra một cận tuy là đúng nhưng không chặt Một đợt thi hành INCREMENT sẽ mất một thời gian
Θ(k) trong trường hợp xấu nhất, ở đó mảng A chứa tất cả 1 Như vậy, một dãy n phép toán INCREMETN trên một bộ đếm zero từ đầu sẽ mất một thời gian O(nk) trong trường hợp xấu nhất
2 Các phương pháp của phân tích khấu trừ
Trong phép phân tích khấu trừ, thời gian yêu cầu để thực hiện một dãy
các phép toán cấu trúc dữ liệu được tính bình quân trên tất cả các phép toán
Trang 8thực hiện Có thể dùng phép phân tích khấu trừ để chứng tỏ mức hao phí trung bình của một phép toán là nhỏ, nếu như ta lấy bình quân trên một dãy các phép toán, cho dù một phép toán đơn lẻ có thể là tốn kém Phân tích khấu trừ khác với phân tích trường hợp trung bình ở chỗ không có liên quan đến xác suất; phân tích khấu trừ bảo đảm khả năng thực hiện trung bình của mỗi phép toán trong trường hợp xấu nhất.
Trong phép phân tích khấu trừ có 3 phương pháp: phương pháp kết tập, phương pháp kế toán và phương pháp tiềm năng
2.1 Phương pháp kết tập: The Aggregate Method
Trong phương pháp kết tập của phép phân tích khấu trừ, ta chứng tỏ với
tất cả n, một dãy n phép toán chiếm tổng cộng T(n) thời gian trường hợp xấu
nhất Như vậy, trong trường hợp xấu nhất, chi phí trung bình hoặc chi phí khấu
trừ của mỗi phép toán là T(n)/n Lưu ý, chi phí khấu trừ này áp dụng cho mỗi
phép toán, thậm chí khi có vài kiểu phép toán trong dãy
Phương pháp kế toán và phương pháp thế, sẽ được giải thích sau trong chương này, có thể gán các chi phí khấu trừ khác nhau cho các kiểu phép toán khác nhau
a Ý tưởng của phương pháp:
Tính thời gian tổng cộng của tất cả các phép toán trong một dãy n phép toán đó là T(n) Từ đó chi phí khấu trừ của mỗi phép toán trong trường hợp xấu nhất là T(n)/ n
Trang 9Trong ví dụ đầu tiên của chúng ta về phương pháp kết tập, ta phân tích ngăn xếp đã được tăng cường một phép toán mới.
Chúng ta đã biết hai phép toán cơ bản stack đó là PUSH và POP, mỗi phép kéo dài O(1) thời gian, trong đó:
PUSH(S,x) bỏ đối tượng x vào stack S
POP(S) lấy một đối tượng ra từ đầu stack S và trả về đối tượng được kéo ra.Bởi từng phép toán này trong O(1) thời gian, ta hãy xem chi phí của mỗi phép toán là 1 Do đó, tổng chi phí của một dãy n phép toán PUSH và POP là n,
và như vậy thời gian thực hiện thực tế cho n phép toán là Θ(n)
Tình huống trở thành thú vị hơn nếu ta bổ sung phép toán stack MULTIPOP(S,k) để lấy k đối tượng trên cùng ra khỏi stack S hoặc kéo ra tất cả các đối tượng trong Stack nếu nó chứa ít hơn k đối tượng Trong mã giả MULTIPOP dưới đây, hàm STACK-EMPTY trả về TRUE nếu không có đối tượng nào hiện nằm trên stack và ngược lại là FALSE
While là số min(s,k) các đối tượng được kéo ra khỏi stack Với mỗi lần lặp lại
vòng lặp, một lệnh gọi được thực hiện cho POP trong dòng 2 Như vậy, tổng chi phí của MULTIPOP là min(s,k), và thời gian thực hiện thực tế là một hàm tuyến tính của chi phí này
Ví dụ: Thực hiện MULTIPOP trên một stack S, thọat đầu nêu trong (a) 4 đối tượng đầu được kéo ra bởi MULTIPOP(S,4) mà kết quả của nó được nêu trong (b) Phép toán kế tiếp là MULTIPOP(S,7) sẽ xả trống stack-được nêu trong (c)-bởi chỉ còn lại ít hơn 7 đối tượng
Trang 10Ta hãy phân tích một dãy n phép toán PUSH, POP và MULTIPOP trên một stack trống từ đầu Chi phí trường hợp xấu nhất của một phép toán MULTIPOP trong dãy là O(n), bởi kích cỡ stack tối đa là n Do đó, thời gian trường hợp xấu nhất của bất kì phép toán stack nào là O(n) và như vậy một dãy n phép toán sẽ
có chi phí là O(n2), bởi ta có thể có n phép toán MULTIPOP, mỗi phép có chi phí là O(n) Mặc dù kiểu phân tích này là đúng đắn, kết quả O(n2) có được nhờ xét chi phí trường hợp xấu nhất của mỗi phép toán riêng lẻ, là không chặt
Bây giờ ta dùng phương pháp của phân tích khấu trừ là phương pháp kết tập với ý tưởng đã trình bày ở trên vào bài toán này ta sẽ thấy kết quả thú vị hơn.Dùng phương pháp kết lập của phép phân tích khấu trừ, ta có thể được một cận trên tốt hơn xem xét nguyên cả dãy n phép toán Thực vậy mặc dù một phép toán MULTIPOP đơn lẻ có thể tốn kém, bất kì dãy n phép toán PUSH, POP và MULTIPOP nào trên một stack trống từ đầu có thể có chi phí tối đa O(n) Tại sao? Mỗi đối tượng có thể được kéo ra tối đa một lần cho mỗi lần nó được bỏ vào Do đó, số lần mà POP có thể được gọi trên một stack không trống, kể cả các lần gọi trong MULTIPOP, tối đa là số lượng các phép toán PUSH, mà các phép toán này tối đa là n Với bất kì giá trị nào của n, một dãy n phép toán PUSH, POP và MULTIPOP bất kì đều chiếm một tổng O(n) thời gian Chi phí khấu trừ của một phép toán là số trung bình: O(n)/n=O(1)
Mặc dù ta vừa chứng minh chi phí trung bình và do đó thời gian thực hiện của một phép toán stack là O(1), nhưng nó không liên quan đến biện luận xác suất Thực tế ta đã nêu một cận trong trường hợp xấu nhất của O(n) trên một dãy
Trang 11n phép toán Chia tổng chi phí này cho n đã cho ra chi phí trung bình của mỗi phép toán hoặc chi phí khấu trừ
* Phân tích bài toán 2:
Gia số bộ đếm nhị phân
Để lấy một ví dụ khác về phương pháp kết tập, ta hãy xét bài toán thực thi
một bộ đếm nhị phân k bít đếm lên từ 0 Ta dùng một mảng A[0 k-1] bit, ở đó
length[A] = k, làm bộ đếm Một số nhị phân x được lưu trữ trong bộ đếm có bit
cấp thấp nhất của nó trong A[0] và bit cao nhất trong A[k-1], sao cho
Hình 1.1 này biểu diễn một đếm nhị phân 8-bit khi giá trị của nó đi từ 0 đến
16 theo một dãy 16 phép toán INCREMENT Các bít lật để đựơc giá trị kế tiếp được tô bóng Chi phí thực hiện để lật các bít được nêu ở bên phải Lưu ý, tổng chi phí không bao giờ lớn hơn hai lần tổng phép toán INCREMENT
Tổng mức chi phí Giá trị bộ
đếm
Trang 12Thuật toán INCREMENT
i và cho ra một phép mang sang 1để được cộng vào vị trí i =i+1 ở lần lặp tiếp theo của vòng lặp Bằng không vòng lặp kết thúc, và như vậy nếu i<k, chúng ta biết A[i]=0 , sao cho phép cộng 1 vào vị trí i thì lật 0 thành 1, được chỉ ra ở dòng
6 Chi phí của mỗi phép toán INCREMENT là tuyến tính với số bit được lật.Giống như trong ví dụ stack, một sự phân tích nhanh cho ra một cận tuy là đúng nhưng không chặt Một đợt thi hành INCREMENT sẽ mất một thời gian
Θ(k) trong trường hợp xấu nhất, ở đó mảng A chứa tất cả 1 Như vậy, một dãy n phép toán INCREMETN trên một bộ đếm zero từ đầu sẽ mất một thời gian O(nk) trong trường hợp xấu nhất
Bây giờ áp dụng phương pháp kết tập vào bài toán này ta có phân tích chặt chẽ hơn để cho ra chi phí trường hợp xấu nhất là O(n) với một dãy n INCREMENT bằng cách nhận xét rằng không phải tất cả các bit đều lật mỗi lần INCREMENT được gọi Như hình 1.1 đã nêu, A[0] lật một lần INCREMENT được gọi Bit cấp cao kế tiếp, A[1], chỉ lật mọi lần khác: một dãy n phép toán INCREMETN trên một bộ đếm zero từ đầu sẽ khiến A[1] lật n/2 lần Cũng vậy, bit A[2] chỉ lật cứ 4 lần hoặc n/4 lần trong một dãy n INCREMENT Nói
Trang 13chung, với i=0,1,…, lg n , bit A[i] lật n/2i lần trong một dãy n phép toán INCREMENT trên một bộ đếm zero từ đầu Với i>lg n , bit A[i] không hề lật
gì cả Như vậy, tổng của các lần lật trong dãy là:
n n
Bài tập:
1 Nếu một phép toán MULTIPUSH được gộp vào tập hợp các phép toán ngăn xếp, thì cận O (1) trên chi phí khấu trừ của các phép toán ngăn xếp tiếp tục đứng vững không?
2 Chứng tỏ nếu một phép toán DECREMENT được gộp trong ví dụ bộ đếm
k- bit, n phép toán có thể có chi phí tối đa là Θ(nk) thời gian.
3 Một dãy n phép toán được thực hiện trên một cấu trúc dữ liệu, phép toán thứ
i có chi phí i nếu i là một lũy thừa chính xác của 2, mà bằng không là 1 Dùng phương pháp kết tập của phân tích để xác định chi phí khấu trừ của mỗi phép toán
2.2 Phương pháp kế toán: The accounting method
Trong phương pháp kế toán của phân tích khấu trừ, ta gán các khoản tính công khác biệt cho các phép toán khác nhau, với vài phép toán được tính công nhiều hoặc ít hơn chi phí thực tế của chúng Khoản mà ta tính công cho một phép toán được gọi là mức hao phí khấu trừ của nó Khi mức hao phí khấu trừ của phép toán vượt quá chi phí thực tế của nó, sự khác biệt được gán cho các đối tượng cụ thể trong cấu trúc dữ liệu dưới dạng khoản tín dụng
Về sau khoản tín dụng có thể được dùng để giúp thanh toán cho những phép toán có mức hao phí khấu trừ nhỏ hơn chi phí thực tế của chúng Như vậy,
Trang 14ta có thể xem mức hao phí khấu trừ của một phép toán dưới dạng đang được tách giữa chi phí thực tế của nó với khoản tín dụng hoặc được ký gửi hoặc được dùng hết Điều này rất khác với phương pháp kết tập, ở đó tất cả các phép toán
có cùng mức hao phí khấu trừ
Ta phải chọn mức hao phí khấu trừ của các phép toán thật cẩn thận Nếu muốn phân tích bằng mức hao phí khấu trừ để chứng tỏ mức hao phí trung bình trong trường hợp xấu nhất của mỗi phép toán là nhỏ, tổng mức hao phí khấu trừ của một dãy các phép toán phải là một cận trên trên tổng mức hao phí của dãy
đó Hơn nữa, như trong phương pháp kết tập, mối quan hệ này phải áp dụng cho tất cả các dãy phép toán Như vậy, tổng khoản tín dụng kết hợp với cấu trúc dữ liệu phải luôn là không âm, bởi nó biểu thị cho khoản mà tổng các mức hao phí khấu trừ gánh chịu vượt quá tổng các chi phí thực tế gánh chịu Nếu tổng khoản tín dụng được phép trở thành âm (kết quả của việc tính công thiếu sớm cho các phép toán với hứa hẹn hoàn trả khoản thanh toán về sau), thì tổng các mức hao phí khấu trừ gánh chịu vào thời điểm đó sẽ nằm dưói tổng các chi phí thực tế gánh chịu; với dãy các phép toán lên tới vào thời điểm đó, tổng mức hao phí khấu trừ sẽ không phải là một cận trên trên tổng chi phí thực tế Như vậy, ta phải thận trong tổng khoản tín dụng trong cấu trức dữ liệu không bao giờ trở thành âm
Các phép toán ngăn xếp
Để minh họa phương pháp kế toán của phân tích khấu trừ, ta hãy trở lại ví
dụ ngăn xếp Chắc bạn còn nhớ các chi phí thực tế của các phép toán là
MULTIPOP min(k, s),
Trong đó k là đối số cung cấp cho MULTIPOP và s là kích cỡ ngăn xếp khi
nó được gọi Hãy gán các mức hao phí khấu trừ sau đây:
Trang 15POP 0,
MULTIPOP 0,
Lưu ý, mức hao phí khấu trừ của MULTIPOP là hằng (0), trong khi đó chi phí thực tế lại biến đổi Ở đây, cả ba mức hao phí khấu trừ là O(1), mặc dù nói chung các mức hao phí của các phép toán đang được xem xét có thể khác nhau theo tiệm cận
Giờ đây ta có thể thanh toán cho bất kỳ dãy phép toán ngăn xếp nào bằng cách tính mức hao phí khấu trừ Giả sử ta dùng một tờ đô la để biểu thị cho mỗi đơn vị của mức hao phí Ta bắt đầu một ngăn xếp rỗng Hãy nhớ lại tương tự của đoạn 10.1 giữa cấu trúc dữ liệu ngăn xếp và một ngăn xếp các đĩa trong một quán ăn tự phục vụ Khi đẩy một đĩa lên ngăn xếp, ta dùng 1 đô la để thanh toán cho chi phí thực tế của lần đẩy và được để lại một khoản tín dụng 1 đô la (từ 2
đô la được tính công), mà ta đặt lên trên đĩa Tại một điểm bất kỳ theo thời gian, mọi đĩa trên xếp đền có một đô la khoản tín dụng nói trên
Đô la được lưu trữ trên đĩa là khoản trả trước cho mức hao phí của tiến trình kéo nó ra từ ngăn xếp Khi ta thi hành một phép toán POP, ta không tính công cho phép toán và thanh toán mức phí thực tế của nó bằng khoản tín dụng lưu trữ trong ngăn xếp Để kéo ra một đĩa, ta lấy đô la tín dụng ra khỏi đĩa và dùng nó để thanh toán mức phí thật tế của phép toán Như vậy, nhờ tính công thêm một ít cho phép toán PUSH, ta không cần tính công cho phép toán POP.Hơn nữa, ta cũng chẳng cần tính công cho các phép toán MULTIPOP Để kéo ra đĩa đầu tiên, ta lấy đô la của khoản tín dụng ra khỏi đĩa và dùng nó để thanh toán chi phí thực tế của một phép toán POP Để kéo ra một đĩa thứ hai, ta lại có một đô la tín dụng trên đĩa để thanh toán cho phép toán POP, và cứ tiếp tục như thế Như vậy, ta luôn tính công trước ít nhất đủ để thanh toán cho các phép toán MULTIPOP Nói cách khác, do mỗi đĩa trên ngăn xếp có 1 đô la tín dụng trên nó, và ngăn xếp luôn có một số đĩa không âm, ta bảo đảm khoản tín dụng luôn không âm Như vậy, với bất kỳ dãy nào n phép toán PUSH, POP và