Middle
Java'da HashMap ma'lumotlar tuzilmasi qanday tuzilgan va tashkil etilgan?
sobes.tech AI
AIdan javob
Java'da HashMap hashing prinsiplari asosida ishlaydi. U "kalit-qiymat" juftliklarini saqlaydi.
Ichki tuzilishi:
- Bucket (qoplar) massivlari. Har bir bucket bog'langan ro'yxat (yoki Java 8 dan boshlab, ko'p koliziyalar bo'lsa, daraxt).
- Element qo'shishda (
put):- Kalitning hash kodi hisoblanadi (
key.hashCode()). - Hash kodi yaxshiroq taqsimot uchun o'zgartiriladi (
hash). - O'zgartirilgan hash va bucket massivining o'lchami yordamida, element joylashadigan bucket indeksi hisoblanadi (
hash & (array_size - 1)). - Element ("kalit-qiymat" juftligi
Nodeobyekti sifatida) shu bucketga joylashtiriladi. Agar bucketda allaqachon elementlar bo'lsa, yangi element bog'langan ro'yxat yoki daraxtning boshiga qo'shiladi. - Qo'shishda, kalit oldindan mavjudligini tekshirish uchun
equals()metodi ishlatiladi. Agar kalit topilsa, qiymat yangilanadi.
- Kalitning hash kodi hisoblanadi (
- Elementni olishda (
get):- Shuningdek, kalitga asoslangan bucket indeksi hisoblanadi.
- Bucket ichida, kalit yordamida element qidiriladi,
hashCode()vaequals()metodlari yordamida. - Bog'langan qiymat qaytariladi.
Tashkiliy tuzilma:
- Kollisionlar: Agar bir nechta kalitlar bir xil hash kodiga ega bo'lsa va bir bucketga tushsa, elementlar bog'langan ro'yxat sifatida saqlanadi. Java 8 dan boshlab, bucketdagi elementlar soni belgilangan chegaradan oshsa (odatda 8), ro'yxat daraxtga aylantiriladi, bu esa qidiruvni tezlashtiradi (O(log n) o'rniga O(n)).
- Yangi o'lchamga o'tish: Elementlar soni "yuklama koeffitsienti" (
load factor * capacity) dan oshsa, HashMap ichki bucket massivining o'lchamini (odatda ikki barobar) oshiradi va barcha elementlarni qayta hashlaydi. Bu juda qimmatli operatsiya (O(n)). - Parametrlar:
capacity: boshlang'ich massiv o'lchami (standart 16).load factor: yuklama chegarasi (standart 0.75). Qachon o'lcham o'zgartirilishini belgilaydi.
Nima uchun hashCode() va equals() muhim:
- HashMap to'g'ri ishlashi uchun bu metodlarning to'g'ri implementatsiyasi muhim.
- Agar
equals()trueqaytaradigan ikki ob'ekt uchun,hashCode()ham bir xil qiymat qaytarishi kerak. - Noto'g'ri implementatsiya, elementlar topilmasligiga olib kelishi mumkin (
getnullqaytaradi), hatto ular qo'shilgan bo'lsa ham.
Node strukturasining misoli:
// Faqat ichki
static class Node<K,V> implements Map.Entry<K,V> {
final int hash;
final K key;
V value;
Node<K,V> next;
Node(int hash, K key, V value, Node<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
public final K getKey() { return key; }
public final V getValue() { return value; }
public final String toString() { return key + "=" + value; }
public final int hashCode() {
return Objects.hashCode(key) ^ Objects.hashCode(value);
}
public final V setValue(V newValue) {
V oldValue = value;
value = newValue;
return oldValue;
}
public final boolean equals(Object o) {
if (o == this)
return true;
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>)o;
if (Objects.equals(key, e.getKey()) &&
Objects.equals(value, e.getValue()))
return true;
}
return false;
}
}
HashMap, hashlarning taqsimoti teng bo'lsa, elementlarni qo'shish, olish va o'chirish operatsiyalari o'rtacha O(1) vaqt oladi. Kuchli koliziyalar bo'lsa, bu operatsiyalar O(n) yoki daraxtlar bilan O(log n) bo'lishi mumkin.
Ushbu class thread-safety emas. Ko'p ipli muhitlarda foydalanish uchun ConcurrentHashMap yoki Collections.synchronizedMap(new HashMap<...>(...)) tavsiya etiladi.