Stack (Yığın)

Tek taraflı giriş ve çıkışlara açık olan. İlk giren son çıkar LIFO (Last in First Out) mantığı ile çalışan bir ADT örneğidir.
Temelde iki veya üç fonksiyonu bulunur bunlar:
Push -> Stack içerisine bir bilgi koymaya (Stack’in en tepesine koyar)
Pop -> Stack içerisinden bir bilgi almaya (Stack’in en tepesinden alır)
Top -> Stack’in en tepesindeki bilgiyi alır ancak stackten çıkartmaz sadece okur
Stack Yığın
Bu fonksiyonlar sayesinde bir stack kullanılabilir hale gelmiş olur. Aynı fonksiyonlar ile PDA (push down Automata) ‘da tasarlanabilir.

Temel olarak stack, bir array veya Linked List üzerine inşa edilebilirler.
Örnek olarak bir dizi üzerine inşa edilen stack için bir değişken, dizide o anda kaç değer olduğunu tutacak ve her pop işleminden sonra bu değer azaltılırken, her push işleminden sonra arttırılacaktır.

Benzer uygulama linked list üzerinde yapılırsa, pop işlemiyle sondan bir düğüm silinecek veya push işlemi ile sona bir düğüm eklenecektir.

aşağıda basit bir bağlı liste üzerinde stack kullanılan kod örneği verilmiştir:

Yukarıdaki kodlar dev-cpp ile test edilmiştir.

Bağlı liste üzerinden yığın kodlamasının açıklaması (Cansu Hanım’ın sorusu üzerine ekliyorum)

Yukarıdaki bağlı liste kodunu anlamaya öncelikle kullandığımı veri yapısını oluşturan bir düğümü anlayarak başlayalım. Düğüm yapısı için kullanılan kodu ele alırsak:

Yukarıdaki bu kodda bulunan lnode isimli yapı (Struct) iki üyeye sahiptir. Buradaki data isimli int değişkeni, düğüm içindeki verileri tutmak için kullanılmakta ve yine kendi tipinden (lnode) bir gösterici (pointer) ile next isimli bir değişken tanımlanmaktadır. Bu ikinci gösterici değişkenin amacı, kendi tipinden düğümleri göstermek ve bu sayede bağlı listeyi inşa etmektir.

Kodun 8. Satırında ise global bir düğüm değişkeni olan iter tanımlanmış ve NULL olarak içeriği atanmıştır. Bu değişken bağlı listenin ilk elemanını tutmak için kodun geri kalan kısmında kullanılacaktır.

Veri yapımızı tanıdıktan sonra, bağlı liste üzerindeki yığın (stack) fonksiyonlarını anlamaya çalışalım. Bu kodda kullanılan 3 fonksiyon şunlardır:

Bu fonksiyonların çalışmalarını anlamaya push fonksiyonu ile başalayalım.

Yukarıdaki kodun, 11. satırında buluna if kontrolü ile, iter göstericisinin ilk değeri kontrol edilmiştir. Buradaki amaç, bağlı listenin ve dolayısıyla yığının içinin boş olup olmadığını anlamaktır. Şayet yığın boşsa (ve dolayısıyla iter’in değeri NULL ise) o zaman hafızada (ram) yeni bir düğüm tanımlanmış ve iter değişkeni bu düğümü gösterecek şekilde atanmıştır (kodun 13. satırı). Ayrıca bu yeni düğümün gösterdiği bağlantı NULL olarak atanmıştır. Bu sayede veri yapımızın son göstericisini NULL olarak ayarlanmış olunur.

Kodun 17. satırında push fonksiyonuna parametre veren ve yığına eklenmek istenen data değişkeni, yeni oluşturduğumuz bu düğümün içerisine veri olarak kaydedilmiş ve ardından yeni bir düğüm oluşturularak bağlı listenin başına eklenmiştir.

Bu fonksiyonun çalışmasını aşağıdaki şekilde hayal etmemiz mümkündür:

