Bu site emekli olmuştur. Arşiv amaçlı olarak BT AKADEMİ sponsorluğunda yayın hayatına devam etmektedir.




C#nedir?com
 
YAZAR HAKKINDA
Çiğdem Çavdaroğlu
Çiğdem Çavdaroğlu
http://www.csharpnedir.com/
İletişme geçmek için tıklayın.
28 Makalesi yayınlanmakta.
Yazar hakkında detaylı bilgi için tıklayın.
Yayınlanan diğer makaleleri için tıklayın.
İlgili etiketler: (index degeri degerine degerini elemanina fonksiyon fonksiyonumuzu ilgili iliskin isimli kaydin listenin listeyi return tmprecord C / Sys Prog. Çiğdem Çavdaroğlu
 
YAZI HAKKINDA
Türü : Makale
Serbest Köşede C#nedir?com üyelerinin hazırladıkları yazılar yayınlanır. Bu yazılar editör incelemesine girmeden yayınlanır.
Seviyesi : Orta
Kategori : C / Sys Prog.
Yayınlanma Tarihi : 30.4.2005
Okunma Sayısı : 19842
Yorum Sayısı : 0     yorum yaz
Site İçi AramaSİTE İÇİ ARAMA
Üye Girişini AçÜye GİRİŞİ
Üye girişi için tıklayın.
Kullanıcı Adı
Şifre
 
Beni her zaman hatırla
Bir hafta boyunca kullanıcı bilgilerinizi kullanıcı çıkışı yapana kadar hatırlar. (Paylaşılan bilgisayarlarda önerilmez.)
 
Şifremi / Kullanıcı Adımı unuttum.
 
.net TV RSS Serbest KÖŞE (?)
Serbest Köşede C#nedir?com üyelerinin hazırladıkları yazılar yayınlanır. Bu yazılar editör incelemesine girmeden yayınlanır.
emre TAŞ
Silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
emre TAŞ
silindi
emre TAŞ
yazının devamı >
Makale Gönder Bende Yazmak İstiyorum
.net TV RSSBlogroll
Turhal Temizer
Conda install environment.yml Package 24.11.2024
Turhal Temizer
Mac OS/X Removing CUDA 24.11.2024
Burak Selim Şenyurt
Rust ile ECS Yaklaşımını Anlamak 24.11.2024
Burak Selim Şenyurt
Birlikte Rust Öğrenelim Serisi 24.11.2024
  Diğer Herşey
Sponsorlar
BT Akademi
Medya Portakal
Video Hosting Sponsoru
Csharpnedir.com bir Ineta üyesidir
Uzman Abi
Her Yönüyle C# - Sefer Algan
Karakter Katarları Üzerinde İşlemler ve Bağlı Liste Uygulaması - 2
 
Kapat
Sayfayı Yazdır Sık Kullanılanlara Ekle Arkadaşıma Gönder MySpace Del.Ico.Us Digg Facebook Google Mixx Reddit StumbleUpon
Yazı dizimizin ilk adımında karakter katarları ile ilgili genel bilgiler vermiştik ve karakter katarları üzerinde işlemler yapabileceğimiz bir bağlı liste uygulamasına başlamıştık. İkinci adımda, bağlı liste uygulamamıza fonksiyonlar eklemeye devam edeceğiz. Karakter katarları ile ilgili işlemler yapan bir takım fonksiyonlar yazarak, uygulamamızda bu fonksiyonlardan yararlanacağız. Yaptıklarımızı kısaca gözden geçirecek olursak; öncelikle iki yapı bildiriminde bulunduk. "record" isimli yapımız, bağlı listedeki elemanlara ilişkin bilgileri tutuyordu. "recordList" isimli yapımız ise, elemanlara ilişkin bilgileri tutan "record" türünden nesneleri tutuyordu. "recordList" yapısında, sadece bağlı listedeki ilk elemana ilişkin adresin tutulması yeterli idi, diğer elemanlara bir önceki elemanda tutuğumuz adres yoluyla erişiyorduk. Bu yapıların başlangıç fonksiyonlarını, listeye baştan ve sonran yeni kayıt ekleyen fonksiyonlarını yazmıştık. Şimdi, listenin herhangi bir sırasına yeni kayıt ekleyen fonksiyonumuzu yazalım :

//başlık dosyası
#define TRUE 1
#define FALSE 1

typedef int BOOL;

BOOL InsertRecordToList(recordList list, char *name,int number, int index); /* Prototip bildirimi */

//kaynak kod dosyası
BOOL InsertRecordToList(recordList list, char *name,int number, int index)
{
    record *tmpRecord, *newRecord;

    if (index == list->size + 1)
    {
       AddRecordEnd(list,name,number);
       return TRUE;
    }

    if (index == 1)
    {
       AddRecordStart(list,name,number);
       return TRUE;
    }

    if (index > list->size || index < 1)
       return FALSE;
    tmpRecord = list->start;
    newRecord = CreateRecord();
    SetRecord(newRecord,name,number);

    index -= 2;
    while (index--)
       tmpRecord = tmpRecord->rNext;

    newRecord->rNext = tmpRecord->rNext;
    tmpRecord->rNext = newRecord;
    return TRUE;
}

Fonksiyonun geri dönüş değeri olarak kullandığımız BOOL ismi, typedef bildirimi yapılarak (int) türünün yeni ismi olarak kullanılmıştır. TRUE ve FALSE ise sırasıyla 1 ve 0 değerlerine define edilmiştir. Fonksiyon başarı durumunda sıfır dışı bir değere (TRUE), başarı durumunda ise sıfır değerine (FALSE) dönecektir. Eğer "index" parametresine geçilen değer, listenin eleman sayısından fazla ise veya 1’den küçük bir değer ise ekleme yapılmıyor; bu durumda fonksiyon sıfır değerine dönüyor. Bu değer 1 ise, listenin başına ekleme yapan fonksiyon çağrılıyor, listenin eleman sayısından 1 fazla ise listenin sonuna ekleme yapan fonksiyon çağrılıyor. Diğer durumlarda araya ekleme işlemi yapılıyor. Biz listemizde sadece ilk kayda ilişkin adresi tutuyoruz. Dolayısıyla araya ekleme yapma durumunda aradaki bir kaydın adresine listeyi kullanarak doğrudan erişemeyiz. Bunun yerine, listedeki elemanları "index" parametresinde belirtilen sayı kadar dolaşarak ilgili kaydın adresine ulaşırız. Araya ekleme işlemi için yapılması gereken, "index" değerinden bir önce sırada bulunan kaydın "rNext" isimli veri elemanına yeni kaydın adresini atamak ve yeni kaydın "rNext" isimli veri elemanına da "index" değerinden bir sonraki sırada bulunan kaydın adresini aramaktır.
Bu işlemi bir şema ile gösterelim :



Fonksiyonumuzda, listeyi dolaşırken kullanacağımız record * türünden geçici bir nesne tanımlıyoruz. Listeyi dolaşırken her adımda ilgili kaydı bu nesneye atayarak kaydın bilgilerine ulaşıyoruz. (record *) türünden tanımladığımız "newRecord" isimli nesnemizi de fonksiyona parametre olarak geçilen bilgileri atayarak oluşturuyoruz. Döngü değişkeninin değerini önce listenin başında bulunan kaydın sıra numarasını sıfır kabul ettiğimiz için, sonra da ilgili sıra numarasından bir önceki kayda ulaşmak istediğimiz için birer defa azaltıyoruz. (index -= 2) Döngü (index--) koşulu sağlandığı sürece dönüyor. Yani bu değer sıfıra ulaştığında döngüden çıkılacak ve "tmpRecord" isimli nesne aradığımız kaydı gösteriyor olacak. Yeni kaydımızın "rNext" veri elemanına da birinci sıradaki kaydın "rNext" veri elemanında tutulan adresi atıyoruz. "tmpRecord" nesnesinin gösterdiği kaydın "rNext" veri elemanına da yeni kaydımızın adresini atıyoruz. Böylece araya ekleme işlemi gerçekleşmiş oluyor.
Şimdi de belli bir kaydı silen fonksiyonumuzu yazalım :

BOOL DeleteRecordFromList(recordList list,int index); /* Prototip bildirimi */

BOOL DeleteRecordFromList(recordList list,int index)
{
    record *tmpRecord, *deleteRecord;
    int tmpIndex = index;

    if (index > list->size || index < 1)
       return FALSE;
    tmpRecord = list->start;

    if (index == 1)
    {
       list->start = tmpRecord->rNext;
       free(tmpRecord);
       return TRUE;
    }

    index -= 2;
    while (index--)
       tmpRecord = tmpRecord->rNext;

    deleteRecord = tmpRecord->rNext;
    if (tmpIndex == list->size)
       tmpRecord->rNext = NULL;
    else
       tmpRecord->rNext = deleteRecord->rNext;

    free(deleteRecord);
    return TRUE;
}

Kayıt silen fonksiyonumuz da başarı durumunda sıfır dışı bir değere, başarısızlık durumunda ise sıfır değerine dönüyor. Fonksiyonumuzun başında yine listeyi dolaşırken kullanacağımız (record *) türünden geçici bir gösterici tanımlıyoruz. Döngünün her adımında sıradaki kaydı bu geçici nesneye atıyoruz. Kayıt silme işlemi, ilgili kayıttan bir önceki sırada bulunan kaydın "rNext" isimli veri elemanına ilgili kayıttan bir sonraki sırada bulunan kaydın adresinni atanması ve silinecek kaydın "free" fonksiyonu ile serbest bırakılması yoluyla gerçekleştirilir. Bu işlemi bir şema ile gösterelim :



while döngüsü ile aradığımız kayda ulaştıktan sonra, silinecek kaydı tutacak olan "deleteRecord" isimli nesneye bu kaydın "rNext" isimli veri elemanında tutulan kayıt adresini atıyoruz. Bu değeri silme işlemini tamamladıktan sonra free etmeliyiz. Fonksiyonun başında, silinecek kaydın ilk kayıt olup olmadığını kontrol ediyoruz. Eğer ilk kayıt ise, listenin "start" isimli veri elemanına tmpRecord nesnesinin "rNext" veri elemanında bulunan adresi atıyoruz ve tmpRecord nesnesini serbest bırakarak fonksiyonu sonlandırıyoruz. Eğer silinecek kayıt ilk kayıt değilse, kayıttan bir önceki eleman bulunana dek döngüde kalıyoruz. Döngüden çıktığımız noktada artık elimizde aradığımız kayıt mevcut durumdadır. Bu noktada, silinecek kaydın son kayıt olup olmadığını kontrol ediyoruz. Eğer son kayıt ise, tmpRecord’da bulunan kaydın "rNext" isimli veri elemanına NULL değerini atamamız gereklidir. Çünkü ilgili kayıt silindikten sonra artık bu kayıt son kayıt durumunda olacaktır. Eğer son kayıt değilse, tmpRecord’un "rNext" isimli veri elemanına deleteRecord’un "rNext" isimli veri elemanında tutulan adresi atıyoruz. En son tmpRecord nesnesini serbest bırakıyoruz. Bu fonksiyon, silinecek kaydın sıra numarasının bilindiği durumlarda kullanılabilir. Ancak silinecek kaydın sıra numarasını değil de, değerini biliyorsak bunun için başka bir fonksiyon yazmamız gerekecek. Bu fonksiyon, örneğin öğrencinin adını alacak ve listeyi dolaşarak bu isme sahip bir kayıt olup olmadığını kontrol edecek. Eğer var ise bu kaydı silecek. Bunun için öncelikle listede arama işlemini yapacak fonksiyonumuzu tasarlayalım :

int FindRecordInList(recordList list, char *name); /* Prototip bildirimi */

int FindRecordInList(recordList list, char *name)
{
    record *tmpRecord = list->start;
    int i = 0, size = list->size;

    while (i++ != size)
    {
       if (!strcmp(tmpRecord->rName,name))
          return i-1;
       tmpRecord = tmpRecord->rNext;
    }
    return -1;
}

Arama işlemini yapan fonksiyonumuz, listeyi ve arayacağı ismi parametre olarak alıyor. Eğer listede o isme sahip olan bir öğrenci kaydı mevcut ise kaydın sıra numarasına, mevcut değil ise -1 değerine geri dönüyor. Burada izleyeceğimiz mantık yine aynı. (record *) türünden "tmpRecord" isimli bir geçici gösterici tanımlayarak fonksiyona başlıyoruz. while döngümüz (i++ != size) koşulu sağlanana dek dönecek. Yani döngü değişkeni i, listenin eleman sayısına ulaştığında arama işlemi bitiyor. Eğer i’nin değeri size’ın değerine ulaşmadan önce aranan kayıt bulunursa (return i - 1;) ifadesi ile kaydın sıra numarasına geri dönülüyor. Her adımda tmpRecord isimli geçici göstericinin gösterdiği nesnenin "rName" isimli veri elemanının değeri ile fonksiyona gönderilen name isimli göstericinin gösterdiği nesnenin değeri, standart strcmp fonksiyonu ile karşılaştırılıyor. Eğer karşılaştırılan iki ifadenin değeri birbirine eşit ise bu fonksiyon sıfır değerine döner. if koşulu içerisindeki ifade de bunu sınamaktadır. Yeni geliştirilmiş dillerde, karakter katarları "==" eşitlik operatörü ile karşılaştırılabiliyor. Ancak C dilinde bu yapılmamalıdır. Eğer (tmpRecord->rName == name) şeklinde bir ifade yazılırsa, derleyici bu iki karakter katarının adres değerlerini karşılaştırır. Çünkü şu halleri ile bu nesneler bir göstericidir ve içlerinde adres bilgisi tutarlar. İki karakter katarı da hiçbir zaman aynı adreste bulunamayacağına göre böyle bir ifade her zaman yanlış yorumlanacaktır. Karşılaştırma işlemleri için standart strcmp fonksiyonu kullanılmalıdır. Şimdi silmek istediğimiz kaydın sıra numarasını önce bu fonksiyon yardımı ile bulabiliriz. Fonksiyonumuzu şu şekilde tasarlayabiliriz :

BOOL DeleteRecordFromListByName(recordList list,char *name); /* Prototoip bildirimi*/

BOOL DeleteRecordFromListByName(recordList list,char *name)
{
    int index = FindRecordInList(list,name);

    if (index == -1)
       return FALSE;

    return DeleteRecordFromList(list,index);
}

Kaydı, isminden bularak silen fonksiyonumuz parametre olarak kaydın ismini ve listeyi alıyor. Fonksiyonda öncelikle söz konusu isme sahip olan kayıt "FindRecordInList" fonksiyonu ile bulunuyor. Eğer bu fonksiyondan -1 değeri dönerse, demek ki listede o isme ilişkin bir kayıt yoktur ve fonksiyonumuz bu durumda FALSE değerine döner. Aksi durumda, kayıt bulunmuştur ve artık elimizde kaydın sıra numarası da olduğuna göre daha önce yazmış olduğumuz "DeleteRecordFromList" fonksiyonumuzu çağırabiliriz. Fonksiyonumuz, çağrılan bu fonksiyondan dönen değere geri dönüyor. Burada, liste içerisinde, gönderilen isme ilişkin ilk kaydın bulunduğuna dikkat etmelisiniz. Eğer aynı isme ilişkin birden fazla kayıt bulunabilecekse ve böyle bir çağrı ile o isme sahip olan tüm kayıtların silinmesi istenirse fonksiyon farklı bir şekilde tasarlanmalıdır. Buna örnek teşkil etmesi açısından listede belli bir not değerine sahip olan tüm kayıtları silen bir fonksiyon yazalım. Öncelikle listemizde ilgili not değerine sahip olan tüm kayıtları bulalım ve bunların liste içerisindeki sıra numaralarını dinamik olarak tahsis edeceğimiz bir dizi içerisinde tutalım. Daha sonra bu diziden silinecek kayıtların sıra numaralarını alarak, sıra numarasına göre silme işlemi yapan fonksiyonumuzu çağıralım :

BOOL DeleteAllRecordsFromListByNumber(recordList list,int number); /* Prototip bildirimi */

BOOL DeleteAllRecordsFromListByNumber(recordList list,int number)
{
    int i, recordNum = 0, size = list->size;
    int *indexArray = (int *)malloc(size * sizeof(int));
    record *tmpRecord = list->start;

    for (i = 0; i < size; ++i)
    {
       if (tmpRecord->rNumber == number)
       indexArray[recordNum++] = i;
       tmpRecord = tmpRecord->rNext;
    }

    if (recordNum == 0)
       return FALSE;

    for (i = 0; i < recordNum; ++i)
       DeleteRecordFromList(list,indexArray[i]+1-i);

    free(indexArray);
    return TRUE;
}

Fonksiyonumuz parametre değişkeni olarak listeyi ve not değerini alıyor. Tanımladığımız değişkenlere göz atalım : "i", döngü değişkeni olarak kullanılıyor. "recordNum" isimli değişken, ilgili not değerine ilişkin kaç tane kayıt bulunduğu bilgisini, "size" ise listedeki eleman sayısını tutuyor. "indexArray" isimli tamsayı türünden dizide ise silinecek kayıtların sıra numaralarını tutuyoruz. Bu diziyi dinamik olarak, listedeki kayıt sayısı kadar tahsis ediyoruz. Çünkü listedeki tüm kayıtlara ilişkin not değeri, fonksiyona gönderilen not değerine eşit olabilir. Taşma hatası ile karşılaşmamak için diziyi maksimum boyutta tahsis ediyoruz. (Burada dizi için önce küçük bir miktar tahsis edip, dizide tutulması gereken eleman sayısı arttığı sürece yeniden tahsisat yapılması yoluna da gidilebilir. Listedeki kayıt sayısı çok fazla olduğunda bu yöntem daha etkin olacaktır.) "tmpRecord" isimli değişkeni yine listeyi dolaşırken kullanıyoruz. Bu göstericiye öncelikle listenin başındaki kaydın adresini atıyoruz. Her adımda, tmpRecord göstericisinin gösterdiği yerdeki nesnenin "rNumber" isimli veri elemanının değeri ile fonksiyona gönderilen "number" isimli parametre değişkeninin değerini karşılaştırıyoruz. Eğer bu iki değer eşit ise tmpRecord göstericisi şu anda aradığımız kayıtlardan birisini göstermektedir. Bu noktada "indexArray" dizimizin sıradaki elemanına i döngü değişkeninin değerini atıyoruz. Bu noktada i döngü değişkeni aradığımız kaydın liste içerisindeki sıra numarasını göstermektedir. Döngüden çıkıldığında eğer "recordNum" değişkeninin değeri sıfıra eşit ise demek ki listede söz konusu nota sahip hiçbir kayıt bulunmamaktadır. Bu duurmda fonksiyon FALSE değerine geri dönüyor. Aksi durumda yine bir for döngüsüne giriyoruz. Bu döngü "recordNum" değişkeninin değeri kadar dönecek. Döngü içerisinde, "DeleteRecordFromList" isimli fonksiyonumuzu çağırıyoruz. Bu fonksiyon, sıra numarasına göre listeden kayıt siliyordu. Sıra numarası olarak da "indexArray" dizisinde sakladığımız değerleri kullanacağız. Ancak bu noktada bir şeye dikkat etmeliyiz : Örneğin sileceğimiz kayıtların sıra numaraları sırasıyla 0, 4, 5 olsun. Bu durumda sıfır sıra numaralı kayıt silindikten sonra, döngünün diğer adımında silme işlemini yapan fonksiyona sıra numarası olarak dört gönderirsek yanlış kaydı silmiş oluruz. Çünkü listeden bir kaydın silinmesi ile artık listemizin sıralaması değişmiş durumdadır. Doğru kayda erişmek için (indexArray[i]+1-i) ifadesini kullanmalıyız. Burada bir eklenmesinin sebebi, silme işlemi yapan fonksiyonun sıra numarasının başlangıcı olarak 0’ı değil 1’i baz almasıdır. (-i) yazılmasının sebebi ise kayıt silindikçe listedeki sıralama değişikliğinden kaynaklanan farkı gidermektir. İlk adımda 0 numaralı kayıt silindiğinde, 4 numaralı kayıt artık 3 numaralı kayıt olacaktır. Bu ifade ile bu şekilde doğru kayda ulaşım sağlanır. Fonksiyondan çıkmadan önce dinamik tahsis ettiğimiz alanı boşaltıyoruz ve TRUE değerine dönüyoruz. Şimdi de listemizdeki kayıtlara sıra numaraları ile ve isimleri ile ulaşarak not değerlerini güncelleyelim. Üç tane fonksiyon yazacağız. Bu üç fonksiyonumuzun prototip bildirimleri şu şekilde :

BOOL UpdateRecordByIndex(recordList list,int index,int newNumber);
BOOL UpdateRecordByName(recordList list,char *name,int newNumber);
void UpdateRecordByNumber(recordList list,int number,int newNumber);

Parametre değişkeni olarak, ilk fonksiyonumuz listeyi, sıra numarasını ve yeni not değerini; ikinci fonksiyonumuz listeyi kaydın isim bilgisini ve yeni not değerini ; üçüncü fonksiyonumuz ise listeyi, not değerini ve yeni not değerini alıyor. İlk fonksiyonumuzu yazalım :

BOOL UpdateRecordByIndex(recordList list,int index,int newNumber)
{
    record *tmpRecord;
    int tmpIndex = index;

    if (index > list->size || index < 1)
       return FALSE;

    tmpRecord = list->start;

    if (index == 1)
    {
       tmpRecord->rNumber = newNumber;
       return TRUE;
    }

    index -= 1;
    while (index--)
       tmpRecord = tmpRecord->rNext;

    tmpRecord->rNumber = newNumber;
    return TRUE;
}
Fonksiyonumuz önce sıra numarası girilen kayda ulaşıyor, ardından kaydın "rNumber" isimli veri elemanına "newNumber" parametre değişkeninin değerini atıyor. Fonksiyonu başında, gönderilen sıra numarasının liste sınırlarını taşıp taşmadığı kontrol ediliyor. Taşma durumunda FALSE değerine dönülüyor. İkinci fonksiyonumuzu yazalım :

BOOL UpdateRecordByName(recordList list,char *name,int newNumber)
{
    int index = FindRecordInList(list,name);

    if (index == -1)
       return FALSE;

    return UpdateRecordByIndex(list,index+1,newNumber);
}
İkinci fonksiyonumuz önce gönderilen isme sahip bir kayıt olup olmadığını araştırmak için "FindRecordInList" isimli fonksiyonu çağırıyor. Eğer o isme sahip bir kayıt yok ise bu fonksiyon -1 değerine dönüyordu. Burada geri dönüş değerinin -1 olup olmadığı kontrol ediliyor ve -1 değerine dönülmüşse fonksiyon FALSE değerine dönüyor. Aksi durumda geri dönen sıra numarası değeri, ilk fonksiyonumuza gönderiliyor. Üçüncü fonksiyonumuzu yazalım :

void UpdateRecordByNumber(recordList list,int number,int newNumber)
{
    record *tmpRecord = list->start;

    while (tmpRecord->rNext)
    {
       if (tmpRecord->rNumber == number)
       tmpRecord->rNumber = newNumber;
       tmpRecord = tmpRecord->rNext;
    }

    if (tmpRecord->rNumber == number)
       tmpRecord->rNumber = newNumber;

    return TRUE;
}
Üçüncü fonksiyonumuz, gönderilen not değerine sahip olan tüm kayıtları güncelliyor. Bunun için liste sırayla dolaşılıyor, her adımda sıradaki kaydın söz konusu not değerine sahip olup olmadığı kontrol ediliyor ve eğer sahip ise kaydın değeri güncelleniyor. Döngüden çıkıldığı noktada "tmpRecord" isimli göstericimiz hala son kaydı göstermektedir. Bu nedenle ikinci bir if ifadesi ile bu kaydın değeri de kontrol ediliyor.

Yazı dizimizin ikinci makalesinin de sonuna geldik. Üçüncü makalemizde listemize yeni fonksiyonlar eklemeye devam edeceğiz. Makaleye ilişkin uygulamayı indirmek için tıklayınız.

Mutlu ve huzurlu günler...

Makale:
Karakter Katarları Üzerinde İşlemler ve Bağlı Liste Uygulaması - 2 C ve Sistem Programlama Çiğdem Çavdaroğlu
  • Yazılan Yorumlar
  • Yorum Yaz
Bu konu hakkında yayınlanan yorum bulunmamaktadır.
"Yorum Yaz" tabını kullanarak sizde yorumlarınızı yazabilirsiniz.
Yorum yazabilmek için üye girişi yapmalısınız. Üye girişi için tıklayın.
Üye değilseniz Üyel Ol linkine tıklayarak üyeliğinizi hemen başlatabilirisniz.
 
  • Bu Konuda Son 10
  • Eklenen Son 10
  • Bu Konuda Geçmiş 10
Bu Konuda Yazılmış Yazılmış 10 Makale Yükleniyor
Son Eklenen 10 Makale Yükleniyor
Bu Konuda Yazılmış Geçmiş Makaleler Yükleniyor