Jump to page: 1 2 3
Thread overview
Yapı içinde bağlı liste oluşturmak...
Feb 19, 2012
Salih Dinçer
Feb 19, 2012
Salih Dinçer
Feb 19, 2012
Salih Dinçer
Feb 19, 2012
Salih Dinçer
Feb 20, 2012
Salih Dinçer
Feb 20, 2012
zafer
Feb 20, 2012
Salih Dinçer
Feb 20, 2012
zafer
Feb 21, 2012
Salih Dinçer
Feb 21, 2012
Salih Dinçer
Feb 23, 2012
Salih Dinçer
Feb 23, 2012
Salih Dinçer
Feb 23, 2012
zafer
Feb 24, 2012
Salih Dinçer
Feb 24, 2012
zafer
Feb 19, 2012
Salih Dinçer
February 19, 2012

Merhaba,

D.ersahane'nin ilgili dersi (http://ddili.org/ders/d/gostergeler.html)ndeki örnek programı aşağıya (yatık yazı benim eklememdir) alıntılıyorum:

'(Bu arada unutmadan küçük bir öneri; dersin bölümlerine** bağlantı|anchor** tanımlayabilsek ne iyi olurdu...)'
Alıntı (Göstergeler Dersi):

>

başınaEkle işlevinde yer alan ilk satırda sağ tarafta dinamik bir Düğüm nesnesi oluşturuluyor. Bu yeni nesne kurulurken, sonraki üyesi olarak listenin şu andaki başı kullanılıyor. Listenin yeni başı olarak da bu yeni düğümün adresi kullanılınca, listenin başına eleman eklenmiş oluyor.

Bu küçük veri yapısını deneyen küçük bir program:

