Vì sao thời gian thực hiện thuật toán là quan trọng nhất

Một số anh em tham gia CodeLearn nhiều khi chạy bài tập bị quá thời gian. Lí do là code của các bạn chạy mất quá nhiều thời gian

Tại sao thời gian lại quan trọng?

  • Trong 1 số chương trình, sản phẩm phần mềm nếu xử lí quá chậm sẽ gây khó chịu cho người dùng ứng dụng. Lấy ví dụ bạn mua hàng mà bấm nút tìm kiếm mất 1 phút thì bạn có khó chịu không? Nếu thời gian tìm kiếm của google cho mỗi từ khoá tốn 5 giây thì liệu google có trở thành công cụ tìm kiếm số 1 thế giới hay không?
  • Thời gian chạy lâu gây tốn CPU, làm giảm số lượng người dùng mà máy tính/máy chủ có thể phục vụ người dùng (với ứng dụng có máy chủ)

Do đó, các bài tập ở CodeLearn khi đưa ra đều có giới hạn thời gian để người dùng suy nghĩ, lựa chọn giải thuật phù hợp. Đó là thời gian chạy.

Vậy độ phức tạp thuật toán là gì, có liên quan gì tới thời gian chạy?

1. Độ phức tạp thuật toán là gì?

Về lý thuyết, các bạn có thể tìm theo từ khoá algorithm complexity hoặc đọc ở đây 

Nói ngắn gọn thì, mỗi một bài toán có giới hạn/kích thước của đầu vào. Độ phức tạp thuật toán là 1 khái niệm/định nghĩa/định lượng tương đối thể hiện số phép toán của giải thuật so với kích thước của đầu vào.

Ví dụ cho dễ hiểu:

  • Một mảng có n phần tử. Hãy tìm phần tử lớn nhất trong mảng
    Bài này tất nhiên chẳng có cách nào khác, bạn sẽ duyệt toàn bộ phần tử trong mảng (duyêt qua mảng n lần) để tìm ra phần tử lớn nhất. Độ phức tạp thuật toán ở đây có thể hiểu là O(n) (chạy qua n phần tử để tìm kiếm)
  • Một mảng có n phần tử. Hãy sắp xếp mảng theo thứ tự tăng dần
    Bài này quá quen nhỉ. Bạn thường dùng 2 vòng lặp từ i->n và từ j->n để đổi chỗ. Lúc này độ phức tạp thuật toán là O(n^2)
    Tuy nhiên với 1 số giải thuật sắp xếp như quicksort, độ phức tạp chỉ là O(n*log(n)). 
    Bạn thử thay n=10, thì giải thuật bên trên có thể hiểu sẽ chạy xấp xỉ là 10*10=100 phép tính, nhưng giải thuật Quicksort thì chỉ dùng khoảng 10 phép tính. Với n rất nhỏ, 100 hay 1000 thì chương trình đều chạy có thời gian xấp xỉ bằng nhau. Thật ra kết quả là có chênh, nhưng quá nhỏ nên các bạn không thấy. Nhưng với n cực lớn, ví dụ 100000 phần tử, thì thuật toán có độ phức tạp O(n^2) với O(nlogn) là cực kì khác biệt.
  • Cho một mảng có n phần tử đã sắp xếp. Hãy tìm xem có phần tử x hay không?
    Bài này nếu các bạn duyệt từ 1 tới n để tìm xem có x hay không, độ phức tạp vẫn là O(n)
    Tuy nhiên nếu để ý, do mảng này là mảng đã sắp xếp, nên bạn có thể áp dụng thuật toán tìm kiếm nhị phân. Tức là bạn chặt dãy ra làm 2, xem X lớn hay nhỏ hơn phần tử ở giữa, nếu nhỏ hơn thì tìm kiếm ở đoạn dưới, nếu lớn hơn thì tìm kiếm ở đoạn trên. Cứ như vậy bạn chặt dãy ra làm 2 liên tục, thì số phép tìm kiếm sẽ là log2 của n, sẽ nhanh hơn nhiều lần so với giải thuật tìm kiếm tuần tự bên trên.

    Nếu không tin, hãy thử code và đo thời gian với số n cực lớn nhé.

