SortedSet, SortedMap, NavigableSet
Bazen sadece sıralı tutmak yetmez — sıralı verinin alt kümelerine erişmek istersin. "50-100 arasındaki puanlar neler?" veya "Ali'den önceki isimler kim?" gibi sorulara cevap vermek istersin. İşte SortedSet, SortedMap ve NavigableSet/NavigableMap bu ihtiyaç için var.
Bunu bir ansiklopedi gibi düşün. Harflere göre sıralı, herhangi bir harften diğerine kadar olan kısmı kolayca kesip alabilirsin. "D'den K'ya kadar olan maddeler" — bu bir range query ve sorted koleksiyonlar tam bunu yapıyor.
SortedSet Interface
SortedSet, elemanları sıralı tutan bir Set. TreeSet en yaygın implementasyonu.
SortedSet<Integer> scores = new TreeSet<>();
scores.add(85);
scores.add(92);
scores.add(67);
scores.add(78);
scores.add(95);
scores.add(45);
// Otomatik sıralı: [45, 67, 78, 85, 92, 95]
// İlk ve son eleman
System.out.println(scores.first()); // 45
System.out.println(scores.last()); // 95
// Alt küme operasyonları
SortedSet<Integer> head = scores.headSet(80); // 80'den küçükler: [45, 67, 78]
SortedSet<Integer> tail = scores.tailSet(80); // 80 ve üstü: [85, 92, 95]
SortedSet<Integer> sub = scores.subSet(60, 90); // 60 (dahil) - 90 (hariç): [67, 78, 85]Önemli: headSet, tailSet, subSet view döndürür — kopya değil. Orijinal değişirse view da değişir.
SortedSet<Integer> tailView = scores.tailSet(80);
System.out.println(tailView); // [85, 92, 95]
scores.add(88);
System.out.println(tailView); // [85, 88, 92, 95] — otomatik güncellendi!
tailView.add(99);
System.out.println(scores.contains(99)); // true — orijinale de eklendi!⚠️ View sınırları: View'a, range dışı eleman eklemeye çalışırsan
IllegalArgumentExceptionalırsın.
SortedSet<Integer> sub = scores.subSet(60, 90);
sub.add(75); // OK — 60-90 arasında
// sub.add(50); // IllegalArgumentException! Range dışı
// sub.add(95); // IllegalArgumentException! Range dışıSortedMap Interface
SortedMap, key'leri sıralı tutan bir Map. TreeMap en yaygın implementasyonu.
SortedMap<String, Integer> ages = new TreeMap<>();
ages.put("Zeynep", 28);
ages.put("Ali", 25);
ages.put("Mehmet", 30);
ages.put("Can", 22);
ages.put("Deniz", 27);
// Key'lere göre sıralı: {Ali=25, Can=22, Deniz=27, Mehmet=30, Zeynep=28}
// İlk ve son
System.out.println(ages.firstKey()); // "Ali"
System.out.println(ages.lastKey()); // "Zeynep"
// Alt küme
SortedMap<String, Integer> head = ages.headMap("Deniz"); // Deniz'den öncekiler
// {Ali=25, Can=22}
SortedMap<String, Integer> tail = ages.tailMap("Deniz"); // Deniz ve sonrası
// {Deniz=27, Mehmet=30, Zeynep=28}
SortedMap<String, Integer> sub = ages.subMap("Can", "Mehmet"); // Can (dahil) - Mehmet (hariç)
// {Can=22, Deniz=27}NavigableSet Interface (Java 6+)
NavigableSet, SortedSet'i genişletir. Daha güçlü navigasyon method'ları ekler: "en yakın eleman" bulma, ters sırada gezinme, dahil/hariç kontrollü range.
NavigableSet<Integer> nums = new TreeSet<>(Set.of(10, 20, 30, 40, 50, 60));
// floor — verilen değere eşit veya küçük en büyük eleman
System.out.println(nums.floor(35)); // 30
System.out.println(nums.floor(30)); // 30 (eşit dahil)
System.out.println(nums.floor(5)); // null (yok)
// ceiling — verilen değere eşit veya büyük en küçük eleman
System.out.println(nums.ceiling(35)); // 40
System.out.println(nums.ceiling(30)); // 30 (eşit dahil)
// lower — verilen değerden kesinlikle küçük en büyük eleman
System.out.println(nums.lower(30)); // 20 (30 hariç)
// higher — verilen değerden kesinlikle büyük en küçük eleman
System.out.println(nums.higher(30)); // 40 (30 hariç)Bu dört method'un farkı:
| Method | Dahil mi? | Yön |
|---|---|---|
floor(e) | ✅ (≤) | Aşağı |
lower(e) | ❌ (<) | Aşağı |
ceiling(e) | ✅ (≥) | Yukarı |
higher(e) | ❌ (>) | Yukarı |
// pollFirst / pollLast — çıkararak al
NavigableSet<Integer> set = new TreeSet<>(Set.of(1, 2, 3, 4, 5));
System.out.println(set.pollFirst()); // 1 — en küçüğü çıkar
System.out.println(set.pollLast()); // 5 — en büyüğü çıkar
System.out.println(set); // [2, 3, 4]
// descendingSet — ters sırada view
NavigableSet<Integer> desc = set.descendingSet();
System.out.println(desc); // [4, 3, 2]
// descendingIterator — ters sırada iterasyon
Iterator<Integer> descIt = set.descendingIterator();
while (descIt.hasNext()) {
System.out.println(descIt.next()); // 4, 3, 2
}NavigableSet: Dahil/Hariç Range
SortedSet'in subSet, headSet, tailSet method'larında sınırlar fixed'dı (fromInclusive, toExclusive). NavigableSet'te sen seçersin:
NavigableSet<Integer> nums = new TreeSet<>(Set.of(10, 20, 30, 40, 50));
// subSet(from, fromInclusive, to, toInclusive)
nums.subSet(20, true, 40, true); // [20, 30, 40] — ikisi de dahil
nums.subSet(20, false, 40, false); // [30] — ikisi de hariç
nums.subSet(20, true, 40, false); // [20, 30] — from dahil, to hariç
// headSet(to, inclusive)
nums.headSet(30, true); // [10, 20, 30] — 30 dahil
nums.headSet(30, false); // [10, 20] — 30 hariç
// tailSet(from, inclusive)
nums.tailSet(30, true); // [30, 40, 50] — 30 dahil
nums.tailSet(30, false); // [40, 50] — 30 hariçNavigableMap Interface
NavigableMap, NavigableSet'in Map karşılığı. TreeMap implement eder.
NavigableMap<Integer, String> scores = new TreeMap<>();
scores.put(50, "Başarısız");
scores.put(60, "Geçer");
scores.put(70, "Orta");
scores.put(80, "İyi");
scores.put(90, "Pekiyi");
// floor/ceiling/lower/higher — key bazlı
Map.Entry<Integer, String> entry;
entry = scores.floorEntry(75); // 70=Orta (≤ 75)
entry = scores.ceilingEntry(75); // 80=İyi (≥ 75)
entry = scores.lowerEntry(70); // 60=Geçer (< 70)
entry = scores.higherEntry(70); // 80=İyi (> 70)
// Sadece key
Integer key = scores.floorKey(75); // 70
Integer key2 = scores.ceilingKey(75); // 80
// İlk ve son
entry = scores.firstEntry(); // 50=Başarısız
entry = scores.lastEntry(); // 90=Pekiyi
// Çıkararak al
entry = scores.pollFirstEntry(); // 50=Başarısız — map'ten silindi
entry = scores.pollLastEntry(); // 90=Pekiyi — map'ten silindiTreeMap Range Operations
NavigableMap<String, Double> prices = new TreeMap<>();
prices.put("Elma", 5.0);
prices.put("Armut", 7.5);
prices.put("Muz", 12.0);
prices.put("Portakal", 8.0);
prices.put("Üzüm", 15.0);
// Alt harita — "E" ile "P" arasındaki ürünler
NavigableMap<String, Double> sub = prices.subMap("E", true, "P", false);
System.out.println(sub); // {Elma=5.0, Muz=12.0} — alfabetik E-P arası
// Ters sırada
NavigableMap<String, Double> desc = prices.descendingMap();
System.out.println(desc); // {Üzüm=15.0, Portakal=8.0, Muz=12.0, ...}Gerçek Dünya: Not Sistemi
public class GradeSystem {
private final NavigableMap<Integer, String> gradeMap = new TreeMap<>();
public GradeSystem() {
gradeMap.put(0, "F");
gradeMap.put(50, "D");
gradeMap.put(60, "C");
gradeMap.put(70, "B");
gradeMap.put(80, "A");
gradeMap.put(90, "A+");
}
public String getGrade(int score) {
Map.Entry<Integer, String> entry = gradeMap.floorEntry(score);
return entry != null ? entry.getValue() : "F";
}
public static void main(String[] args) {
GradeSystem gs = new GradeSystem();
System.out.println(gs.getGrade(85)); // A
System.out.println(gs.getGrade(72)); // B
System.out.println(gs.getGrade(55)); // D
System.out.println(gs.getGrade(45)); // F
}
}💡 İpucu:
floorEntry()range-based lookup için mükemmel. Tam eşleşme aramak yerine "en yakın alt sınır" bulur. Not sistemi, vergi dilimleri, kargo fiyatlandırması gibi aralık bazlı mantıklar için ideal.
Gerçek Dünya: Zaman Aralığı Sorguları
public class EventLog {
private final NavigableMap<LocalDateTime, String> events = new TreeMap<>();
public void log(String event) {
events.put(LocalDateTime.now(), event);
}
// Son 1 saatteki event'ler
public NavigableMap<LocalDateTime, String> getLastHour() {
LocalDateTime oneHourAgo = LocalDateTime.now().minusHours(1);
return events.tailMap(oneHourAgo, true);
}
// İki tarih arasındaki event'ler
public NavigableMap<LocalDateTime, String> getBetween(
LocalDateTime from, LocalDateTime to) {
return events.subMap(from, true, to, true);
}
}Özet
SortedSet/SortedMap elemanları sıralı tutar —
first(),last(),headSet(),tailSet(),subSet()ile range erişimNavigableSet/NavigableMap daha güçlü:
floor(),ceiling(),lower(),higher()ile "en yakın eleman" bulmaheadSet/tailSet/subSetview döndürür (kopya değil) — orijinal değişirse view da değişir, view'a range dışı eleman eklenemezNavigableSet'te
subSet(from, fromInclusive, to, toInclusive)ile dahil/hariç kontrolü senin elindefloorEntry()/ceilingEntry()range-based lookup için mükemmel — not sistemi, vergi dilimi, fiyat aralığı senaryolarıTüm sorted/navigable yapılar arka planda TreeSet/TreeMap (Red-Black Tree) kullanır — operasyonlar O(log n)
AI Asistan
Sorularını yanıtlamaya hazır