> struct Düğüm
> {
>     int eleman;
>     Düğüm * sonraki;
>
>     this(int eleman, Düğüm * sonraki)
>     {
>         this.eleman = eleman;
>         this.sonraki = sonraki;
>     }
>
>     string toString() const
>     {
>         string sonuç = to!string(eleman);
>
>         if (sonraki) {
>             sonuç ~= " -> " ~ to!string(*sonraki);
>         }
>
>         return sonuç;
>     }
> }
>
> struct Liste
> {
>     Düğüm * baş;
>
>     void başınaEkle(int eleman)
>     {
>         baş = new Düğüm(eleman, baş);
>     }
>
>     string toString() const
>     {
>         return format("(%s)", baş ? to!string(*baş) : "");
>     }
> }
>
> void main()
> {
>     Liste sayılar;
>
>     writeln("önce : ", sayılar);
>
>     foreach (sayı; 0 .. 10) {
>         sayılar.başınaEkle(sayı);
>     }
>
>     writeln("sonra: ", sayılar);
> }
> ```

> **Çıktısı:**
> 'önce : ()
> sonra: (9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0)'
Yukarıdaki örnekteki **Düğüm** ve **Liste** yapılarını anlamaya çalışıyorum da veri, **Düğüm** yapısı içinde tutulduğuna göre **Liste**'nin tam olarak görevi nedir; ya da **Liste** aslında düğümlerin kendisi olabilir mi? Gerçi hayatta bir çok şey tersine işler (burada verilerin ters belleğe yerleşmesi gibi), belki de burada da bir ters mantık olabilir ama anlamakta zorlanıyorum... :rolleyes:

Yardımcı olursanız sevinirim, teşekkürler...

-- 
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]
February 19, 2012

Tekrar Merhaba...:)

Belleğe yerleşim bölgelerini görebilmek için 'main()''i aşağıdaki gibi ve bir de Düğüm içinde tek satırı değiştirdim. Sonuçta altındaki gibi bir çıktı aldım. Görünüşe göre her düğüm arasında epey bir boşluk (ubyte da denedim aynı!) varken; yapıların ilk elemanları ile yapıların adresleri aynıymış. Ayrıca *sonraki, Düğüm'ün başka bir kopyası (göstergesi) ama adresi farklı...

Son olarak ne hikmetse adresler hep geriye doğru gidiyor...:)

/*
listeyeEkle.d (19.02.2012)
*/
import std.array, std.conv, std.stdio, std.string, std.random;

struct Düğüm {
// ...
string toString() const {
       string sonuç = format("%d\t@%X\n", eleman, &eleman);
// ...

void main() {
   Düğüm say;
   Liste sayılar;

   writeln("Liste\t@", &sayılar, "\t.baş      @", &sayılar.baş);
   writeln("Düğüm\t@", &say, "\t.eleman   @", &say.eleman, "\t.sonraki  @", &say.sonraki);

   foreach (sayı; 0 .. 10) sayılar.başınaEkle(sayı);

   writeln(sayılar);
}

Çıktısı:
'salih@DB-N150-N210-N220:~/d.ders$ dmd listeyeEkle.d
salih@DB-N150-N210-N220:~/d.ders$ ./listeyeEkle
Liste @BFA99BD4 .baş @BFA99BD4
Düğüm @BFA99BCC .eleman @BFA99BCC .sonraki @BFA99BD0
-> 9 @BFA999F0
-> 8 @BFA99950
-> 7 @BFA998B0
-> 6 @BFA99810
-> 5 @BFA99770
-> 4 @BFA996D0
-> 3 @BFA99630
-> 2 @BFA99590
-> 1 @BFA994F0
-> 0 @BFA99450'

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 19, 2012

Teşekkürler...

Bellek kontrolünü hiç bilmiyorum. Neyse ki D, bunu bizim için yapıyor. Yoksa 'malloc()''lar ile kafayı yerdim; eminim...:)

Bu bağlı liste hakkında D'de çok fazla örnek bulamadığım için C örneklerine bakıyorum. Şurada çok güzel bilgiler buldum:

http://ddili.org/forum/unb_lib/designs/modern/img/arrow_right.png http://cslibrary.stanford.edu/103/LinkedListBasics.pdf (46 Kb.)

Ancak hala araya ekleme, sıralama ve silme olaylarını beceremedim ama yaklaştım. Mesele C'de YAPI şöyle oluşturuluyormuş:

struct node* Build() {
   struct node* head = NULL;

   head = malloc(sizeof(struct node)); // allocate 3 nodes in the heap
   head->data = 1; // setup first node
   head->next = second; // note: pointer assignment rule

   // At this point, the linked list referenced by "head" matches the list in the drawing.

   return head;
}

Neyse, konumuzda, forumuzda D... Yani önemli olan D ile yapabilmek. İlk olarak şöyle bir şeyler yaptım ama çok eksiğim var. Devam etmeden önce hatalarım var mı öğrenmek isterim?

/*
listeyeEkle.d (19.02.2012)
*/
import std.array, std.conv, std.stdio, std.string, std.random;

struct AĞAÇ {
   ubyte yaprak;
   AĞAÇ* sonrakiDal;

   this(ubyte yaprak, AĞAÇ* sonrakiDal) {
       this.yaprak = yaprak;
       this.sonrakiDal = sonrakiDal;
   }
   void ekle(ubyte değeri, ref AĞAÇ* boğumu) {
       auto ekle = new AĞAÇ(değeri, null);
       boğumu.sonrakiDal = ekle;
       boğumu = ekle;
   }
   string toString() const {
       string tamamı = format("%d\t@%X", yaprak, &yaprak);
       if (sonrakiDal) tamamı ~= "\n" ~ to!string(*sonrakiDal);

       return tamamı;
   }
}
void main (){
   AĞAÇ* tmp, soy = new AĞAÇ(0, null);

   ubyte [] s = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
   auto r = Random(unpredictableSeed);

   tmp = soy;
   foreach(e; randomCover(s, r))
   {
       soy.ekle(e, tmp);
   }

   writeln("AĞAÇdakiler~~~~v\n", to!string(*soy));
}

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 19, 2012

Alıntı (acehreli):

>

Görsel olarak deniyorum. Elimizde iki elemanlı bir liste bulunsun. new ile oluşturulmuş olan düğümlerin bellekte ilgisiz yerlerde olabildiklerini gösterebilmek için karışık olarak çiziyorum:

' ..............
| eleman: 100 |
| sonraki:null |
..............
^
Liste: |
..... |
| baş ----- |
..... | |
| ---------------------
| |
| ........... |
------------>| eleman: 7 | |
| sonraki ------
...........'

Bu çok çok güzel bir gösterim şekli, elinize sağlık. Şimdi ayrıntısı ile inceleceğim. Ben yukarıdaki iletimi yazarken aynı konudaymışız...:)

O yüzden gönderdikten sonra gördüm. Bu arada yukarıdaki kodların içinde diğer konudan (http://ddili.org/forum/thread/724) olan işlevlerde var. Bilmiyorum ikisini karşılaştırmaya orada mı devam etsek?

Sevgiler, saygılar...

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 19, 2012

Alıntı (Ali Çehreli):

>

Alıntı (Salih Dinçer):

>

Devam etmeden önce hatalarım var mı öğrenmek isterim?

YAPI güzel bir isim değil. ;)

listeyeEkle()'nin görevini güzelce oturtmak gerek. Neden YAPI'nın bir üye işlevi? Üye işlev olduğunda şu anda üzerinde işlediği nesneye bir etkisinin olmasını bekleyebiliriz. Örneğin veri ve sonraki üyelerini değiştirmesini bekleyebiliriz.

Ama anladığım kadarıyla 'bağı' parametresinin sonrasına yeni bir düğüm ekliyor. Burada bir soru: ya 'bağı'nın sonrasında zaten bir düğüm varsa? O zaman o bağlantıyı kopartmış oluruz.

Aklıma ilk anda fazla bir şey gelmediği için YAPI kullandım. Karışıklık olmasın diye sonradan iletiyi değiştirmeme gibi bir prensibimiz var; biliyorum ama sadece kodun gereksiz yerlerini çıkarıp aklıma gelen şeyi düzelttim:
Alıntı (Salih Dinçer):

>
> void main (){
>     AĞAÇ* tmp, soy = new AĞAÇ(0, null);
>
>     ubyte [] s = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ];
>     auto r = Random(unpredictableSeed);
>
>     tmp = soy;
>     foreach(e; randomCover(s, r))
>     {
>         soy.ekle(e, tmp);
>     }
>
>     writeln("AĞAÇdakiler~~~~v\n", to!string(*soy));}
> ```