Và như bạn thấy đó, máy tính của chúng ta có tốc độ là khác nhau. Có thể hiểu là, cùng có 100000 phép tính, thì máy của ông A có thể chạy nhanh hơn máy ông B. Do đó, độ phức tạp giải thuật có thể thể hiện tương đối chính xác thuật toán nào nhanh hay chậm, so với việc đo thời gian chạy trên các máy khác nhau. Có nhiều bạn cũng comment tại sao chạy ở máy ở nhà thì không quá thời gian, lên server thì bị quá. Cũng là cùng lí do như thế.

2. Chọn giải thuật phù hợp

Như giải thích ở trên, độ phức tạp thuật toán có thể hiểu là số phép toán thực hiện của một hàm dựa trên kích thước tối đa của dữ liệu. Độ phức tạp thuật toán (trên cùng 1 máy) có thể hiểu là nó tỉ lệ thuận (1 cách tương đối) với thời gian chạy.
Mình xem nhiều bài tập của các bạn thấy các bạn chọn giải thuật không phù hợp dẫn đến thời gian chạy cực lâu. Mình ví dụ nha:

  • Tính tổng các số nguyên từ 1 -> nBài này ai dùng công thức thì 1 dòng là ra: n*(n+1)/2. Giải thuật này có độ phức tạp là O(1) (1 phép toán)Với các bạn dùng vòng lặp từ 1 -> n để tính tổng, độ phức tạp là O(n). Với n bằng 1 tỷ, tương đương bạn thực hiện 1 tỷ lần phép toán cộng

    Bạn hiểu thời gian chạy chênh lêch lớn như thế nào rồi chứ?

  • Bài toán kiểm tra số nguyên tốBài này cũng đơn giản thôi. Nhưng nhiều bạn cũng chọn giải thuật phức tạp

    Các bạn chạy để kiểm tra từ 1->n, độ phức tạp là O(n). Các bạn chạy từ 1->sqrt(n) (căn bậc 2 của n) thì đã giảm rất nhiều phép toán, nếu bạn nào còn tăng bước nhảy lên bằng 2 (kiểm tra có chia hết cho 2,3, 5, 7, 9, 11, ... thay vì 2,3,4,5,6, ....) thì số phép toán lại giảm thêm nữa.


    Do đó, ngay từ bài số nguyên tố, việc sử dụng vòng lặp để kiểm tra các bạn đã có thể tối ưu cực nhiều. Bạn có thể thử bài này với số n cực lớn và gọi đi gọi lại nhiều lần để đo độ chênh lệch thời gian nha.
  • Bài toán tính tổng các số nguyên tố nhỏ hơn hay bằng n
    Bài này cũng giống bài trên. Độ phức tạp giải thuật của việc kiểm tra số nguyên tố giả sử đang là O(n)
    Nếu với mỗi 1 số từ 1 tới n, bạn lặp lại việc kiểm tra 1 cách thông thường, độ phức tạp thuật toán của giải thuật này là O(n^2)
    Bài này nếu cho n=1000000, đa phần sẽ ko chạy được. Do số phép toán cực nhiều.
    Đối với bài này, nếu bạn dùng sàng nguyên tố (ý tưởng là loại bỏ các hợp số), thì độ phức tạp thuật toán xấp xỉ O(nlogn). Chi tiết tham khảo ở đây nhé.

3. Tổng kết

Hiểu rõ về khái niệm độ phức tạp thuật toán và cách tính toán độ phức tạp của giải thuật (của mình hay của người khác) bạn sẽ tối ưu thuật toán để đáp ứng thời gian chạy tốt hơn ví dụ như làm ứng dụng của bạn chạy nhanh, thời gian phản hồi cao, ... Do đó, với mỗi bài toán hay yêu cầu cụ thể, hãy xem xét độ lớn của tập dữ liệu mà chọn giải thuật cho phù hợp. Chúc anh em thành công

