Java Düğüm mantığı ve kullanımı

Merhaba arkadaşlar.

Java dilinde basitçe düğüm mantığını anlatmak istedim sizlere. Birçok dilde de benzer yapıda kullanabilirsiniz.

Düğümler, birbirine bağlı objeler, sınıflar olarak düşünebiliriz. Veri aramak, gezinti yapmak için kullanılan faydalı yapılardır.
Birçok durum için kullanılabilir. Gruplama, çok verili listeleme gibi ve çok gruplu verileri, başka çok gruplu veriler ile karşılaştırma gibi.

Basitçe syntax'ını yazalım;

Java:
public class Node{
 
    int sayi;
    String isim;
    Node next;
}

Üsteki kodumuz, düğümdeki bulunan verileri temsil eder ve bir düğümü diğer düğüme bağlanması içinde, next adında Node sınıfını temsil eden bir obje belirtiyoruz.

Java:
public class Main{
 
    public static void main(String[] args){
   
        Node A = new Node();
        Node B = new Node();
        Node C = new Node();
   
        A.sayi = 14;
        A.isim = "Çırpı";
   
        B.sayi = 16;
        B.isim "Cavidan";
   
        C.sayi = 11;
        B.isim = "Mükremin"
   
        A.next = B;
        B.next = C;
        C.next = null;
    }
}

Şeklinde düğülerimizi oluşturur ve birbirine bağlarız.

Kısaca böyle bir yapı oluşur;
1688595089173.png


Java:
Node temp = A;
while(temp != null){
    System.out.println(temp.isim + " adlı kişinin yaşı: " + temp.sayi);
    temp.next;
}

Üstekli kod ile de basitçe travelling yaparak yani düğümler üzerinde gezerek bilgiler edinebiliriz.


Böyle konular ve daha fazlası için beni takip etmeyi unutmayın ve beğenileriniz eksik etmeyin, he he :D.
 
Son düzenleme:
Bu arada "Bitwise Sort" olarak geçiyor sanırım yöntemin adı.
Bu da bir çözüm. Programlamada ihtiyaç hangisi ise onu kullanmak yada kendi yöntemlerini keşfetmek önemli ama bazen ateşi de yeniden keşfetmeye gerek yok tabii.

0 ms. de çözen adam için demedim. Bazen bizler bir konu için çok zorluyoruz ya hazır şeyler kullansak daha iyi olur diye dedim.
 
Bunu otomatik yapmanın bir yolu yok mu acaba 🤔?
Diziler yada listeler ile döngüler kullanılarak yapılabilir.
Java:
Node[] nodes = new Node[10];

for(int i = 0; i<nodes.lenhth; i++){
 
    nodes[i] = new Node();
    if(i !=0){
        nodes[i-1].next = nodes[i];
    }
}
nodes[nodes.lenght-1].next = null;
 
Son düzenleme:
Diziler yada listeler ile döngüler kullanılarak yapılabilir.
Java:
Node[] nodes = new Node[10];

for(int i = 0; i<nodes.lenhth; i++){
 
    nodes[i] = new Node();
    if(i !=0){
        nodes[i-1].next = nodes[i];
    }
}
nodes[nodes.lenght-1].next = null;
Bu da olur :). Benim aklıma da bir ara fonksiyon kullanmak gelmişti.
 
Bunu otomatik yapmanın bir yolu yok mu acaba 🤔?
next node u set etmeyi soruyorsanız, node sınıfının içine parametre olarak bir node alan constructor konabilir, yani
Node A = new Node();
Node B = new Node(A); //default olmayan constructor
Node C = new Node(B);

bu constructor üzerinden yaratılırsa parametreNode.next = this; yapılabilir.

Diziler yada listeler ile döngüler kullanılarak yapılabilir.
Java:
Node[] nodes = new Node[10];