Bilmiyorum, mümkün mü? Yani yaşam ağacı (Şecere) bana açıklamak için güzel göründü. Gerçi yaprak yerine aile kullanmak daha akıllıca olabilir. Standartların aksine AĞAÇ'ı özellikle büyük yazıyorum çünkü kod aralarında belirgin görünmesi iyi oluyor. Bağ yerine de yaprakların boğumları, ok çizgileri de dal (kodda sonrakiDal) şeklinde düzenledim. Şimdi güzel oldu mu?

Devam etmeden önce bugün öğrendiklerimi hazmedeyim. Genelde uzanıp sabaha kadar (bazen rüyalarda!) düşünüyorum ve uyandığımda deli gibi kod yazmak istiyorum...:)

**Dip Not:** Gerçek bir şecere için, sanırım daha çok elemanlı bir yapı kurmak gerekiyor. Biraz düşünmeliyim...

Sevgiler, saygılar...

-- 
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]
February 19, 2012

Alıntı (Salih Dinçer):

>

veri, Düğüm yapısı içinde tutulduğuna göre Liste'nin tam olarak görevi nedir

Öncelikle hayatımda yalnızca bir kaç kere bağlı liste yazmış olduğumu hatırlatayım. :) C++ ve D gibi diller elle yazılmalarını gerektirmeyecek kadar güçlüler. C++'ta std::list'i kullanırdım, D'de de std.container.SList'i...

Ben, düğüm kavramını bağlı listenin yapı taşı olarak ayrıca tanımladım: Her düğüm tek eleman barındırıyor ve bir sonraki düğümü gösteriyor.

Liste ise hangi düğümden başlandığını tutan tek göstergelik bir yapı. Daha kapsamlı bir liste olduğunda sonuncu elemanı da bu dış yapı gösterebilir.

Ayrıca toString() işlevleri de farklı: Düğümler kendi elemanlarını yazdırıyorlar ve yazdırma işlemini sonraki düğüme havale ediyorlar. Burada özyinelemeli bir durum var. Liste düzeyinde ise özyineleme yok: baştaki düğümün string olarak ifadesini elde ediyor ve etrafına parantez yazıyor.

O yüzden düğümüm ve listenin farklı düzeylerde kavramlar olduklarını düşündüm.

Yalnız bir hata yaptım ve hoş durduğu için başınaEkle() işlevinin içini tek satır olarak yazdım:

   void başınaEkle(int eleman)
   {
       baş = new Düğüm(eleman, baş);
   }

Şöyle daha açıklayıcı olabilirdi:

   void başınaEkle(int eleman)
   {
       Düğüm * yeniDüğüm = new Düğüm(eleman, baş);
       baş = yeniDüğüm;
   }

Alıntı:

>

