Bağlı Liste (Linked List)

Elemanları işaretçilerle birbirine bağlı düğümler olarak saklayan veri yapısı.

#Nasıl çalışır?

Bağlı liste (linked list), elemanları bellekte yan yana değil, birbirine işaretçilerle (pointer) bağlı düğümler (node) olarak saklar. Her düğüm bir değer ve bir sonraki düğümün adresini (next) tutar.

Listenin ilk düğümünü head gösterir, son düğümün next işaretçisi ise null'dır. Bir elemana ulaşmak için head'den başlayıp next işaretçilerini tek tek takip etmek gerekir.

Diziden en büyük farkı şudur: araya eleman eklemek ya da silmek için diğer elemanları kaydırmak gerekmez, yalnızca birkaç işaretçi değişir. Buna karşılık i'inci elemana doğrudan atlanamaz.

#Kendin dene

$ linked_list --interactive

Bir değer yazıp başa, sona ya da belirli bir sıraya ekle; silme ve aramada düğümlerin tek tek gezildiğini izle.

Eleman: 4/8GeziliyorYeniÇıkarılıyorBulundu / okunan

#Temel işlemler

insertHead(x)
Yeni düğümü başa ekler: yeni düğüm eski head'i gösterir, head yeni düğüm olur.
insertTail(x)
Son düğüme kadar gidip yeni düğümü sona bağlar. Bir tail işaretçisi tutulursa O(1) olur.
insertAt(i, x)
i - 1'inci düğüme kadar gider, yeni düğümü araya bağlar.
remove(x)
x değerli düğümü bulur; önceki düğümün next işaretçisini bir sonrakine bağlayarak onu listeden çıkarır.
search(x)
head'den başlayıp düğümleri tek tek kontrol eder.

#Örnek kod

Aynı algoritma 8 dilde. Her program derlenip çalıştırılarak test edildi ve hepsi aynı çıktıyı veriyor.

from __future__ import annotations

from dataclasses import dataclass


@dataclass
class Node:
    value: int
    next: Node | None = None


class LinkedList:
    def __init__(self) -> None:
        self.head: Node | None = None

    def push_front(self, value: int) -> None:
        # O(1): the new node simply points at the old head.
        self.head = Node(value, self.head)

    def push_back(self, value: int) -> None:
        # O(n): walk to the last node (a tail pointer would make this O(1)).
        node = Node(value)
        if self.head is None:
            self.head = node
            return
        cur = self.head
        while cur.next is not None:
            cur = cur.next
        cur.next = node

    def index_of(self, value: int) -> int:
        cur, i = self.head, 0
        while cur is not None:
            if cur.value == value:
                return i
            cur, i = cur.next, i + 1
        return -1

    def remove(self, value: int) -> None:
        # Unlinks the first node with this value: the previous node skips over it.
        if self.head is None:
            return
        if self.head.value == value:
            self.head = self.head.next
            return
        prev = self.head
        while prev.next is not None and prev.next.value != value:
            prev = prev.next
        if prev.next is not None:
            prev.next = prev.next.next

    def __str__(self) -> str:
        values, cur = [], self.head
        while cur is not None:
            values.append(str(cur.value))
            cur = cur.next
        return " ".join(values)


items = LinkedList()
items.push_front(2)
items.push_front(1)
items.push_back(3)
print(items)               # 1 2 3
print(items.index_of(2))   # 1
items.remove(2)
print(items)               # 1 3

#Karmaşıklık

İşlemSüre
Başa ekleme / baştan silmeO(1)
Sona ekleme (tail işaretçisiyle)O(1)
Sona ekleme (tail olmadan)O(n)
i'inci elemana erişimO(n)
AramaO(n)
Bilinen bir düğümden sonra ekleme/silmeO(1)

Bağlı listenin gücü ekleme ve silmede: doğru düğüme ulaşıldıktan sonra yalnızca işaretçiler değişir. Zayıf yanı erişim: dizide a[i] O(1) iken bağlı listede i düğüm gezmek gerekir. Ayrıca düğümler bellekte dağınık durduğu için önbellek (cache) kullanımı diziden kötüdür.

#Ne zaman kullanılır?

Başa ya da ortaya sık ekleme/silme yapılan ve rastgele erişimin gerekmediği durumlarda kullanılır: LRU önbellekleri (çift yönlü bağlı liste + hash tablosu), işletim sistemindeki boş bellek listeleri, yığın ve kuyruk gerçeklemeleri. Çoğu günlük işte dinamik diziler (ArrayList, Python list) daha hızlıdır.

#Alıştırma

Soruları cevaplamak ve ilerlemeni kaydetmek için giriş yap.

Kolay

1/3

Tekli bağlı listede her düğüm ne tutar?

  • 1Bir değer ve sonraki düğümün adresi
  • 2Yalnızca bir değer
  • 3Bir değer ve indeksi
  • 4Tüm listenin uzunluğu

Orta

1/1

head → 4 → 7 → 2 → null listesinde 7 silinirse hangi işaretçi değişir?

  • 14'ün next işaretçisi 2'yi gösterir
  • 2head 7'yi gösterir
  • 32'nin next işaretçisi 4'ü gösterir
  • 4Hiçbiri, elemanlar kaydırılır

Zor

1/1

Bağlı liste hangi durumda diziden daha uygun bir seçimdir?

  • 1Ortaya ve başa sık ekleme/silme yapılıp rastgele erişim gerekmediğinde
  • 2Elemanlara sık sık indeksle erişildiğinde
  • 3İkili arama yapılacağında
  • 4Önbellek verimliliği önemli olduğunda

#Bundan sonra

Bu dersi bildiğini varsayan dersler: