2016-03-09 24 views
7

Gần đây tôi đã biết rằng trong bản đồ băm Java 8 sử dụng cây nhị phân thay vì danh sách liên kết và mã băm được sử dụng làm hệ số phân nhánh.I hiểu rằng trong trường hợp va chạm cao, việc tra cứu được giảm xuống O (log n) từ O (n) bằng cách sử dụng cây nhị phân. Câu hỏi của tôi là thực sự làm tốt khi độ phức tạp thời gian phân bổ vẫn là O (1) và có thể nếu bạn buộc lưu trữ tất cả các mục trong cùng một nhóm bằng cách cung cấp cùng một mã băm cho tất cả chìa khóa chúng ta có thể thấy sự khác biệt đáng kể về thời gian nhưng không ai trong tâm trí của họ sẽ làm điều đó.Tại sao bản đồ băm trong Java 8 sử dụng cây nhị phân thay vì danh sách liên kết?

Cây nhị phân cũng sử dụng nhiều không gian hơn danh sách được liên kết đơn lẻ vì nó lưu trữ cả hai nút trái và phải.Why tăng độ phức tạp của không gian khi hoàn toàn không có sự phức tạp về thời gian ngoại trừ một số trường hợp kiểm tra giả mạo.

+2

Đây không phải là cuộc tranh luận. Tôi trích dẫn: * Câu hỏi của tôi là nó thực sự tốt [...] có thể nếu bạn [...] chúng ta có thể thấy sự khác biệt đáng kể nhưng không ai trong tâm trí của họ sẽ làm điều đó. Vì vậy, bạn đang nói nó được thiết kế để xử lý một trường hợp không ai trong tâm trí của họ sẽ làm, do đó các devs ** rõ ràng ** xử lý một trường hợp câm, do đó các devs là câm và bạn giữ Chân lý. Tôi đề nghị viết lại câu hỏi của bạn. – Tunaki

+1

Câu hỏi của bạn không có ý nghĩa. Nếu bạn cho rằng các va chạm băm sẽ không xảy ra, thì cây nhị phân sẽ * không * tiêu thụ nhiều không gian hơn vì cây nhị phân sẽ chỉ được sử dụng khi có * là các xung đột băm. Để chính xác hơn, số lượng va chạm phải vượt quá ngưỡng trước khi triển khai chuyển từ danh sách được liên kết sang cây nhị phân. – Holger

+0

@Tunaki Tôi đặc biệt có nghĩa là những người cố ý cố gắng kịch bản đó để cho thấy lợi thế và nếu tôi nghĩ rằng không có gì hơn để nó tôi sẽ không bao giờ hỏi nó như là một câu hỏi. – user1613360

Trả lời

15

Đây chủ yếu là thay đổi liên quan đến bảo mật. Mặc dù trong tình huống bình thường hiếm khi có thể có nhiều va chạm, nếu các khóa băm đến từ nguồn không đáng tin cậy (ví dụ như các tên tiêu đề HTTP nhận được từ máy khách), thì có thể và không khó để đặc biệt tạo đầu vào, do đó các khóa kết quả sẽ có cùng một hashcode. Bây giờ nếu bạn thực hiện nhiều lần tra cứu, bạn có thể bị từ chối dịch vụ. Có vẻ như có khá nhiều mã trong tự nhiên vốn dễ bị tấn công bởi loại tấn công này, do đó nó đã được quyết định sửa lỗi này ở phía Java.

Để biết thêm thông tin, tham khảo JEP-180.

+0

Đồng ý nhưng làm thế nào người dùng có thể đầu vào để tăng va chạm mà không biết hàm băm cơ bản? – user1613360

+2

@ user1613360, hàm băm cho 'Chuỗi' là nổi tiếng và [được ghi lại] (https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#hashCode--), vì vậy nó không phải là một vấn đề lớn. Mọi triển khai Java phải sử dụng cùng một hàm. –

+2

Bên cạnh thực tế là một số mã băm được cố định và được ghi lại đầy đủ, kẻ tấn công luôn có thể tìm ra phiên bản cụ thể mà máy chủ đang chạy và xem mã băm của một lớp thực hiện cụ thể được tính toán như thế nào. Đó là cách hầu hết các cuộc tấn công hoạt động, trước tiên, hãy tìm hiểu xem phần mềm nào chạy, sau đó, hãy thử một khai thác thích hợp phù hợp với phần mềm và phiên bản cụ thể. – Holger

8

Câu hỏi của bạn có chứa một số cơ sở sai.

  1. A va chạm xô không nhất thiết là một va chạm băm. Bạn không cần phải có cùng một mã băm cho hai đối tượng để kết thúc tại cùng một nhóm. Thùng là một phần tử của một mảng và mã băm phải được ánh xạ tới một chỉ mục cụ thể. Vì kích thước mảng phải hợp lý đối với kích thước của Map, bạn không thể tăng kích thước mảng tùy ý để tránh va chạm với xô. Thậm chí còn có giới hạn lý thuyết rằng kích thước mảng có thể ở mức tối đa 2³¹ trong khi có 2³² mã băm có thể.
  2. Việc có va chạm băm không phải là dấu hiệu của chương trình xấu. Đối với tất cả các đối tượng có không gian giá trị lớn hơn 2³², khả năng có các đối tượng riêng biệt có cùng mã băm là không thể tránh khỏi. String s là một ví dụ rõ ràng, nhưng ngay cả một số Point mang hai giá trị int hoặc một khóa đơn giản Long có va chạm băm không thể tránh khỏi. Vì vậy, chúng có thể phổ biến hơn bạn nghĩ và nó phụ thuộc rất nhiều vào trường hợp sử dụng.
  3. Việc triển khai chỉ chuyển sang cây nhị phân khi số lần va chạm trong một nhóm vượt quá ngưỡng nhất định để chi phí bộ nhớ cao hơn chỉ áp dụng khi chúng sẽ trả hết. dường như có một sự hiểu lầm phổ biến liên quan đến cách họ làm việc. Kể từ khi va chạm xô không nhất thiết phải va chạm băm, tìm kiếm nhị phân đầu tiên sẽ tìm kiếm các mã băm. Chỉ khi các mã băm giống hệt nhau và khóa phù hợp thực hiện Comparable, thứ tự tự nhiên của nó sẽ được sử dụng. Các ví dụ bạn có thể đã tìm thấy trên web cố tình sử dụng cùng một mã băm cho các đối tượng để chứng minh việc sử dụng thực hiện Comparable nếu không sẽ không hiển thị. Những gì họ kích hoạt chỉ là phương sách cuối cùng của việc thực hiện.
  4. Tagir pointed out, sự cố này có thể ảnh hưởng đến bảo mật của phần mềm dưới dạng dự phòng chậm có thể mở khả năng tấn công DoS. Đã có nhiều nỗ lực trong các phiên bản JRE trước đó để giải quyết vấn đề này có nhiều hạn chế hơn mức tiêu thụ bộ nhớ của cây nhị phân. Ví dụ, đã có một nỗ lực để phân ngẫu nhiên ánh xạ mã băm thành các mảng trong Java 7 gây ra phí khởi tạo như được ghi trong this bug report. Đây không phải là trường hợp với việc triển khai mới này.
+0

Related: [http://www.javaspecialists.eu /archive/Issue235.html](http://www.javaspecialists.eu/archive/Issue235.html) –

+0

Chỉ ra rằng "va chạm xô" không nhất thiết phải giống như "va chạm băm" là quan trọng ở đây. Nhiều người lập trình lầm tưởng rằng họ đồng nghĩa với nhau. – nanosoft

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