Gerçi hayatta bir çok şey tersine işler (burada verilerin ters belleğe yerleşmesi gibi)

Burada bağlı listenin ters oluşmasının tek nedeni, Liste'nin basitliği. Yoksa 'son' diye bir gösterge de barındırabilir ve yeni düğümü ona bağlayabilirdir. Veya hızdan ödün vererek baştan başlayarak sonuncu düğümü bulurdu ve oraya ekleyebilirdi.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 19, 2012

Alıntı (Salih Dinçer):

>

Görünüşe göre her düğüm arasında epey bir boşluk (ubyte da denedim aynı!) varken;

O adresler bizim dışımızdaki düzenekler tarafından veriliyorlar. Kendi bildikleri iş. Adresleri gözlemlediğimizde artan yönde, azalan yönde, veya karışık yönde görebiliriz. Belleğin o anda neresinin boş olduğuna bağlıdır.

Alıntı:

>

yapıların ilk elemanları ile yapıların adresleri aynıymış.

Aynen öyle. C'de de öyledir. D yapıları ile C yapıları bire bir örtüşürler. (C++ yapıları ise ancak POD (plain old data) şartını sağlarlarsa öyledirler.)

Alıntı:

>

Ayrıca *sonraki, Düğüm'ün başka bir kopyası (göstergesi) ama adresi farklı...

'sonraki' bir gösterge olduğuna göre '*sonraki' onun gösterdiği değişken oluyor. Yani başka bir Düğüm.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 19, 2012

Görsel olarak deniyorum. Elimizde iki elemanlı bir liste bulunsun. new ile oluşturulmuş olan düğümlerin bellekte ilgisiz yerlerde olabildiklerini gösterebilmek için karışık olarak çiziyorum:

'
..............
| eleman: 100 |
| sonraki:null |
..............
^
Liste: |
..... |
| baş ----- |
..... | |
| ---------------------
| |
| ........... |
------------>| eleman: 7 | |
| sonraki ------
...........
'

Listenin 'baş' üyesi baştaki elemanı gösteriyor. Onun değeri 7. O da bir sonraki elemanı gösteriyor. Onun değeri 100. Artık ondan sonra düğüm gösterilmiyor çünkü onun 'sondaki' üyesinin değeri null.

Şimdi şu işlevin nasıl işlediğine bakalım:

   void başınaEkle(int eleman)
   {
       Düğüm * yeniDüğüm = new Düğüm(eleman, baş);
       baş = yeniDüğüm;
   }

Eleman değeri 42 olduğunda o birinci satır işletildiğinde durum şunun gibidir:

'
..............
| eleman: 100 |
| sonraki:null |
..............
^
Liste: |
..... |
| baş ----- |
..... | |
| ---------------------
| |
| ........... |
------------>| eleman: 7 | |
| sonraki ------
...........
^
|
|
..........
|
|
............ |
yeniDüğüm ------------>| eleman: 42 | |
| sonraki -------
...........
'

Yeni düğüm oluşturulurken onun sonraki üyesinin değeri olarak 'baş'ın değeri kullanıldığı için şimdi hem 'baş' hem de 'yeniDüğüm.sonraki' aynı düğümü gösteriyorlar.

Ondan sonra kodun ikinci satırına geçiyoruz ve 'baş'ın 'yeniDüğüm'ü göstermesini sağlıyoruz. Şimdi durum şu:

'
..............
| eleman: 100 |
| sonraki:null |
..............
^
Liste: |
..... |
| baş ----- |
..... | |
| ---------------------
| |
| ........... |
| | eleman: 7 | |
| | sonraki ------
| ...........
| ^
--------------- |
| |
| ----------
| |
v |
............ |
yeniDüğüm ------------>| eleman: 42 | |
| sonraki -------
...........
'

Evet şu anda yeni eklenen 42 değeril düğümü gösteren iki gösterge var: baş ve yeniDüğüm. Ama olsun, bu işlevden çıkıldığında yeniDüğüm isimli gösterge uçup gidecek ve geriye şu kalacak:

'
..............
| eleman: 100 |
| sonraki:null |
..............
^
Liste: |
..... |
| baş ----- |
..... | |
| ---------------------
| |
| ........... |
| | eleman: 7 | |
| | sonraki ------
| ...........
| ^
--------------- |
| |
| ----------
| |
v |
............ |
| eleman: 42 | |
| sonraki -------
...........
'

