Java’da Set Interface’i ve Implemantasyonları

Duygu Orhan
folksdev
Published in
4 min readJan 1, 2024

--

Set Interface’i ve Implemantasyonları

Set interface’i matematikte kullandığımız kümelemenin soyutlanmış halidir. Kümelemede bir elemandan sadece bir tane vardır yani yinelenen eleman yoktur. Collection interface’inden miras alınmıştır ve yinelenen öğeleri kısıtlayan özellikler eklenmiştir. Hedef nesneye gitmek için küme içerisinde ilerlenir. İlerlemek için Iterator veya for-each döngüsü gibi yapılar kullanılır. Böylelikle küme içerisinde elemanlar tek tek gezilebilir ve üzerinde işlemler yapılabilir.

Set interface’in 3 alt sınıfı vardır: HashSet, LinkedHashSet ve TreeSet.

Setler senkronize edilemez yani aynı anda birden fazla iş parçacığı Setlere doğru bir şekilde erişemez. Senkronizasyon manuel olarak yapılır. Aşağıdaki şekilde kullanarak Seti senkronize eder ve küme içindeki işlemler doğru iş parçacığı olarak gerçekleşir, veri bütünlüğü korunur.

TreeSet treeSet = new TreeSet();   
Set syncrSet = Collections.synchronziedSet(treeSet);

HashSet

HashSet, benzersiz (unique) nesneleri herhangi bir sıra olmadan tutar. Nesneleri hashing algoritması ile saklar. Bu algoritma nesnelerin benzersiz bir hash kodunun olmasını sağlar ve buna göre sıralanır. Bu hash koda erişilemez. HashSet ile oluşturulan nesnelerin index erişimine doğrudan izin yoktur, sadece yapı içerisindeki ilk ve son elemana doğrudan erişim sağlanabilir. HashSet’te “null” öğelere izin verilir.

import java.util.*;
class Set{
public static void main(String[] args) {
HashSet<Integer> numbers1 = new HashSet<>();
numbers1.add(2);
numbers1.add(3);
numbers1.add(5);
System.out.println("HashSet1: " + numbers1);

HashSet<Integer> numbers2 = new HashSet<>();

numbers2.add(3);
numbers2.add(5);
System.out.println("HashSet2: " + numbers2);

//HashSet1 ve HashSet2 arasındaki fark
numbers1.removeAll(numbers2);
System.out.println("Difference : " + numbers1);

//HashSet boş mu kontrol edilir
System.out.println(numbers2.isEmpty());

//HashSet değerlerine iterator ile ulaşma
Iterator<Integer> it = numbers2.iterator();
while (it.hasNext()) {
System.out.print(it.next() + " ");
}

//HashSet'in boyutunu döndürür
System.out.println( "\n" + numbers2.size());

}
}
Çıktı

HashSet’te temel işlemlerde(ekleme, çıkarma, boyutlandırma, silme) zaman karmaşıklığı O(1)’dir.

LinkedHashSet

LinkedHashSet, öğeler arasında çift bağlantılı bir liste tutan, HashSet’in genişletilmiş sıralı halidir. Eklenme sırasına göre öğeler tutulur. HashSet’deki gibi benzersiz elemanları tutar., “null” öğelere izin verilir.

import java.util.*;
class Set{
public static void main(String[] args)
{

LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();

linkedHashSet.add("A");
linkedHashSet.add("B");
linkedHashSet.add("C");
linkedHashSet.add("D");

//yinelenen eleman yoktur
linkedHashSet.add("A");
linkedHashSet.add("E");

// Set'in boyutunu hesaplar
System.out.println("Size of LinkedHashSet = "
+ linkedHashSet.size());

//oluşturulan Set yazdırılır
System.out.println("Original LinkedHashSet:"
+ linkedHashSet);

//Set üzerinden olan bir nesneyi silme
System.out.println("Removing D from LinkedHashSet: "
+ linkedHashSet.remove("D"));

//Set üzerinden olmayan bir nesneyi silme
System.out.println(
"Trying to Remove Z which is not present: "
+ linkedHashSet.remove("Z"));

//Set içerisinde nesne kontrolü
System.out.println("Checking if A is present="
+ linkedHashSet.contains("A"));

//Güncel Set'in hali
//iterator ile for döngüsü
System.out.print("Updated LinkedHashSet: ");
for (String s : linkedHashSet)
System.out.print(s + ", ");

}
}

Temel işlemler için zaman karmaşıklığı HashSet ile aynıdır, O(1)’dir.

TreeSet

