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.