İşte başına işleme olayı gerçekleşmiş oldu.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

February 19, 2012

Alıntı (Salih Dinçer):

>

Ancak hala araya ekleme, sıralama ve silme olaylarını beceremedim ama yaklaştım.

Çok normal. ;) Baştan çok zorlayan ama birden anlaşılan bir konudur.

Alıntı:

>

Mesele C'de YAPI şöyle oluşturuluyormuş:

> struct node* Build() {
>     struct node* head = NULL;
>
>     head = malloc(sizeof(struct node)); // allocate 3 nodes in the heap
>     head->data = 1; // setup first node
>     head->next = second; // note: pointer assignment rule
>
>     // At this point, the linked list referenced by "head" matches the list in the drawing.
>
>     return head;
> }
> ```

>

C++ forumlarında hep tekrarlarım: C++'ın new'ü, C'nin "malloc() + üye ilkleme" işleminin eşdeğeridir. Yani bellekten yer ayırma ve nesne kurma.

Neyse ki D'de kurucu işlev kavramı hem de otomatik olarak bulunduğundan şu D işlevi yukarıdaki C işlevinin eşdeğeri oluyor:


struct node* Build() {
node* head; // D'de zaten null olarak ilklenir

head = new node(1, second); // aradaki üç satırın eşdeğeri

return head;
}



Değişkenlerin tanımlandıkları satırda ilklenmeleri C'de haklı nedenlerle yaygın değildir. D'de şu daha iyi:


struct node* Build() {
node* head = new node(1, second);

return head;
}



Ama bazen kodun anlaşılmasının engellenmediği düşünüldüğünde daha da kısa olarak:


struct node* Build() {
return new node(1, second);
}



C'de nasıl her işlem teker teker yapılmak zorundaydı ama D'de nasıl üst düzey bir kavram olarak açıkladık: "değeri 1 olan ve second'ı gösteren bir node oluştur ve döndür."

Alıntı:
> Devam etmeden önce hatalarım var mı öğrenmek isterim?

YAPI güzel bir isim değil. ;)

listeyeEkle()'nin görevini güzelce oturtmak gerek. Neden YAPI'nın bir üye işlevi? Üye işlev olduğunda şu anda üzerinde işlediği nesneye bir etkisinin olmasını bekleyebiliriz. Örneğin veri ve sonraki üyelerini değiştirmesini bekleyebiliriz.

Ama anladığım kadarıyla 'bağı' parametresinin sonrasına yeni bir düğüm ekliyor. Burada bir soru: ya 'bağı'nın sonrasında zaten bir düğüm varsa? O zaman o bağlantıyı kopartmış oluruz.

Yanlış demiyorum. Yalnızca kafamda böyle sorular oluştu. Ama sonuçta bağlı liste bir kaç göstergeye başka düğüm göstertme üzerine kurulu olan basit bir olay. Kağıt üzerinde düşünmek de çok yararlı oluyor. Devam... :)

Ali

-- 
[ Bu gönderi, <http://ddili.org/forum>'dan dönüştürülmüştür. ]
February 19, 2012

Alıntı (Salih Dinçer):

>

Aklıma ilk anda fazla bir şey gelmediği için YAPI kullandım.

Tabii ki. :) İsimler çok önemli. Güzel isim veremediğimiz zaman tasarımda sorun var demektir. Örneğin birden fazla kavramı temsil etmeye çalışıyoruzdur veya fazla sorumluluk vermişizdir, vs.

Alıntı:

>

yaşam ağacı (Şecere) bana açıklamak için güzel göründü.

Bir şanssızlık, en yaygın üçüncü veri yapısının ismini seçmişsin: dizi, liste, ağaç. ;) (Yaygınlık sıralarını uyduruyorum tabii ki. :-p) Bağlı listeye ağaç demek karışıklık yaratır. İngilizce isimleri:

  • array

  • linked list

  • tree (daha çok 'binary tree')

D'nin eşleme tabloları olan 'hash table' da başlıca veri yapılarından bir diğeridir.

Alıntı:

>

sabaha kadar (bazen rüyalarda!) düşünüyorum

Ne güzel! :) Uykunun o günkü problemlerin irdelenmesi ve yeni çözümler aranması ile ilgili olduğu biliniyor.

Ali

--
[ Bu gönderi, http://ddili.org/forum'dan dönüştürülmüştür. ]

« First   ‹ Prev
1 2 3