1. LinkedHashSet və LinkedHashMap nədir?
Java-nın standart kitabxanasında Set və Map kolleksiyalarının bir neçə reallaşdırması var. Ən məşhurları — HashSet və HashMap-dır. Bu strukturlar elementlərə hash üzrə sürətli giriş təmin edir, amma elementlər üzərində iterasiya zamanı heç bir sıra zəmanəti vermir. Sıra vacib olanda — köməyə LinkedHashSet və LinkedHashMap gəlir.
- LinkedHashSet — elementlərin əlavə olunma sırasını saxlayan bir Set-dir.
- LinkedHashMap — açar–dəyər cütlərinin əlavə olunma sırasını (və ya istəyə görə, müraciət sırasını) saxlayan bir Map-dir.
Onlar “adi” HashSet/HashMap kimidir, lakin elementlərin sırasını saxlamaq üçün iki tərəfli bağlı siyahı ilə tamamlanıb.
2. Əlavə etmə sırası və müraciət sırası
Əlavə etmə sırası
Susmaya görə LinkedHashSet və LinkedHashMap iterasiya zamanı elementlərin əlavə olunduqları sırada (for-each/iterator) qaytarılmasını təmin edir.
Set<String> set = new LinkedHashSet<>();
set.add("A");
set.add("B");
set.add("C");
for (String s : set) {
System.out.println(s);
}
// Çıxış: A B C
Map<Integer, String> map = new LinkedHashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
for (Integer key : map.keySet()) {
System.out.println(key + " -> " + map.get(key));
}
// Çıxış: 1 -> one, 2 -> two, 3 -> three
Müraciət sırası (yalnız LinkedHashMap üçün)
LinkedHashMap-da son müraciətə görə sıra (access order) rejimi var. Xəritə yaradılarkən konstruktora üçüncü parametr kimi true verilsə, elementə hər dəfə müraciətdə (get/put) o, siyahının sonuna keçirilir.
Map<Integer, String> lruMap = new LinkedHashMap<>(16, 0.75f, true);
lruMap.put(1, "one");
lruMap.put(2, "two");
lruMap.put(3, "three");
lruMap.get(2); // Açar 2-yə müraciət
for (Integer key : lruMap.keySet()) {
System.out.println(key);
}
// Çıxış: 1 3 2 (2 — sonuncudur, çünki ona müraciət olundu)
removeEldestEntry vasitəsilə LRU-keş
LinkedHashMap-ın əsas “fəndi” — LRU-keşin (Least Recently Used, “ən çoxdan istifadə olunmayan”) sadə reallaşdırılmasıdır. removeEldestEntry(Map.Entry<K,V> eldest) metodunu yenidən təyin etmək kifayətdir: əgər o, true qaytarırsa, yeni element əlavə ediləndə ən “köhnə” element silinir.
class LRUCache<K, V> extends LinkedHashMap<K, V> {
private final int maxSize;
public LRUCache(int maxSize) {
super(maxSize, 0.75f, true); // true — müraciətə görə sıra
this.maxSize = maxSize;
}
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
return size() > maxSize;
}
}
// İstifadə:
LRUCache<Integer, String> cache = new LRUCache<>(3);
cache.put(1, "one");
cache.put(2, "two");
cache.put(3, "three");
cache.get(1); // 1-i ən "təzə" edirik
cache.put(4, "four"); // 2 silinəcək (ən köhnə)
System.out.println(cache.keySet()); // [3, 1, 4]
3. Yaddaş və sürət xərci: LinkedHashSet/LinkedHashMap vs HashSet/HashMap
Bu necə qurulub
Daxildə — demək olar ki, adi HashSet/HashMap kimidir, amma hər element həm də iki tərəfli bağlı siyahıda saxlanılır. Bu əlavə struktur əlavə/müraciət sırasını “yadda saxlayır”.
Yaddaş xərci
Hər düyündəki prev/next istinadlarına görə daha çox yaddaş tələb olunur. Milyonlarla element üçün bu nəzərə çarpır; tipik tapşırıqlar üçün isə deterministik sıra üçün məqbul ödənişdir.
Sürət xərci
Əsas əlavə/axtarış/silmə əməliyyatları amortizə olunmuş O(1) qalır. Siyahının keçilməsinə görə iterasiya bir qədər yavaşdır, lakin çox hallarda fərq minimumdur. “Ən köhnəni sil” (LRU) ssenarisi isə çox səmərəlidir, çünki “ən köhnə” element həmişə siyahının başındadır.
Nəticə olaraq: sıra vacibdirsə — LinkedHashSet/LinkedHashMap seçin. Yaddaşa qənaət lazımdırsa və sıra önəmli deyilsə — HashSet/HashMap kifayətdir.
4. Keşləmə, deterministik çıxış, stabil testlər
Keşləmə (LRU)
LinkedHashMap — ölçü məhdudiyyəti və “köhnə” elementlərin avtomatik silinməsi olan keşlər üçün ideal bazadır. Kitabxanalarda/freymvörklərdə, fayllar, şəkillər, hesablamaların nəticələri ilə işləyərkən tətbiq olunur.
Deterministik çıxış
Hesabatlar, ixrac, seriyalaşdırma kimi məlumatların təqdimatının qabaqcadan proqnozlaşdırılması kritik olduqda, LinkedHashSet/LinkedHashMap istifadə edin. Bu, testlər üçün xüsusilə vacibdir — sıra hər işə salmada dəyişmir.
Stabil testlər
Unit testlərdə çox vaxt gözlənilən kolleksiyalar alınanlarla müqayisə olunur. Əgər sıra zəmanəti yoxdursa, testlər qeyri-sabit ola bilər. “Linked” reallaşdırmalar deterministikliyi təmin edir.
Nümunə: HashMap və LinkedHashMap müqayisəsi
Map<Integer, String> hashMap = new HashMap<>();
Map<Integer, String> linkedMap = new LinkedHashMap<>();
for (int i = 1; i <= 5; i++) {
hashMap.put(i, "val" + i);
linkedMap.put(i, "val" + i);
}
System.out.println(hashMap.keySet()); // Sıra istənilən ola bilər!
System.out.println(linkedMap.keySet()); // Həmişə 1, 2, 3, 4, 5
Növbələr üçün LinkedList vs ArrayDeque
LinkedList
- List, Deque, Queue interfeyslərini reallaşdırır.
- İki tərəfli bağlı siyahı: başlanğıcda və sonda sürətli əlavə/silmə.
- Növbə (FIFO), yığın (LIFO), iki tərəfli növbə kimi istifadə oluna bilər.
ArrayDeque
- Deque, Queue reallaşdırır (amma List deyil).
- Massivə əsaslanır, avtomatik genişlənir.
- Növbə/yığın əməliyyatlarında çox vaxt LinkedList-dən daha sürətlidir; əlavə xərclər azdır.
- null elementini dəstəkləmir.
Nə zaman hansını istifadə etməli?
- Növbələr və yığınlar — demək olar həmişə ArrayDeque.
- Ortada çoxlu əlavə/silmə və həm də siyahı lazımdırsa — LinkedList.
- Sıra saxlayan Set/Map — LinkedHashSet/LinkedHashMap.
Nümunə: tapşırıq növbəsi
Queue<String> queue = new ArrayDeque<>();
queue.add("task1");
queue.add("task2");
System.out.println(queue.poll()); // task1
Nümunə: yığın
Deque<String> stack = new ArrayDeque<>();
stack.push("first");
stack.push("second");
System.out.println(stack.pop()); // second
Nəticə:
— Növbələr və yığınlar üçün — ArrayDeque.
— Ortaya tez-tez əlavə etmə tələb olunan siyahılar üçün — LinkedList.
— Set/Map üçün sıra lazımdırsa — LinkedHashSet/LinkedHashMap.
6. LinkedHashSet/LinkedHashMap ilə işləyərkən tipik səhvlər
Səhv №1: HashSet/HashMap-in sıranı saxladığını gözləmək.
HashSet/HashMap sıra zəmanəti vermir. Əgər sıra vacibdirsə — LinkedHashSet/LinkedHashMap istifadə edin.
Səhv №2: removeEldestEntry yenidən təyin edilmədən keş üçün LinkedHashMap istifadə etmək.
LRU üçün removeEldestEntry-ni yenidən təyin etmək lazımdır, əks halda xəritə məhdudiyyətsiz böyüyəcək.
Səhv №3: ehtiyac olmadan növbə/yığın üçün LinkedList istifadə etmək.
Əksər hallarda ArrayDeque daha sürətli və daha qənaətcildir.
Səhv №4: LinkedHashMap-dən sıralama gözləmək.
LinkedHashMap əlavə/müraciət sırasını saxlayır, lakin açara görə sıralamır. Sıralama üçün — TreeMap.
Səhv №5: ArrayDeque-ə null əlavə etmək.
ArrayDeque null elementlərini dəstəkləmir — NullPointerException olacaq.
Səhv №6: Sıra nəzərə alınmadan kolleksiyaları müqayisə etmək.
LinkedHashSet/LinkedHashMap-ı adi HashSet/HashMap ilə müqayisə edərkən elementlərin sırasındakı fərqləri nəzərə alın.
GO TO FULL VERSION