Yukarıdaki temsili resimlerde gösterilen 4. durum için, kodun 18. satırında yeni bir düğüm göstericisi tanımlanmış ve bu düğüm göstericisi, bağlı listenin ilk elemanını, kendi next göstericisi ile kodun 19. satırında göstermiştir. Bu sayede bağlı listenin başına yeni bir düğüm eklenmiş ve daha sonraki ekleme işlemleri için bu düğüm boş olarak tutulmuştur. Zaten kodun 11. satırında bağlı listenin boş olup olmadığının kontrol edilmesi ve şayet boş ise yeni bir düğüm eklenmesinin sebebi de budur.

Push fonksiyonu yukarıdaki şekilde, bağlı listeye yeni veri geldikçe ekleme işlemi yapar ve liste içerisine veri eklenerek temsili olarak sola doğru büyür. Listenin son elemanı her zaman için NULL değerindedir ve listeye yeni eklenen değerler soldan eklenir.

Kodun 44. satırına kadar olan main fonksiyonu içerisinde bulunan push fonksiyonları çalıştırıldığında bağlı listenin hali aşağıdaki şekli alır:

Push fonksiyonunun çalışmasına baktıktan sonra sıradaki fonksiyonumuz olan pop fonksiyonunu inceleyelim:

pop fonksiyonu, iter ile gösterilmekte olan düğümden (node) bir sonraki düğümün verisini döndürmekte ve iter göstericisini sağa doğru ilerletmektedir.

kodun 28. satırındaki free fonksiyonunun amacı, bu ilk başta tutulan düğümün hafızadan (ram) kaldırılması ve gereksiz yere yer kaplamamasıdır.

Son olarak yığının (stack) içeriğini ekrana basan fonksiyonumuz olan printStack fonksiyonunu incelersek:

bu kodda, temp isminde geçici bir gösterici, iter’in gösterdiği ilk elemandan başlayarak bağlı listenin sonuna kadar olan bütün elemanları sırasıyla ekrana basmaktadır.

Bu yazıyı beğendiyseniz, başkalarının da ilgisini çekebilirsiniz:


1,472 views

