6 - Bağlı Liste İşlemleri
2025
Geçen hafta bağlı listelerin ne olduğunu, türlerini ve temel yapısını öğrendik. Bu hafta, bağlı listeler üzerinde gerçekleştirebileceğimiz temel işlemleri inceleyeceğiz:
Bu işlemler, tek yönlü bağlı listeler üzerinde gösterilecek, ancak temel prensipler diğer türler için de geçerlidir.
head, bağlı listenin ilk düğümüne işaret eder.next, son düğümün işaret ettiği adres NULL’dur, bu nedenle bir sonraki geçerli düğüm NULL ise, bağlı listenin sonuna ulaşmış oluruz.Tüm örneklerde, bağlı listenin aşağıdaki gibi düğüm yapısına sahip üç düğüm 1 ---> 2 ---> 3 olduğunu varsayacağız:
head’den başlayarak, her düğümün next işaretçisini takip ederek son düğüme (NULL işaretçisine sahip olan) kadar ilerleriz.void printList(struct node *head) {
struct node *temp = head;
printf("Liste: ");
while (temp != NULL) {
printf("%d -> ", temp->data);
temp = temp->next;
}
printf("NULL\n");
}Yeni bir düğüm oluşturulur ve listenin başına eklenir. head işaretçisi güncellenir.
data alanına veriyi ata.next işaretçisini, mevcut head’i gösterecek şekilde ayarla.head işaretçisini yeni düğümü gösterecek şekilde güncelle.void insertAtBeginning(struct node **headRef, int newData) {
// 1. Yeni düğüm için bellek ayır
struct node *newNode = malloc(sizeof(struct node));
// 2. Veriyi ata
newNode->data = newData;
// 3. Yeni düğümün next'i eski head olsun
newNode->next = *headRef;
// 4. head'i yeni düğüme güncelle
*headRef = newNode;
}head değişkeninin kendisini değiştirebilmek için, head’in adresini fonksiyona geçirmemiz gerekiyor. İşte bu yüzden struct node **headRef kullanıyoruz. headRef, head işaretçisinin adresini tutan bir işaretçi (pointer to a pointer).
headRef: head’in adresini tutan değişken.*headRef: headRef’in gösterdiği adresteki değer, yani head’in kendisi.**headRef: *headRef in değeri olan head’ın gösterdiği değeri ifade eder.Fonksiyon içinde *headRef = newNode; yaptığımızda, aslında şunu demiş oluyoruz: “headRef’in gösterdiği adrese (yani head’in kendisine) newNode’un adresini ata.” Bu sayede, main fonksiyonundaki orijinal head değişkeni de güncellenmiş oluyor.
Yeni bir düğüm oluşturulur ve listenin sonuna eklenir.
data alanına veriyi ata.next işaretçisini NULL yap (çünkü son düğüm olacak).head NULL ise), head’i yeni düğüm yap ve fonksiyondan çık.next’i NULL olan düğüm).next işaretçisini yeni düğümü gösterecek şekilde ayarla.void insertAtEnd(struct node **headRef, int newData) {
struct node *newNode = malloc(sizeof(struct node));
newNode->data = newData;
newNode->next = NULL;
if (*headRef == NULL) { // Liste boşsa
*headRef = newNode;
return;
}
struct node *last = *headRef;
while (last->next != NULL) {
last = last->next;
}
last->next = newNode;
}Yeni bir düğüm, listede belirli bir konumdan sonraya eklenir.
data alanına veriyi ata.prevNode diyelim).prevNode NULL ise, bu konuma ekleme yapılamaz (hata mesajı verilebilir veya başa ekleme yapılabilir), fonksiyondan çık.next işaretçisini, prevNode’un next’ini gösterecek şekilde ayarla.prevNode’un next işaretçisini yeni düğümü gösterecek şekilde ayarla.Listenin başındaki düğüm silinir. head işaretçisi güncellenir.
head NULL ise), yapılacak bir şey yok, fonksiyondan çık.head’i geçici bir değişkende sakla (temp).head’i, head’in next’ine eşitle (yani bir sonraki düğüme).temp’i serbest bırak (free).Listenin sonundaki düğüm silinir.
head->next NULL ise), head’i NULL yap, düğümü serbest bırak ve fonksiyondan çık.secondLast).secondLast->next) geçici bir değişkende sakla (temp).secondLast->next’i NULL yap.temp’i serbest bırak.void deleteFromEnd(struct node **headRef) {
if (*headRef == NULL) {
return; // Liste boş
}
if ((*headRef)->next == NULL) { // Tek eleman
free(*headRef);
*headRef = NULL;
return;
}
struct node *secondLast = *headRef;
while (secondLast->next->next != NULL) {
secondLast = secondLast->next;
}
struct node *temp = secondLast->next;
secondLast->next = NULL;
free(temp);
}Belirli bir düğüm (ne baş ne de son) listeden silinir.
prevNode).prevNode veya prevNode->next NULL ise, silme yapılamaz (hata mesajı ver), fonksiyondan çık.prevNode->next) geçici bir değişkende sakla (temp).prevNode->next’i, temp->next’e eşitle (yani silinecek düğümü atla).temp’i serbest bırak.void deleteNode(struct node **headRef, struct node *prevNode)
{
if(prevNode == NULL || prevNode->next == NULL)
{
printf("Silinecek elemanın öncesi veya silinecek eleman yok.\n");
return;
}
struct node *temp = prevNode->next; //Silinecek eleman
prevNode->next = temp->next; //Önceki elemanın next'i, silinecek elemanın next'i yapılıyor.
free(temp); //Silinecek eleman siliniyor.
}Önce two’yu bulup, sonra silmek için one’ı (önceki düğüm) parametre olarak vermeliyiz.
Belirli bir veriyi içeren düğümü bulma işlemidir.
head’den başla.data’yı aranan veriyle (key) karşılaştır.NULL) ve eşleşme bulunamazsa, NULL döndür.