TreeSet sınıfı SortedSet Interface’ni miras almıştır. Sorted interface’i de kümelemeye ek olarak elemanların sıralı bir şekilde tutulmasına olanak sağlar. NavigableSet Interface’i de SortedSet Interface’inden türetilmiştir. NavigableSet Interface’i ile küme içerisinde gezinme ve özel sorgu işlemleri gerçekleştirilir, en yakın değeri bulma, verilen değere kadarki değerleri bulma gibi. Navigable Interface’i ile kullanılmakta olan metotlar :

  • lower(e): Verilen e değerinden küçük olan en büyük değeri döndürür.
  • floor(e): Verilen edeğerinden küçük veya ona eşit olan en büyük elemanı döndürür.
  • ceiling(e): Verilen e değerinden büyük veya ona eşit olan en küçük elemanı döndürür.
  • higher(e) : Verilen edeğerinden sadece büyük olan en küçük elemanı döndürür.
  • descendingSet(): Küçükten büyüğe sıralanmış kümenin ters bir görünümünü döndürür.
  • descendingIterator(): Set içindeki elemanları azalan sırada dolaşmaya izin veren bir iterator döndürür.
  • pollFirst(): İlk elemanı alır ve siler; set boşsa null döner.
  • poolLast(): Son elemanı alır ve siler; set boşsa null döner.

Aşağıdaki kod bloğunda Navigable türünde iki adet Set oluşturuldu. TreeSet üzerinden bir nesne alınarak bir sayı listesi atandı ve descendingSet() metodu kullanarak oluşturulan Set’in tersi diğer Set değişkenine atıldı.
TreeSet içerisinde tersten erişmek istediğimizde diğer uygulayabileceğimiz bir yöntem ise descIterator metodu kullanılarak Set içerisinde elemanlara tersten tek tek erişilebilir.

import java.util.*;
class Set{
public static void main(String[] args){
NavigableSet<Integer> setNumbers1 = new TreeSet<>();
setNumbers1.addAll(Arrays.asList(4, 8, 3, 9, 1, 6, 4, 5, 3, 2, 7, 8, 0));

NavigableSet<Integer> setNumbers2 = setNumbers1.descendingSet();

System.out.println("Set Numbers 1: " + setNumbers1);
System.out.println("Set Numbers 2: " + setNumbers2);


Iterator<Integer> descIterator = setNumbers1.descendingIterator();

System.out.print("Number by descending : ");

while (descIterator.hasNext()) {
System.out.print(descIterator.next() + ", ");

}
}
}
Çıktı

TreeSet’de oluşan nesneler sıralanmış ve artan şekilde saklanır, nesnelerin eklenme sırası korunmaz ama TreeSet yapısında bulunan doğal sıralama ile sıralanır. Doğal sıralama, nesnelerin türüne ve karşılaştırılabilir (comparable) olup olmadığına bağlıdır. Eğer nesne Comparable interface’ini uyguluyorsa veya karşılaştırıcı(comparator) belirtilmişse, nesneler bu sıralamaya göre sıralanır.

Aşağıdaki kodda bir Employee sınıfı oluşturulmuştur. Empoyee sınıfında Comparable interface’ini kullanarak bir sıralama yapıldı. Bu interface’den gelen compareTo() metotou ezilerek (override) elemanların isme göre sıralanacağı belirtildi. Object interface’inden toString() metodu ezilerek de Employee’nin çıktısının formatının nasıl olacağı belirtilmiştir.

import java.util.*;

class Employee implements Comparable<Employee>{
String name;
Integer id;
public Employee(String name, Integer id) {
this.name = name;
this.id = id;
}

@Override
public int compareTo(Employee e) {
return this.name.compareTo(e.name);
}

@Override
public String toString() {
return "Employee{" + "name=" + name + ", id=" + id + '}';
}
}

class TreeSetWithComparable{
public static void main(String[] args) {
Employee e1= new Employee("Zeynep",2);
Employee e2= new Employee("Samet",1);
Employee e3= new Employee("Ahmet",5);
Employee e4= new Employee("Buse",8);

Set<Employee> treeSet = new TreeSet<Employee>();
treeSet.add(e1);
treeSet.add(e2);
treeSet.add(e3);
treeSet.add(e4);

for(Employee e: treeSet){
System.out.println(e);

}
}

}

Employee sınıfın elemanları aşağıdaki şekilde sıralanmış, for-each döngüsü ile yazdırılmıştır.

Çıktı

TreeSet “Null” değerler içermez.
TreeSet ikili arama ağacı kullanılarak uygulanır. Böylelikle ekleme, silme, arama gibi işlemler O(log(n)) zamanında gerçekleşir.

Umarım faydalı olmuştur, bir sonraki yazıda görüşmek üzere ❤

--

--