Bài viết theo ý hiểu của mình, cố gắng đơn giản hoá cho anh em, có gì anh em mạnh dạn góp ý nha.

Giới thiệu về cuốn sách này


Page 2

Giới thiệu về cuốn sách này

Vì sao thời gian thực hiện thuật toán là quan trọng nhất

Thông thường khi tính toán độ phức tạp của một thuật giải thì thời gian thực hiện là khía cạnh quan trọng của một giải thuật. Việc chọn một giải thuật đưa đến kết quả nhanh nhất là một đòi hỏi thực tế. Thời gian thực hiện giải thuật bằng chương trình máy tính phụ thuộc vào rất nhiều yếu tố. Bài viết này sẽ giúp các bạn biết một số khái niệm các các phân tích, đánh giá độ phức tạp của một thuật toán.

1. Giới thiệu (Introduction)

–  Như chúng ta được biết thì thời gian thực hiện của giải thuật phụ thuộc vào rất nhiều yếu tố. Trong đó yếu tố cần chú ý nhất là kích thước của dữ liệu đưa vào. Dữ liệu càng lớn thì thời gian xử lý càng chậm. Chẳng hạn như thời gian sắp xếp một dãy số phải chịu ảnh hưởng của các số thuộc dãy số đó. Nếu gọi n là kích thước dữ liệu đưa vào thì thời gian thực hiện của giải thuật có thể biểu diễn một cách tương đối như một hàm của n:  T(n).

–  Phần cứng máy

Vì sao thời gian thực hiện thuật toán là quan trọng nhất
tính, ngôn ngữ viết chương trình và chương trình dịch  ngôn ngữ ấy đều ảnh hưởng tới thời gian thực hiện. Những yếu tố này không giống nhau trên các loại máy vì vậy không thể dựa vào chúng khi xác định T(n)  -> T(n) không thể biểu diễn bằng đơn vị thời gian (giờ, phút, giây..).

–  Nếu thời gian thực hiện một giải thuật là  T1(n) = n2

và thời gian thực hiện của một giải thuật khác là T2(n) = 100n  thì khi n đủ lớn thời gian thực hiện của giải thuật T2 rõ ràng nhanh hơn T1. Khi đó, nếu nói rằng thời gian thực hiện giải thật tỉ lệ thuận với n hay tỉ lệ thuận với  n2 cũng cho ta một cách đánh giá tương đối về tốc độ thực hiện của giải thuật đó khi n khá lớn.

–  Cách đánh giá thời gian thực hiện của giải thuật độc lập với máy tính và các yếu tố liên quan tới máy tính như vậy sẽ dẫn tới khái niệm gọi là độ phức tạp của giải thuật.

2.  Các ký pháp để đánh giá độ phức tạp tính toán.

Cho một giải thuật thực hiện trên dữ liệu với kích thước n. Giả sử  T(n) là thời gian thực hiện một giải thuật đó,  g(n) là một hàm xác định dương với mọi n. Khi đó ta nói độ phức tạp tính toán của giải thuật là:

–  O(g(n))  nếu tồn tại các hằng số dương c và n0 sao cho T(n) ≤ c.g(n) với mọi n ≥ n0 . Ký  pháp này được gọi là ký pháp chữ O lớn (big-oh notation). Trong ký pháp chữ O lớn, hàm  g(.) được gọi là giới hạn trên (asymptotic upper bound) của hàm T(.).

–  Ω(g(n)) nếu tồn tại các hằng số dương c và n0 sao cho c.g(n) ≤ T(n) với mọi n ≥ n0. Ký  hiệu này gọi là ký pháp Ω lớn (big-omega notation). Trong ký pháp Ω lớn, hàm g(.) được  gọi là giới hạn dưới (asymptotically lower bound) của hàm T(.).

