Tại sao Python sử dụng bảng băm để thực hiện dict, nhưng không phải Red-Black Tree?
Chìa khóa là gì? Hiệu suất?
Tại sao Python sử dụng bảng băm để thực hiện dict, nhưng không phải Red-Black Tree?
Chìa khóa là gì? Hiệu suất?
Câu trả lời:
Đây là một câu trả lời chung chung, không dành riêng cho Python.
| Hash Table | Red-Black Tree |
-------+-------------+---------------------+
Space | O(n) : O(n) | O(n) : O(n) |
Insert | O(1) : O(n) | O(log n) : O(log n) |
Fetch | O(1) : O(n) | O(log n) : O(log n) |
Delete | O(1) : O(n) | O(log n) : O(log n) |
| avg :worst | average : worst |
Vấn đề với bảng băm là băm có thể va chạm. Có nhiều cơ chế khác nhau để giải quyết các va chạm, ví dụ như mở địa chỉ hoặc tách chuỗi. Trường hợp xấu nhất tuyệt đối là tất cả các khóa đều có cùng mã băm, trong trường hợp đó, bảng băm sẽ biến thành một danh sách được liên kết.
Trong tất cả các trường hợp khác, bảng băm là một cấu trúc dữ liệu tuyệt vời, dễ thực hiện và mang lại hiệu suất tốt. Một nhược điểm là việc triển khai có thể nhanh chóng phát triển bảng và phân phối lại các mục nhập của chúng có thể sẽ lãng phí gần như nhiều bộ nhớ như đang thực sự được sử dụng.
Cây RB tự cân bằng và không thay đổi độ phức tạp thuật toán của chúng trong trường hợp xấu nhất. Tuy nhiên, chúng khó thực hiện hơn. Độ phức tạp trung bình của chúng cũng tệ hơn so với bảng băm.
Tất cả các khóa trong bảng băm phải có thể băm và có thể so sánh cho sự bình đẳng lẫn nhau. Điều này đặc biệt dễ dàng đối với các chuỗi hoặc số nguyên, nhưng cũng khá đơn giản để mở rộng sang các loại do người dùng xác định. Trong một số ngôn ngữ như Java, các thuộc tính này được đảm bảo theo định nghĩa.
Các khóa trong Cây RB phải có tổng thứ tự: mỗi khóa phải tương đương với bất kỳ khóa nào khác và hai khóa phải so sánh nhỏ hơn, lớn hơn hoặc bằng nhau. Bình đẳng thứ tự này phải tương đương với bình đẳng ngữ nghĩa. Điều này rất đơn giản đối với các số nguyên và các số khác, cũng khá dễ dàng đối với các chuỗi (thứ tự chỉ cần nhất quán và không thể quan sát được bên ngoài, vì vậy thứ tự không cần phải xem xét các vị trí [1] ), nhưng khó khăn cho các loại khác không có thứ tự vốn có . Hoàn toàn không thể có các loại khóa khác nhau trừ khi có thể so sánh giữa chúng.
[1]: Thật ra, tôi sai ở đây. Hai chuỗi có thể không bằng byte nhưng vẫn tương đương theo quy tắc của một số ngôn ngữ. Xem ví dụ: chuẩn hóa Unicode cho một ví dụ trong đó hai chuỗi bằng nhau được mã hóa khác nhau. Việc thành phần ký tự Unicode có quan trọng đối với khóa băm của bạn hay không là điều mà việc triển khai bảng băm không thể biết được.
Mọi người có thể nghĩ rằng một giải pháp rẻ tiền cho các khóa RB-Tree sẽ là thử nghiệm đầu tiên cho sự bằng nhau, sau đó so sánh danh tính (ví dụ so sánh các con trỏ). Tuy nhiên, thứ tự này sẽ không mang tính bắc cầu: Nếu a == b
và id(a) > id(c)
, thì nó cũng phải tuân theo điều đó id(b) > id(c)
, điều này không được đảm bảo ở đây. Vì vậy, thay vào đó, chúng tôi có thể sử dụng mã băm của các khóa làm khóa tra cứu. Ở đây, thứ tự hoạt động chính xác, nhưng chúng ta có thể kết thúc với nhiều khóa riêng biệt có cùng mã băm, sẽ được gán cho cùng một nút trong cây RB. Để giải quyết các xung đột băm này, chúng ta có thể sử dụng các chuỗi riêng biệt giống như với các bảng băm, nhưng điều này cũng thừa hưởng hành vi xấu nhất đối với các bảng băm - điều tồi tệ nhất của cả hai thế giới.
Tôi hy vọng một bảng băm có địa phương bộ nhớ tốt hơn một cây, bởi vì bảng băm về cơ bản chỉ là một mảng.
Các mục trong cả hai cấu trúc dữ liệu có chi phí khá cao:
Chèn và xóa trong cây RB liên quan đến xoay cây. Chúng không thực sự tốn kém, nhưng có liên quan đến chi phí chung. Trong một hàm băm, việc chèn và xóa không tốn kém hơn một truy cập đơn giản (mặc dù thay đổi kích thước bảng băm khi chèn là một O(n)
nỗ lực).
Các bảng băm vốn dĩ có thể thay đổi, trong khi đó cây RB cũng có thể được thực hiện theo cách bất biến. Tuy nhiên, điều này hiếm khi hữu ích.
Có rất nhiều lý do có thể đúng, nhưng những lý do chính có thể là:
Dễ dàng hơn để viết / duy trì và một người chiến thắng hiệu suất trong các trường hợp sử dụng điển hình? Hãy đăng ký cho tôi!