You are on page 1of 4

ĐỘ PHỨC TẠP THUẬT TOÁN

Thời gian mà máy tính khi thực hiện một thuật toán không chỉ phụ thuộc vào bản thân thuật
toán đó, ngoài ra còn tùy thuộc từng máy tính. Để đánh giá hiệu quả của một thuật toán, ta có thể
xét số các phép tính phải thực hiện khi thực hiện thuật toán này. Thông thường số các phép tính
được thực hiện phụ thuộc vào là độ lớn của đầu vào. Vì thế độ phức tạp thuật toán là một hàm
phụ thuộc đầu vào.
Để ước lượng độ phức tạp của một thuật toán ta thường dùng khái niệm Big O

TÍNH TOÁN ĐỘ PHỨC TẠP


Bạn muốn một phương pháp để tính toán số lượng thao tác cần thiết để chạy từng thuật toán,
dựa trên kích thước đầu vào n. May mắn thay, điều này có thể được thực hiện một cách tương
đối dễ dàng bằng cách sử dụng Ký hiệu Big O , nó biểu thị độ phức tạp thời gian trong trường
hợp xấu nhất theo hàm của n khi n tiến tới vô cùng lớn. Độ phức tạp là một giới hạn trên cho số
lượng bước mà thuật toán yêu cầu dựa trên kích thước đầu vào. Trong ký hiệu Big O, chúng ta
biểu thị độ phức tạp của một hàm là O(f(n)), nơi mà các yếu tố hằng số và các thuật ngữ bậc thấp
thường bị bỏ qua từ f(n). Chúng ta sẽ thấy một số ví dụ về cách nó hoạt động, như sau:
Mã code sau đây có độ phức tạp O(1), bởi vì nó thực hiện một số lượng hằng số các thao tác:

Các thao tác đầu ra đầu vào cũng được giả định là O(1). Trong các ví dụ sau đây, ta giả sử
rằng mã bên trong các vòng lặp là O(1).
Độ phức tạp về thuật toán của vòng lặp là số lần lặp mà vòng lặp chạy. Các ví dụ mã sau đây đều
là O(n):

Vì chúng ta bỏ qua các hệ số không đổi và các số hạng bậc thấp hơn nên các ví dụ sau đây cũng
là O(n):

Câu lc b lp trình Fullhouse | FULLHOUSE


Ta có thể tìm độ phức tạp thuật toán của nhiều vòng lặp bằng cách nhân độ phức tạp thuật
toán của mỗi vòng lặp với nhau. Ví dụ sau đây là O(nm), bởi vòng lặp bên ngoài chạy O(n) lần
lặp lại và vòng lặp bên trong chạy O(m) lần lặp lại:

Trong ví dụ này, vòng lặp bên ngoài chạy O(n) lần, và vòng lặp bên trong chạy từ 1 đến n
lần (tức là tối đa là n) vì ký hiệu Big O tính toán độ phức tạp thời gian trong trường hợp xấu
nhất, chúng ta coi vòng lặp bên trong như một yếu tố phụ thuộc vào n. Do đó, đoạn mã này có độ
phức tạp là O(n2 ¿

Nếu một thuật toán chứa nhiều khối mã khác nhau, thì độ phức tạp thời gian của nó sẽ là độ
phức tạp tệ nhất trong số các khối đó. Ví dụ, đoạn mã sau đây có thể được hiểu là O(n2 ¿:

Đoạn mã sau đây có độ phức tạp là O(n2 +m ), bởi vì nó bao gồm hai khối mã có độ phức tạp
lần lượt là O(n2 ) và O(m) và không có khối mã nào trong hai khối đó có độ phức tạp thấp hơn so
với khối mã kia.

ĐỘ PHỨC TẠP PHỔ BIẾN VÀ NHỮNG HẠN CHẾ THƯỜNG GẶP


Các yếu tố độ phức tạp phát sinh từ một số thuật toán và cấu trúc dữ liệu phổ biến như sau:
 Các công thức toán học chỉ tính toán một kết quả: O(1)
 Tìm kiếm nhị phân: O(log n )

Câu lc b lp trình Fullhouse | FULLHOUSE


 Danh sách set/map hoặc priority queue : O(log n ) cho mỗi thao tác
 Phân tích thành phân số nguyên tố của một số nguyên hoặc kiểm tra tính nguyên tố hoặc
hợp số của một số nguyên một cách đơn giản: O(√ n)
 Đọc n phần tử đầu vào: O(n)
 Lặp lại danh sách gồm n phần tử: O(n)
 Sắp xếp: thường là O(nlog n ) cho các thuật toán sắp xếp mặc định (mergesort,
Collections.sort, Arrays.sort)
 Hàm Java: Arrays.sort sử dụng thuật toán quicksort trên các kiểu dữ liệu nguyên thủy
(primitives): O(n2 )
 Lặp qua tất cả các tập con có k phần tử từ các phần tử đầu vào: O(n k). Ví dụ, lặp qua tất
cả các bộ ba phần tử là O(n3 )
 Lặp qua tất cả các tập con: O(2n)
 Lặp qua tất cả các hoán vị: O(n!)
Dưới đây là các giới hạn trên giá trị của n cho từng độ phức tạp thời gian. Bạn có thể thực
hiện được với giá trị n lớn hơn, nhưng đây là giới hạn tối đa thường dùng để kiểm tra nhanh xem
một thuật toán có khả thi hay không.
n Độ phức tạp có thể xảy
ra
n ≤ 10 O(n!),O(n7 ),O(n6 )
n ≤ 20 O(2n.n),O(n5 )
n ≤ 80 O(n 4)
n ≤ 400 O(n3 )
n ≤ 7500 O(n2)
n ≤ 7.104 O(n√ n)
n ≤ 5.105 O(nlog n )
n ≤ 5.106 O(n)
n ≤ 1018 O(log 2 n), O(log n ),O(1)

HỆ SỐ HẰNG SỐ
Hệ số hằng số (Constant factor) đề cập đến ý tưởng rằng các phép toán khác nhau có cùng
độ phức tạp có thể mất thời gian chạy khác nhau một chút. Ví dụ, ba phép cộng sẽ mất thời gian
hơn một phép cộng đơn lẻ. Một ví dụ khác là mặc dù tìm kiếm nhị phân trên một mảng và chèn
vào một tập hợp đã được sắp xếp đều có độ phức tạp O(log n ), tìm kiếm nhị phân thường nhanh
hơn.
Hệ số hằng số hoàn toàn bị bỏ qua trong ký hiệu Big O. Điều này thường là ổn trong hầu hết
các trường hợp, nhưng nếu giới hạn thời gian cụ thể rất chặt, bạn có thể gặp phải vượt quá giới
hạn thời gian (TLE) với độ phức tạp dự kiến. Khi điều này xảy ra, quan trọng là phải nhớ đến hệ
số hằng số. Ví dụ, một đoạn mã lặp qua tất cả các bộ ba phần tử có thứ tự chạy trong thời gian
O(n3 ) có thể được tăng tốc lên gấp 6 lần nếu chúng ta chỉ cần lặp qua tất cả các bộ ba phần tử
không có thứ tự.

ĐỊNH NGHĨA CHÍNH THỨC CỦA KHÁI NIỆM Big O


Cho f và g là các hàm không âm từ ℝ ≥ 0 đến ℝ ≥ 0. Nếu tồn tại các hằng số dương n 0 và c
sao cho f(n) ≤ c. g(n) khi n ≤ n 0 , chúng ta nói rằng f(n) = O(g(n))

Câu lc b lp trình Fullhouse | FULLHOUSE


Do đó chúng ta có thể nói rằng độ phức tạp thời gian của một hàm tuyến tính, O(n), cũng là
O(n/2), O(2n), O(n2 ), O(2n), O(n n),v.v.. Tuy nhiên, Thường thì chúng ta chỉ viết hàm đơn giản
nhất trong số các hàm đó, tức là hàm giới hạn nhất. Trong trường hợp của hàm tuyến tính ở trên,
đó chính là O(n)

Câu lc b lp trình Fullhouse | FULLHOUSE

You might also like