29 responses to “Stack (Yığın)”
  1. cansu says:

    programı tam olarak anlayamadım
    mesela push 10 dedik ama burdaki ekran çıktısı atıyorum 198556-10
    oluyo
    push 20 de ise 1985-20-10 şeklinde bu neden kaynaklanıyo yardımcı olabilirmisiniz

  2. Şadi Evren ŞEKER says:

    program, başta bulunan ve iter tarafından tutulan boş düğümü (node) de basıyor. Şayet bu tip baştaki anlamsız sayıları görmek istemiyorsanız, kodun 33. satırındaki
    lnode *temp = iter;
    kodunu aşağıdaki şekilde değiştiriniz:
    lnode *temp = iter->next;
    Bu defa yığının ilk elemanından başlanarak basılır ve aslında daha başta olan ve içerisinde veri olmayan boş düğüm basılmaz.

    Yukarıdaki yazının içerisine kodun nasıl çalıştığını açıklayan bir kısım eklemeye çalışayım belki yardımcı olur.

    başarılar

  3. cansu says:

    çok güzel bir açıklama.teşekkür ederim zaman ayırıp anlattığınız için :)

  4. serhat says:

    ben bu stack ve listelemeyi kullanarak bir dosyadan okunan 2 sayıyı carpmayı nasıl yapabiliriz. yada fgetchar ı kullanarak . yani ınput dosyasında olan iki sayıyı 2 ayrı listeye atıp bu sayıları çarpacak ve sonucu da br lsitede tutacak . yardımcı olursanız sevınırm

  5. Sorunuzu doğru anladıysam, çok büyük iki sayı, dosyalarda bulunuyor ve siz de bu dosyalardan her seferinde bir karakter okuyorsunuz. Dosyadan, sayının tamamı okunamayacak kadar büyük sayı olduğu için bu yolla okuyup sayıları nasıl çarpacağımızı soruyorsunuz.

    Bakın dosyalardan birisindeki örnek sayı aşağıdaki gibi olsun:

    1231432142121312312

    diğerinde de aşağıdaki sayılar olsun
    3432423423412312714

    Şimdi bu iki sayıyı , C dilinde bir değişkende tutamayacağımıza göre, bir yol bulup bunları çarpmalıyız. İlk okulda öğrendiğimiz üzere çarpma işlemine son haneden başlanır ancak ne yazık ki son hane, dosyanın sonunda bulunuyor ve dosyayı okumaya başladığımızda elimize ilk hane geliyor.

    Olsun, bu durumu tersine çevirmek mümkün. Veri yapılarından yığın (stack) tam da bunun için tasarlanmış. Başlıyoruz dosyadan okuduğumuz sayıları yığına (stack) koymaya.

    Neticede stackin en üstünde, çarpılacak olan sayıların son haneleri bulunuyor.

    Örneğin ilk yığının en üstünde, son sayı olan 2, ikinci yığında ise son sayı olan 4 bulunuyor.

    Bu iki sayıyı çarpıp elde var bilgisi ile sonraki sayılara geçiyoruz ve böylece bütün sayılar çarpılana kadar devam ediyoruz.
    Örneğimizden devam edecek olursak, 2×4 = 8 (elde var 0). 8′i bir kenara yazıp sonraki sayılara geçiyoruz (stackten pop ediyoruz)

    1×1 = 1 (elde var 0 )
    3×7 = 1 (elde var 2 )
    2×2 = 4 + 2 = 6 (elde var değeri buraya eklendi)
    Görüldüğü üzere elde var değeri için ilave bir değişken tutulması gerekiyor. Ayrıca yukarıdaki sonuçlar da bir listede durabilir.
    Şimdiye kadar olan sayılar için temsili liste:
    Head -> 6 -> 1 -> 1 -> 8 -> NULL

    Sürekli başa ekleme yapılan (insert front) yukarıdaki şekilde bir liste, sonucu tutmak için uygundur. Veya bu veriyi işlemeyecekseniz doğrudan ekrana basmak gibi yollar da bulunabilir.

    Bilemiyorum açıklayıcı oldu mu ama anlaşılmayan birşey olursa daha detaylı anlatabilirim.

    başarılar

  6. serhat says:

    yardımcı oldunuz teşekkürler.bu stack yerine linked list e atıp karakterleri snra carpma işlemi yapan örnek ufak bir kod var mı peki elinizde desem cok mu olmus olurm :d

  7. Aslında stack ve linked list farklı yapılar değiller. Yani olmaları gerekmiyor. Linked list, stack veya queue olarak kullanılabilir. Yukarıdaki anlattığım algoritmayı linked liste uyarlayabilirsiniz.
    Hazır kod yok ne yazık ki. Ancak bağlı liste kodlarına (linked list) bir göz atmanızı tavsiye ederim. Aşağıda bağlantıyı veriyorum :
    http://www.bilgisayarkavramlari.com/2007/05/03/linked-list-linkli-liste-veya-bagli-liste/

    Başarılar

  8. serhat says:

    çok olduğumun farkındayım ama lined listlerle yaparken karaker karakter okumak için fgetchar kullanmak lazım diye biliyorum . bu fgetchar ın kullanımını anlatablir misinziz rica etsem ?

  9. hayat says:

    merhabalar
    5+4*7+8 bu stringi kaakter karakter okuyup rakamları bir classa operatörleri ayrıbir classa yerleştiren daha sonra operatör sınıfından ilk operatörü alıp rakam sınıfından iki rakam alan (başta + operatörü var diğer class da da 7,8 alır toplar sonuc 15 dahasonra 15 i tekrar sayı sınıfına atar sonra operatör sınıfından * yı alır diger class dan 15 ve 4 alır bu operatör sınıfında hiç elemn kalmayana kadar devam eder sonuc 65 olnca sonucu geri döndürür)bunu stack ile nasıl yapabiliriz … yardımcı olursanız sevinirim

  10. bu meşhur bir ödev sorusudur. yanlız soru ile ilgili hatalarınız var. Algoritma tasarımınızda işlem önceliğini göz ardı etmişsiniz. Örneğin bahsettiğiniz şekilde işlem yapılınca sonuç 65 çıkıyor.

    Oysaki ilk yapılması gereken işlem 4*7 ve ardından toplama işlemleri. Yani sonuç 65 değil, 28 + 5 + 8 = 41 olmalı.

    Sorunun çözümü için ön işlem hesaplaması (prefix calculation, veya literatürde polonya yazımı hesaplaması (polish notation calculator) olarak da geçer) anlamanızda yarar var. Bu gösterimde sayılar prefix olarak aşağıdaki şekilde yazılıp hesaplanır:

    * + 2 3 4 = 10 (önce * 2 3 sonra + 4 işlemi yapılır)

    Benzer gösterim de son işlem hesaplaması (postfix calculator veya ters polonya yazımı hesap makinesi (reverse polish notation calculator) ) şeklinde geçer ve işlemler aşağıdaki şekilde yazılır:

    2 3 4 + * = 11 (önce 2 * 4 sonra + 3 işlemi yapılır)

    Gelelim sizin probleminize,
    infix gösterimi ile yazılan (yani işlemlerin (operators), sayıların arasında bulunması durumu) denklemler için aşağıdaki gibi stack (yığın) yapısı izlemeniz gerekiyor:

    Sizin verdiğiniz örnek üzerinden gidelim:

    5 + 4 * 7 + 8

    Öncelikle iki ayrı yığın (stack) tutuyoruz. Birisi sayıları (S1 olarak göstereceğim), diğeri ise işlemleri (S2 olarak göstereceğim ) barındırıyor.

    S1 –> 5 4
    S2 –> +

    İşlemin ilk 3 sembolüne baktığımızda yukarıdaki gibi bir durum ortaya çıkıyor. Yani basitçe 5+4 kısmına baktık. Devam edelim:

    S1 –> 5 4 7
    S2 –> + *

    Bu aşamada, * ve + işlemleri üst üste geldi. Şayet üst üste gelen işlemlerden öncelikli olan yukarıda ise yığına (stack) yerleştiriyoruz. Yani şu anda * işlemi + işleminden öncelikli olduğu için işlemi yapmadık ama yığına yerleştirdik.

    Bir sonraki adımda, sıradaki işlem + olarak gelecek ( denklemin sonunda bulunan + 8 kısmı). Bu durumda + işlemi *’dan düşük öncelikli olduğu için yığına konulamaz. Bunun yerine yığındaki işlem yapılır.

    S2 yığınında en üstte bulunan işlem (pop sonucu gelecek olan terim) * işlemidir. Bunu pop ediyoruz. Ayrıca S1 yığınından da iki değeri pop ediyoruz: 4 ve 7
    İşlemi yapıyoruz :

    4 * 7 = 28

    çıkan sonucu S1′e yerleştiriyoruz:

    S1 –> 5 28
    S2 –> +

    son durumda gelen yeni değere bakalım : + 8
    Yine yerleştirme yapmıyoruz çünkü yeni işlem + olarak geldi. İşlem yığını olan S2′de ise aynı önceliğe sahip + işlemi bulunuyor. Bu durumda yığında bulunan işlemi yapabiliriz:

    S1 –> 33
    S2 –> boş

    Şimdi gelen yeni terimleri yerleştirelim:

    S1 –> 33 8
    S2 –> +

    Son olarak denklem bittiği için stackteki işlemleri yapıyoruz:

    33 + 8 = 41 olarak sonuç bulunuyor.

    başarılar

  11. hayat says:

    hocam öncelikle teşekkür ederim verdiğiniz bilgiler için.benim sorunum aslında algoritmada değil
    kodda ben sayıları bir classa operatorleri diğer classa atmayı beceremedim c++ da. yardımcı olursanız gerçekten cok makbule geçer çünkü gerçekten bayadır uğraşıyorum

  12. class tasarımınızda bir hata olması çok yüksek ihtimal. sınıf tasarımınızı ve metot prototiplerinizi yollarsanız sizin için inceleyerek hatayı bulabilirim. Örneğin class diagram ve fonksiyonlarınızın parametrelerini yollayabilirsiniz.

    başarılar

  13. SEMA says:

    Merhabalar,stack yapısını kullanarak labirent yapmaya çalışıorum,bağlı liste ile oluşturlmuş bir stack yapsıı ne demek o şekilde yazmam gerekmiş?yiğina giriş noktasından itibaren izlenen yol eklenecek,giriş noktası sol üst köşe olcakmış bu kodu nasıl yazarım ben şöyle düşündüm
    int maz[0][0]=Yigin.indis dizinin içine ne yazmam gerk ki 0 0 dedim ama sol üst köşede bir yer olcak belki bu nokta bir duvar,sırayla aratmam mı gerk acaba,yardımcı olursanz çok sevinirim.

  14. Konu ile ilgili örnek bir kodu yazıp, aşağıdaki adreste yayınlamıştım. Okuyabilirsiniz.

    http://www.bilgisayarkavramlari.com/2011/11/04/labirentte-yol-bulma-kodu/

  15. cem says:

    Benim anlamadigim nokta stack veri yapisini kendimiz mi tasarliyoruz yoksa programlama dillerinin icinde geliyor mu?(push pop gibi fonksiyonlar yani)

  16. Kendimiz her zaman için tasarlayabiliriz. Örneğin yukarıdaki yazıda, C dili için tasarım verilmiştir. Ayrıca bazı dillerde stack yapısı hazır da sunulmaktadır. Örneğin JAVA, C# gibi dillerde hazır bulunur. Ancak standart C dilinde hazır bir stack yapısı bulunmaz. Kullanılmak istendiğinde kodlanmalıdır.

    java dilinde hazır stack yapısı için java.util.stack kütüphanesi kullanılabilir. Bu yapının kullanıldığı bir uygulamaya aşağıdaki bağlantıdan ulaşabilirsiniz:

    http://www.bilgisayarkavramlari.com/2011/11/04/labirentte-yol-bulma-kodu/

  17. muammer says:

    s.a hocam bir bağlı listeye, bir yığıtı nasıl aktarabiliriz?

  18. yığıt ile stack mi kastediliyor acaba? yani yığıt ile kastedilen heap ise farklı bir uygulama gerekir ancak stack ise, bu yazıda bulunan örnek kodların işinizi görmesi gerekir. Basitçe bir yığın (stack) dizide veya bağlı listede tutulabilir (linked list) ayrıca aktarma işlemine gerek yoktur. Yukarıdaki örnek kodda bu tutma işleminin nasıl yapıldığı anlatılmıştır. Şayet dizi temelli bir yığında (stack) tutuyor ve bağlı listeye (linked list) aktarmak istiyorsanız aşağıdaki gibi bir kod işinizi görür :

    while(!stack.isEmpty())
    liste.add(stack.pop());

    Başarılar

  19. muhendis_adayi says:

    mrb hocam yukarıda yığıtı link-list ile gerceklemissiniz link-list yerine bunu eleman sayı belli olan ornegin double tipinde 100 elemanlı bir diziyle gerceklemek istesek dizinin dolu veya bos oldugunuda denetleyerek nasıl olur ugrastım ama yapamadım diziyi bosaltamıyorum push tada pop tada sorun yasadım yardımcı olursanız sevinirim

  20. muhendis_adayi says:

    Hocam cevap bekliyorum 2 gün sonra 2 gün sonra 2.vizeler baslıyo ve dizilerle push pop gercekleme cıkacak kafamda tasarımını bir turlu olusturamadım hocanın istediği dizi[100] elemanlı olsun ornegin bunun doluluk bosluk durumlarınıda inceleyen C programı

  21. muhendis_adayi says:

    ben boyle bisey yazdım hocam#include “stdio.h”
    #define MAXVAL 100
    double val[MAXVAL];
    int sp = 0;
    void push (double f){
    if (sp==100)
    printf(“yıgıt daha eleman alamaz”);
    else{

    val[sp] = f;
    ++sp;
    }

    }

    double pop(void){
    double w;
    if (val[0] == ‘*’){
    printf(“yıgıtta eleman kalmadı”);

    }
    else {

    w = val[sp-1];
    val[sp-1] = ‘*’;
    –sp;
    }
    return w;
    }

    int main(void)
    {
    double p;
    push(3);
    push(5);
    push(9);
    push(7);
    p = pop();
    printf(“%0.f”,p);
    p= pop();
    printf(“%0.f”,p);
    p = pop();
    printf(“%0.f”,p);
    p = pop();
    printf(“%0.f\n”,p);
    p = pop();
    printf(“%0.f”,p);
    return 0;

    ama yıgıtta eleman kalmadıgı zaman yıgıtta eleman kalmadı0 donuyo sonundaki sıfır niye geliyo orayı anlayamadım

  22. Anladığım kadarıyla dizi ile yığın kodlamak istiyorsunuz. Basit bir kodlamayı aşağıdaki şekilde yapabilirsiniz:

    #define limit 100
    double a[limit];
    int sayac = 0;
    
    int push(double eklenen){
       if(sayac<limit){
          a[sayac++] = eklenen;
          return 1; // basarili
       }
       return -1; // hata limit dolu daha fazla eklenemez
    }
    
    double pop(){
       if(sayac > 0)
        return a[sayac -- ];
      return -1; // hata stack boş olduğu halde pop
    }
    
  23. kodunuzdaki hataya gelince. pop fonksiyonunda double w tanımlamışsınız. bu değişkene değer atamadığınız için kullandığınız compiler muhtemelen içerisine 0 atıyor.

    pop fonksiyonunuzda içinde değer kalmayınca ekrana değer kalmadı yazdırıyorsunuz (if’e giriyor) ancak sonra return w yapıyorsunuz. Bu durumda içinde değer olarak 0 olan değer döndürülüyor ve main fonksiyonunda ekrana printf ile yazılıyor dolayısıyla sonda gördüğünüz 0 değeri buradan geliyor.

    Başarılar

  24. muhendis_adayi says:

    double pop(){
    if(sayac > 0)
    return a[sayac -- ];
    return -1; // hata stack boş olduğu halde pop

    Hocam burda yazdıgınız kodda if deyiminden çıktıktan sonra return -1 dondurecek yanlıs mı dusunuyorum

    if(sayac > 0)
    return a[sayac -- ];
    else
    return -1; // hata stack boş olduğu halde pop

    else koymamız gerekmez mi?

    yine yazdıgınız kodun bu kısmındada aynı sey aklıma takıldı

    if(sayac<limit){
    a[sayac++] = eklenen;
    return 1; // basarili
    }
    return -1; // hata limit dolu daha fazla eklenemez

    yine else olmalı mı sorusu aklıma geliyo

  25. muhendis_adayi says:

    yani stack dolmadığı halde -1 dondurmez mı program?

  26. if deyiminden sadece hata olduğunda çıkacağı için bir sorun yok. Kod doğru. Yani if doğru ise zaten return yapılacak ve alttaki sizi endişelendiren return satırı hiç çalışmayacak. O satırın çalışması sadece hata olduğunda mümkün ki biz de zaten bu durumda -1 döndürmek istiyoruz. Benzer durum diğer fonksiyon için de geçerli.

    Başarılar

  27. yılmaz akca says:

    tek bağlı ve çift vağlı listeyede örnek kod verirmisiniz. java ve netbeans için

  28. muhendis_adayi says:

    tesekkur ederim hocam

  29. Bağlı liste konusunun anlatımı ve örnek kodlar aşağıdaki adreste yer alıyor. İstediğiniz kod var mı hatırlamıyorum ancak oradaki kodlara bir bakıp şayet istediğiniz kod yoksa oraya yorum olarak yazmanız halinde, vakit bulunca eklemeye çalışırım.

    http://www.bilgisayarkavramlari.com/2007/05/03/linked-list-linkli-liste-veya-bagli-liste/

    Başarılar

Leave a Reply


2 * = oniki

Benzer Yazılar:

Bilgisayar Kavramları üzerinde şu anda okumakta olduğunuz 'Stack (Yığın)' isimli yazı 04 May 2007 tarihinde, saat: 12:22 'de �adi Evren �EKER tarafından gönderilmiş, toplam1,472 defa okunmuştur.

Benzer yazıları Bilgisayar Kavramları, C/C++, JAVA, Programlama Dilleri, veri yapıları kategorilerinden okuyabilirsiniz. Yazar ile irtibat kurmak için email gönderebilirsiniz. Yazıya yorum yapabilir ya da yapılan yorumları RSS 2.0 ile takibe alabilirsiniz.


Category: Bilgisayar Kavramları, C/C++, JAVA, Programlama Dilleri, veri yapıları