2008-10-31 30 views
30

Tôi đã nói với mã như:Trong Java, với chuỗi x, chi phí thời gian chạy của s.length() là bao nhiêu? Có phải O (1) hoặc O (n)?

for (int i = 0; i < x.length(); i++) { 
    // blah 
} 

thực sự là O (n^2) vì các cuộc gọi lặp đi lặp lại để x.length(). Thay vào đó, tôi nên sử dụng:

int l = x.length(); 
for (int i = 0; i < l; i++) { 
    // blah 
} 

Điều này có đúng không? Là chuỗi chiều dài được lưu trữ như là một thuộc tính số nguyên riêng của lớp String? Hoặc không String.length() thực sự đi bộ toàn bộ chuỗi chỉ để xác định chiều dài của nó?

+1

Ngay cả khi tính chiều dài của chuỗi là O (n), tổng độ phức tạp sẽ vẫn không phải là O (n^2). Độ dài được tính một lần và được sử dụng làm giá trị biên trong vòng lặp for, nó không được tính trên mỗi lần lặp. –

+0

Theo như tôi biết, các giá trị biên không được lưu trong bộ nhớ cache. Điều gì nếu ranh giới đã được sửa đổi trong vòng lặp? –

+2

Ranh giới được tính toán mỗi lần. Hãy nhớ rằng, kiểm tra vòng lặp for chỉ là một biểu thức tùy ý. Trình biên dịch không thực sự quan tâm những gì trong đó, và không thể đưa ra các giả định. Bạn có thể dễ dàng gọi một phương thức trả về một cái gì đó khác nhau mỗi lần. – Herms

Trả lời

51

Không, độ dài của chuỗi java là O (1) vì lớp chuỗi của java lưu trữ độ dài dưới dạng trường.

Lời khuyên bạn đã nhận được là đúng với C, trong số các ngôn ngữ khác, chứ không phải java. C strlen đi qua mảng char tìm kiếm ký tự kết thúc chuỗi. Joel đã nói về nó trên podcast, nhưng trong ngữ cảnh của C.

+0

Lưu ý rằng mã sẽ vẫn thực hiện cuộc gọi phương thức trên mỗi lần lặp (trình biên dịch không biết giá trị sẽ không thay đổi). Di chuyển cuộc gọi bên ngoài điều khiển vòng lặp sẽ loại bỏ cuộc gọi phương thức. Có thể nói rằng, không có khả năng sẽ gây ra nhiều thay đổi trong thời gian thực hiện vòng lặp này –

+5

Một JIT hiện đại có thể sẽ nhận thấy độ dài đó là một trình rút gọn đơn giản của một lớp cuối cùng trả về giá trị nguyên thủy cuối cùng và thay thế gọi phương thức với chính giá trị int. –

+0

sk - Tôi dường như nhớ lại khi thấy một blog đã kiểm tra tối ưu hóa JIT về độ dài() và đã chứng minh điều đó là sự thật. –

-2

Theo this, độ dài là trường của đối tượng String.

0

Tôi không biết liên kết sẽ dịch tốt như thế nào, nhưng hãy xem source of String#length. Tóm lại, #length() có độ phức tạp O (1) vì nó chỉ trả lại một trường. Đây là một trong nhiều ưu điểm của các chuỗi bất biến.

+0

Tính bất biến không liên quan gì đến nó. Bạn có thể có một lớp chuỗi có thể thay đổi để theo dõi độ dài của nó, giống như bạn có thể với một chuỗi không thay đổi (ví dụ, StringBuilder). Và bạn có thể có một chuỗi không thể thay đổi mà không (const char * trong C). – Herms

+0

Nhưng bất biến không đảm bảo rằng bạn chỉ phải tính giá trị cho độ dài một lần khi đối tượng được tạo. Nếu đối tượng có thể thay đổi, nó sẽ yêu cầu một phép tính mới cho mọi lời gọi của một phương thức mutator. Trả tiền cho tôi ngay bây giờ hoặc trả tiền cho tôi sau khi nói đi. – laz

+0

Nói đúng, cả hai đều đúng; nhưng đồng thời ném một cờ lê vào toàn bộ chuyện. Cố gắng để giữ cho một lĩnh vực phụ trợ được cập nhật khi thay đổi cấu trúc dữ liệu không đồng bộ về cơ bản là không thể, vì vậy thường dài() được tính toán hơn là truy cập trong việc triển khai chuỗi có thể thay đổi. –

12

Trái với những gì đã được nói cho đến thời điểm này, không có gì đảm bảo rằng String.length() là hoạt động liên tục trong số lượng ký tự chứa trong chuỗi. Cả javadocs cho lớp String cũng như Đặc tả Ngôn ngữ Java đều yêu cầu String.length là hoạt động liên tục trong thời gian.

Tuy nhiên, trong quá trình thực hiện của Sun, String.length() là hoạt động liên tục trong thời gian. Cuối cùng, thật khó để tưởng tượng tại sao việc thực hiện bất kỳ sẽ có một thời gian thực hiện không liên tục cho phương pháp này.

+2

Không chắc chắn, tôi nghĩ rằng nó là an toàn để * giả định * rằng String.length * sẽ luôn luôn * được thời gian liên tục ... vì những lý do mà bạn đã đưa ra. –

4

Bạn nên lưu ý rằng phương thức length() trả về số lượng điểm mã UTF-16, không nhất thiết giống với số ký tự trong tất cả các trường hợp.

OK, cơ hội thực sự ảnh hưởng đến bạn khá mỏng, nhưng không có hại khi biết điều đó.

+0

http://java.sun.com/javase/6/docs/api/java/lang/Character.html#unicode Về cơ bản, một số ký tự phải được thể hiện bằng hai giá trị char. Vì length() là kích thước của mảng char [], nó có thể không giống như số ký tự. Nhưng, như buồn bã nói, điều đó rất hiếm. –

3

Chuỗi lưu trữ độ dài trong một biến riêng biệt. Vì chuỗi là bất biến, độ dài sẽ không bao giờ thay đổi. Nó sẽ cần phải tính toán chiều dài chỉ một lần khi nó được tạo ra, điều này xảy ra khi bộ nhớ được cấp phát cho nó. Do đó O của nó (1)

4

Trong trường hợp bạn không biết bạn có thể viết nó theo cách này:

for (int i = 0, l = x.length(); i < l; i++) { 
    // Blah 
} 

Nó chỉ là một chút bụi từ l 's phạm vi nhỏ hơn.

Các vấn đề liên quan