ฉันเห็นด้วยกับ:
- ความซับซ้อนของการตัดจำหน่ายทั่วไปของ O (1)
- การ
hashCode()
ใช้งานที่ไม่ดีอาจส่งผลให้เกิดการชนกันหลายครั้งซึ่งหมายความว่าในกรณีที่เลวร้ายที่สุดทุกออบเจ็กต์จะไปที่ที่เก็บข้อมูลเดียวกันดังนั้น O ( N ) หากแต่ละที่เก็บข้อมูลได้รับการสนับสนุนโดยกList
.
- ตั้งแต่ Java 8
HashMap
จะแทนที่โหนด (รายการที่เชื่อมโยง) แบบไดนามิกที่ใช้ในแต่ละที่เก็บข้อมูลด้วย TreeNodes (ต้นไม้สีแดงดำเมื่อรายการมีขนาดใหญ่กว่า 8 องค์ประกอบ) ส่งผลให้ O ( logN ) มีประสิทธิภาพแย่ที่สุด
แต่นี่ไม่ใช่ความจริงทั้งหมดหากเราต้องการให้แม่นยำ 100% การใช้งานhashCode()
และประเภทของคีย์Object
(ไม่เปลี่ยนรูป / แคชหรือเป็นคอลเล็กชัน) อาจส่งผลต่อความซับซ้อนจริงในเงื่อนไขที่เข้มงวด
สมมติสามกรณีต่อไปนี้:
HashMap<Integer, V>
HashMap<String, V>
HashMap<List<E>, V>
มีความซับซ้อนเหมือนกันหรือไม่? ความซับซ้อนตัดจำหน่ายของอันที่ 1 เป็นไปตามที่คาดไว้ O (1) แต่ที่เหลือเราต้องคำนวณhashCode()
องค์ประกอบการค้นหาด้วยซึ่งหมายความว่าเราอาจต้องสำรวจอาร์เรย์และรายการในอัลกอริทึมของเรา
ให้คิดว่าขนาดของทั้งหมดของอาร์เรย์ดังกล่าวข้างต้น / รายการคือk จากนั้นHashMap<String, V>
และHashMap<List<E>, V>
จะมี O (k) ตัดจำหน่ายความซับซ้อนและในทำนองเดียวกัน O ( k + logN ) กรณีที่เลวร้ายที่สุดใน Java8
* โปรดทราบว่าการใช้String
คีย์เป็นกรณีที่ซับซ้อนกว่าเนื่องจากไม่เปลี่ยนรูปและ Java จะแคชผลลัพธ์ของhashCode()
ตัวแปรส่วนตัวhash
ดังนั้นจึงคำนวณเพียงครั้งเดียว
/** Cache the hash code for the string */
private int hash; // Default to 0
แต่ข้างต้นก็มีกรณีที่เลวร้ายที่สุดเช่นกันเนื่องจากString.hashCode()
การใช้งานJava กำลังตรวจสอบว่าhash == 0
ก่อนที่จะคำนวณhashCode
หรือไม่ แต่เดี๋ยวก่อนมีสตริงที่ไม่ว่างเปล่าที่ส่งออกเป็นhashcode
ศูนย์เช่น "f5a5a608" ดูที่นี่ซึ่งในกรณีนี้การบันทึกช่วยจำอาจไม่เป็นประโยชน์