Tôi đồng ý với:
- độ phức tạp khấu hao chung của O (1)
hashCode()
việc thực hiện không tốt có thể dẫn đến nhiều va chạm, điều đó có nghĩa là trong trường hợp xấu nhất, mọi đối tượng sẽ vào cùng một nhóm, do đó O ( N ) nếu mỗi nhóm được hỗ trợ bởi a List
.
- kể từ Java 8,
HashMap
thay thế động các Nút (danh sách được liên kết) được sử dụng trong mỗi nhóm bằng TreeNodes (cây đỏ đen khi danh sách lớn hơn 8 phần tử) dẫn đến hiệu suất O ( logN ) kém nhất.
Nhưng, đây không phải là sự thật đầy đủ nếu chúng ta muốn chính xác 100%. Việc triển khai hashCode()
và loại khóa Object
(không thay đổi / lưu trữ hoặc là Bộ sưu tập) cũng có thể ảnh hưởng đến độ phức tạp thực sự trong các điều khoản nghiêm ngặt.
Hãy giả sử ba trường hợp sau:
HashMap<Integer, V>
HashMap<String, V>
HashMap<List<E>, V>
Họ có cùng độ phức tạp không? Vâng, độ phức tạp khấu hao của cái thứ nhất, như mong đợi, O (1). Nhưng, đối với phần còn lại, chúng ta cũng cần tính toán hashCode()
phần tử tra cứu, điều đó có nghĩa là chúng ta có thể phải duyệt qua các mảng và danh sách trong thuật toán của mình.
Giả sử rằng kích thước của tất cả các mảng / danh sách trên là k . Sau đó, HashMap<String, V>
và HashMap<List<E>, V>
sẽ có độ phức tạp khấu hao O (k) và tương tự, trường hợp xấu nhất O ( k + logN ) trong Java8.
* Lưu ý rằng việc sử dụng String
khóa là một trường hợp phức tạp hơn, bởi vì nó là bất biến và Java lưu trữ kết quả của hashCode()
một biến riêng tư hash
, do đó, nó chỉ được tính một lần.
/** Cache the hash code for the string */
private int hash; // Default to 0
Nhưng, ở trên cũng có trường hợp xấu nhất của riêng nó, bởi vì String.hashCode()
việc triển khai Java đang kiểm tra xem hash == 0
trước khi tính toán hashCode
. Nhưng này, có những Chuỗi không trống tạo ra hashcode
số 0, chẳng hạn như "f5a5a608", xem ở đây , trong trường hợp đó, việc ghi nhớ có thể không hữu ích.