for(int i = 0; i<nodes.lenhth; i++){
 
    nodes[i] = new Node();
    if(i !=0){
        nodes[i-1].next = nodes[i];
    }
}
nodes[nodes.lenght-1].next = null;
...
nodes[0] = new Node();
for(int i = 1; i<nodes.length; i++){
nodes = new Node();
nodes[i-1].next = nodes;
...
şeklinde yaparsanız if(i !=0) kontrolünden kurtulursunuz.
 
Bu veri yapısına genelde Linked List denir. Listenin sonuna ve başına eleman eklemek ve onlara erişmek neredeyse kayıpsız. Objeler belirli bir indekse göre sıralanmadığı için belirli bir sıradaki objeye erişmek de bir o kadar maliyetli. O yüzden ne zaman kullanılması gerektiğini iyi düşünmelisiniz. Java'daki obje bilginizi daha da ilerletilmek isterseniz Node içerisinde sayı, isim vs. barındırmak yerine istediğimiz objeyi alacak şekilde Generic'leri kullanabilirsiniz. Benim de Rust'tan gelme null'a karşı bir antipatim var. Bu yüzden listenin sonundaki objeyi null olarak atamak yerine, Optional atamayı daha uygun görüyorum. Daha sonra null sebebiyle yaşayacağınız sorunları engellemek adına böyle pratikler edinmeniz çok faydalı olur. Tabii isterseniz Linked List'i double hale getirip baş ve kuyruk kısmını da birleştirebilirsiniz. Bu sayede yüzüğü andıran bir veri yapısına sahip olursunuz ki bu gerçekten ihtiyacınız varsa kullanmanız gereken bir veri yapısı.

Bu çocuğu, çocukken izlemiştim ben he he . Şimdi abimizdir.

Bir dil, assemblye'e ne kadar yakın ise sonuç o kadar kısadır diye bir şey vardır ama Java'da bu durum öylemidir bilmem. 0 ms. sonucunu evet Java dilinde aldı .
Evet makineye yaklaştıkça hızın arttığı doğru fakat bu tarz problemlerin çözümlerindeki asıl sebep bellek yönetimi. Eğer problemi çözerken gereksiz obje üretiyor ve objenin üzerinde gereksiz değişiklikler yapıyorsanız yavaşlığı tecrübe etmeniz çok doğal. Örneğin listeleri kullanırken olabildiğince az sayıda ve sabit uzunlukta olmasına dikkat etmelisiniz. Objelerle çöp toplayıcısını meşgul ederseniz asıl kodun yürütülmesine sıra gelmeyecektir. Buna dikkat ettiğiniz sürece Assembly üzerinde yaptığınız işlemlerle Java'dakilerin düşündüğünüz kadar farklı olmadığını anlayacaksınız.
 
Son düzenleme:
Evet makineye yaklaştıkça hızın arttığı doğru fakat bu tarz problemlerin çözümlerindeki asıl sebep bellek yönetimi. Eğer problemi çözerken gereksiz obje üretiyor ve objenin üzerinde gereksiz değişiklikler yapıyorsanız yavaşlığı tecrübe etmeniz çok doğal. Örneğin listeleri kullanırken olabildiğince az sayıda ve sabit uzunlukta olmasına dikkat etmelisiniz. Objelerle çöp toplayıcısını meşgul ederseniz asıl kodun yürütülmesine sıra gelmeyecektir. Buna dikkat ettiğiniz sürece Assembly üzerinde yaptığınız işlemlerle Java'dakilerin düşündüğünüz kadar farklı olmadığını anlayacaksınız.
Mesela şundan mı bahsediyorsunuz?


Aşağıdaki kod sürekli GC'yi mejgul eder;
Java:
void yazdir(){
    String isim = "Merhaba ben Cafer";
    System.out.println(isim);
  
}

public static void main(String[] args){
    for(int i = 0; i<1000000;i++){
        yazdir();
    }
}


Aşağıdaki kod sürekli GC'yi meşgul etmez.
Java:
static String isim;

static void yazdir(){
    isim = "Merhaba ben Cafer";
    System.out.println(isim);
  
}

public static void main(String[] args){
    for(int i = 0; i<1000000;i++){
        yazdir();
    }
}
 
Mesela şundan mı bahsediyorsunuz?


Aşağıdaki kod sürekli GC'yi mejgul eder;
Java:
void yazdir(){
    String isim = "Merhaba ben Cafer";
    System.out.println(isim);
 
}

public static void main(String[] args){
    for(int i = 0; i<1000000;i++){
        yazdir();
    }
}


Aşağıdaki kod sürekli GC'yi meşgul etmez.
Java:
static String isim;

static void yazdir(){
    isim = "Merhaba ben Cafer";
    System.out.println(isim);
 
}

public static void main(String[] args){
    for(int i = 0; i<1000000;i++){
        yazdir();
    }
}

Şöyle bir bilgi ekleyeyim.

Javada string tipi veriler heap memory içinde bir string poolda tutulur. Sizin kodunuzun ilk bölümü şöyle çalışır: for döngüsünün içindeki String isim="Merhaba ben Cafer"; şeklinde bir kod çalıştırırsanız string poolda "Merhaba ben Cafer" diye bir string oluşturmuş olursunuz. for döngüsünün içinde bu işlemi ne kadar yaparsanız yapın her bir yeni değişken string pooldaki "Merhaba ben Cafer" olarak tutulan yere işaret edecektir. Bu heap memory kullanımını arttırmaz. Bütün String isim değişkenleriniz aynı yeri işaret eder.

Ancak; String isim="Merhaba ben Cafer"; yerine String isim=new String("Merhaba ben Cafer"); şeklinde kodunuzu yazıp yeni bir nesne oluştursaydınız, bir nesne yaratılacak ve bu da string poolda değil heap memoryde yeni bir alan işgal edecekti. for döngüsünün içinde bu satırı defalarca çalıştırsaydınız da dediğiniz gibi gcc meşgul olacaktı sürekli olarak bu nesneye bir referans var mı diye.

String isim="Merhaba ben Cafer"; şeklinde sürekli aynı stringe işaret eden değişkenler tanımlarsanız ise heap memory değil stack memory şişer, garbage collector stack memory ile ilgilenmez, heap memory ile ilgilenir. java programınıza kullanması için ayrılan memory dolarsa da stack overflow hatası alırsınız.
 

Technopat Haberler

Yeni konular

Geri
Yukarı