–  Θ(g(n)  nếu tồn tại các hằng số dương c1, c2 và n0 sao cho c1.g(n) ≤ f(n) ≤ c2.g(n)  với mọi n  ≥ n0 . Ký pháp này được gọi là ký pháp Θ lớn (big-theta notation). Trong ký pháp Θ lớn,  hàm g(.) được gọi là giới hạn chặt (asymptotically tight bound) của hàm T(.).

Hình dưới đây:  biểu diễn đồ thị của ký pháp Θ lớn, Ο lớn và Ω lớn. Dễ thấy rằng T(n) = Θ(g(n)) nếu và chỉ nếu T(n) = O(g(n)) và T(n) = Ω(g(n))

Vì sao thời gian thực hiện thuật toán là quan trọng nhất

–  Ta nói độ phức tạp tính toán của giải thuật là:

  • o(g(n)) nếu với mọi hằng số dương c, tồn tại một hằng số dương n0 sao cho T(n) ≤ c.g(n)  với mọi n ≥ n0. Ký pháp này gọi là ký pháp chữ o nhỏ (little-oh notation).
  • ω(g(n)) nếu với mọi hằng số dương c, tồn tại một hằng số dương  n0 sao cho c.g(n) ≤ T(n)  với mọi n ≥ n0 . Ký pháp này gọi là ký pháp ω nhỏ (little-omega notation).

–  Ví dụ:  Nếu T(n) = n2 + 1, thì:

  • T(n) = O(n2 ). Thật vậy, chọn c = 2 và  n0 = 1. Rõ ràng với mọi n  ≥ 1, ta có:  T(n) = n2 + 1 ≤ 2.n2 =  2.g(n).
  • T(n) ≠ o(n2).  Thật vậy, chọn c = 1. Rõ ràng không tồn tại n để: n2 + 1 ≤ n2 , tức là không tồn  tại n0 thoả mãn định nghĩa của ký pháp chữ o nhỏ.

–  Lưu ý rằng không có ký pháp θ  nhỏ.

Một vài tính chất

–  Tính bắt cầu (transitivity): Tất cả các ký pháp nêu trên đều có tính bắt cầu.

  • Nếu f(n) = Θ(g(n)) và g(n) = Θ(h(n)) thì f(n) = Θ(h(n)).
  • Nếu f(n) = O(g(n)) và g(n) = O(h(n)) thì f(n) = O(h(n)).
  • Nếu f(n) = Ω(g(n)) và g(n) = Ω(h(n)) thì f(n) = Ω(h(n)).
  • Nếu f(n) = o(g(n)) và g(n) = o(h(n)) thì f(n) = o(h(n)).
  • Nếu f(n) = ω(g(n)) và g(n) = ω(h(n)) thì f(n) = ω(h(n)).

–  Tính phản xạ (reflectivity):  Các ký pháp “lớn” mới có tính phản xạ.

  • f(n) = Θ(f(n)).
  • f(n) = O(f(n)).
  • f(n) = Ω(f(n)).

–  Tính đối xứng (symmetry): chỉ có ký pháp Θ mới có tính đối xứng.

  • f(n) = Θ(g(n)) nếu và chỉ nếu g(n) = Θ(f(n)).

–  Tính chuyển vị đối xứng (transpose symmetry):

  • f(n) = O(g(n)) nếu và chỉ nếu g(n) = Ω(f(n)).
  • f(n) = o(g(n)) nếu và chỉ nếu g(n) = ω(f(n)).

Để dễ nhớ ta coi các ký pháp Ο, Ω, Θ, ο, ω lần lượt tương ứng với các phép so sánh ≤, ≥, =, <,  >. Từ đó suy ra các tính chất trên.

3.  Xác định độ phức tạp tính toán của giải thuật

Việc xác định độ phức tạp tính toán của một giải thuật bất kỳ có thể rất phức tạp. Tuy nhiên, độ phức tạp tính toán của một số giải thuật trong thực tế có thể tính bằng một số quy tắc đơn

Vì sao thời gian thực hiện thuật toán là quan trọng nhất
giản.

3.1 Quy tắc bỏ hằng số

Nếu đoạn chương trình P có thời gian thực hiện T(n) = O(c1.f(n))  với c1 là một hằng số dương thì có thể coi đoạn chương trình đó có độ phức tạp tính toán là  O(f(n)).

– Chứng minh:

T(n) = O(c1.f(n)) nên ∃ c0 > 0 và ∃ n0 > 0 để T(n) ≤ c0.c1 .f(n) với ∀n ≥ n0 . Đặt C = c0.c1 và  dùng định nghĩa, ta có T(n) = O(f(n)).

Qui tắc này cũng đúng với các ký pháp  Ω, Θ, ο và ω.

3.2  Quy tắc lấy MAX

Nếu đoạn chương trình P có thời gian thực hiện T(n) = O(f(n) + g(n)) thì có thể coi đoạn chương trình đó có độ phức tạp tính toán O(max ( f(n) , g(n) )).

Chứng minh:

T(n) = O(f(n) + g(n)) nên ∃C > 0 và ∃ n0 > 0 để T(n) ≤ C.f(n) + C.g(n), ∀n ≥ n0 .

Vậy T(n) ≤ C.f(n) + C.g(n) ≤ 2C.max(f(n), g(n)) (∀n ≥ n0 ).

Từ định nghĩa suy ra  T(n) = O(max( f(n), g(n) )).

Qui tắc này cũng đúng với các ký pháp  Ω, Θ, ο và ω.

3.3  Quy tắc cộng

Nếu đoạn chương trình P1 có thời gian thực hiện  T1(n) = O(f(n)) và đoạn chương trình P2 có thời gian thực hiện là T2(n) = O( g(n)) thì thời gian thực hiện P1 rồi đến P2 tiếp theo sẽ là:

T1(n) + T2(n) = O(f(n) + g(n))

Chứng minh:

  • T1(n) = O(f(n)) nên ∃ n1 > 0 và c1 > 0 để T1(n) ≤ c1.f(n) với ∀ n ≥ n1.
  • T2(n) = O(g(n)) nên ∃ n2 > 0 và c2 > 0 để T2(n) ≤ c2.g(n) với ∀ n ≥ n2.

Chọn  n0 = max(n1, n2) và c = max(c1, c2) ta có:

Với ∀ n ≥ n0 :

  • T1(n) + T2(n) ≤ c1.f(n) + c2.g(n) ≤ c.f(n) + c.g(n) ≤ c.(f(n) + g(n))

Vậy T1(n) + T2(n) = O(f(n) + g(n)).

–  Quy tắc cộng cũng đúng với các ký pháp Ω, Θ, ο và ω.

3.4  Quy tắc nhân

Nếu đoạn chương trình  P có thời gian thực hiện là  T(n) = O( f(n)). Khi đó, nếu thực hiện  k(n)  lần đoạn chương trình P với  k(n) = O( g(n)) thì độ phức tạp tính toán sẽ là  O( g(n). f(n))

Chứng minh

Thời gian thực hiện k(n) lần đoạn chương trình P sẽ là  k(n)T(n). Theo định nghĩa.

  • ∃ ck ≥ 0 và  nk> 0 để k(n) ≤ ck(g(n)) với ∀ n ≥ nk
  • ∃ cT ≥ 0 và nT > 0 để T(n) ≤ cT (f(n)) với ∀ n ≥ nT

Vậy với ∀ n ≥ max(nT , nk ) ta có k(n).T(n) ≤ cT.ck(g(n).f(n))

– Quy tắc nhân cũng đúng với các ký pháp Ω, Θ, ο và ω.

3.5  Định lý Master (Master Theorem)

Cho a ≥ 1 và b >1 là hai hằng số, f(n) là một hàm với đối số n, T(n) là một hàm xác định trên  tập các số tự nhiên được định nghĩa như sau:

T(n) = a.T(n/b) + f(n)

Ở đây n/b có thể hiểu là ⎣n/b⎦ hay ⎡n/b⎤. Khi đó:

Vì sao thời gian thực hiện thuật toán là quan trọng nhất

–  Định lý Master là một định lý quan trọng việc phân tích độ phức tạp tính toán của các giải thuật lặp hay đệ quy. Tuy nhiên việc chứng minh định lý khá dài dòng nằm ngoài phạm vi bài viết này.

3.6  Một số tính chất

–  Ta quan tâm chủ yếu đến các ký pháp “lớn”. Rõ ràng ký pháp Θ là “chặt” hơn ký pháp O và   Ω  theo nghĩa: nếu độ phức tạp tính toán của giải thuật có thể viết là  Θ( f(n)) thì cũng có thể viết là O( f(n)) cũng như Ω( f(n)). Dưới đây là một số cách biểu diễn độ phức tạp tính toán qua ký pháp Θ.

  • Nếu một thuật toán có thời gian thực hiện là P(n), trong đó P(n) là một đa thức bậc k thì độ phức tạp tính toán đó có thể viết là  Θ(nk ).
  • Nếu một thuật toán có thời gian thực hiện là logaf(n). Với b là một số dương, ta nhận thấy  logaf(n) = logab.logb f(n). Tức là: Θ(loga f(n)) = Θ(logb f(n)). Vậy ta có thể nói rằng độ phức  tạp tính toán của thuật toán đó là  Θ(log (f(n))) mà không cần ghi cơ số của logarit.
  • Nếu một thuật toán có độ phức tạp là hằng số, tức là thời gian thực hiện không phụ thuộc vào kích thước dữ liệu vào thì ta ký hiệu độ phức tạp tính toán của thuật toán đó là Θ(1).

–  Dưới đây là một số hàm số hay dùng để ký hiệu độ phức tạp tính toán và bảng giá trị chúng để tiện theo dõi sự tăng của hàm theo đối số n.

Vì sao thời gian thực hiện thuật toán là quan trọng nhất

–  Ví dụ: Thuật toán tính tổng các số từ 1 đến n.

+  Nếu viết theo sơ đồ sau:

Vì sao thời gian thực hiện thuật toán là quan trọng nhất

Đoạn chương trình ở các dòng 1, 2 và 4 có độ phức tạp tính toán là Θ(1). Vòng lặp ở dòng 3 lặp n lần phép gán S := S + i , nên thời gian tính toán tỉ lệ thuận với n. Tức là độ phức tạp tính toán là Θ(n). Dùng quy tắc cộng và quy tắc lấy max ta suy ra độ phức tạp tính toán của giải thuật trên là Θ(n).

+  Còn nếu viết theo sơ đồ sau:

Vì sao thời gian thực hiện thuật toán là quan trọng nhất

Độ phức tạp tính toán trong trường hợp này là Θ(1), thời gian tính toán không phụ thuộc vào n.

3.7  Phép toán tích cực

–  Dựa vào những nhận xét đã nêu ở trên về các quy tắc khi đánh giá thời gian thực hiện giải thuật, ta chú ý đặc biệt đến một phép toán mà ta gọi là phép toán tích cực trong một đoạn chương trình. Đó là một phép toán trong một đoạn chương trình mà số lần thực hiện không ít hơn các phép toán khác.

–  Xét 2 đoạn chương trình tính  ex bằng công thức gần đúng:

Vì sao thời gian thực hiện thuật toán là quan trọng nhất

4. Độ phức tạp tính toán với tình trạng dữ liệu vào

Có nhiều trường hợp, thời gian thực hiện giải thuật không phải chỉ phụ thuộc vào kích thước dữ liệu mà còn phụ thuộc vào tình trạng của dữ liệu đó nữa. Chẳng hạn thời gian sắp xếp một dãy số theo thứ tự tăng dần mà dãy đưa vào chưa có thứ tự sẽ khác với thời gian sắp xếp một dãy số đã sắp xếp rồi hoặc đã sắp xếp theo thứ tự ngược lại. Lúc này, khi phân tích thời gian thực hiện giải thuật ta sẽ xét trường hợp tốt nhất, trường hợp trung bình và trường hợp xấu nhất.

Vì sao thời gian thực hiện thuật toán là quan trọng nhất

–  Phân tích thời gian thực hiện giải thuật trong trường hợp xấu nhất (worst-case analysis): với một kích thước dữ liệu n, tìm  T(n) là thời gian lớn nhất khi thực hiện giải thuật trên mọi bộ dữ liệu kích thước n và phân tích thời gian thực hiện giải thuật dựa trên hàm T(n).

–  Phân tích thời gian thực hiện giải thuật trong trường hợp tốt nhất (best-case analysis): với một kích thước dữ liệu n, tìm T(n) là thời gian ít nhất khi thực hiện giải thuật trên mọi bộ dữ liệu kích thước n và phân tích thời gian thực hiện dựa trên hàm  T(n).

–  Phân tích thời gian trung bình thực hiện giải thuật (average-case analysis): giả sử rằng dữ liệu vào tuân theo một phân phối xác suất nào đó (chẳng hạn phân bố đều nghĩa là khả năng chọn mỗi bộ dữ liệu vào là như nhau) và tính toán giá trị kỳ vọng (trung bình) của thời gian chạy cho mỗi kích thước dữ liệu  n (T(n)), sau đó phân tích thời gian thực hiện giải thuật dựa trên hàm T(n).

Khi khó khăn trong việc độ phức tạp tính toán trung bình (bởi việc xác định  T(n) trung bình thường phải dùng tới những công cụ tính toán phức tạp), người ta thường chỉ đánh giá độ phức tạp tính toán trong trường hợp xấu nhất.

Không nên lẫn lộn các cách phân tích trong trường hợp xấu nhất, trung bình, và giá tốt nhất với các ký pháp biểu diễn độ phức tạp tính toán, đây là 2 khái niệm hoàn toàn phần biệt.

Trên phương diện lý thuyết, đánh giá bằng ký pháp Θ(.) là tốt nhất, tuy vậy việc đánh giá bằng ký pháp Θ(.) đòi hỏi phải đánh giá bằng cả ký pháp O(.) lẫn Ω(.). Dẫn tới việc phân tích thuật toán khá phức tạp, gần như phải biểu diễn chính xác thời gian thực hiện giải thuật qua các hàm giải tích. Vì vậy trong những thuật toán người ta thường dùng ký pháp T(n) = O( f(n)).

5. Chi phí thực hiện thuật toán.

–  Khái niệm độ phức tạp thuật toán đặt ra không chỉ dùng để đánh giá chi phí thực hiện một giải thuật về mặt thời gian mà là để đánh giá chi phí thực hiện giải thuật nói chung, bao gồm cả chi phí về thời gian ( lượng bộ nhớ cần sử dụng).

Vì sao thời gian thực hiện thuật toán là quan trọng nhất

–  Thông thường:

  • Nếu ta đánh giá được độ phức tạp tính toán của một giải thuật qua ký pháp Θ, có thể coi phép đánh giá này là chủ chặt và không cần đánh giá qua các ký pháp khác nữa.
  • Nếu không:

+  Để nhấn mạnh tính “tốt” của một giải thuật, các ký pháp O, o thường được sử dụng. Nếu đánh giá được qua O thì không cần đánh giá qua o. Ý nói: chi phí thực hiện thuật toán tối đa là …, ít hơn….

+  Đề cập đến tính toán “tồi” của một giải thuật, các ký pháp Ω, ω thường được sử dụng. Nếu đánh giá được qua Ω thì không cần đánh giá qua ω. Ý nói chi phí thực hiện thuật toán tối thiểu là…, cao hơn…

(Theo A.K.A DSAP Textbox)