Listeler -2 (Doubly Linked List)

Samet Avcı
5 min readMar 14, 2022

--

Doubly linked listler singly linked listlerle aynı mantığa sahiptir fakat tek farkları singly linked listlerde Nodlar sadece kendisinden sonraki nodun adresini tutarken double linked listler hem kendisinden önceki hemde kendisinden sonraki nodun adresini tutarlar.

Not: Linked listlerin detaylı anlatımı serinin bir önceki yazısında mevcuttur.

Çift Yönlü Listenin Başına Eleman Ekleme

Not: Head listenin başlangıç adresini tutan bir değişkendir.

Next: Nodun kendinden sonraki nodun adresini tuttuğu yer

  • Eğer listemiz boş ise Head nodumuzu ekleyeceğimiz noda eşitliyoruz.
  • Eğer listemiz boş değil ise head nodumuzun previni ekleyeceğimiz noda ekleyeceğimiz nodun kuyruğunu ise head nodumuza eşitliyoruz.
type ListNode struct {
data int
next *ListNode
prev *ListNode
}type LinkedList struct {
Head *ListNode
len int
}
func (l *LinkedList) AddNodeToFront(data int) {
n := ListNode{}
n.data = data

if l.len == 0 {
l.Head = &n
l.len++
return
} else {

n.next = l.Head
l.Head.prev = &n
l.Head = &n
l.len++
return
}

}

Çift Yönlü Listenin Sonuna Eleman Ekleme

  • Öncelikle ilk noddan başlayarak son noda kadar gelmeliyiz.
  • Bunun için current nodu tanımlıyoruz ve kuyruğu null olana kadar kuyruğuna eşitliyoruz.
  • Sonra son nodumuzun kuyruğu (next) null değer taşıyordu.
  • Bu değeri ekleyeceğimiz nodun adresi olarak değiştireceğiz.
  • Ekleyeceğimiz nodumuzun previni de current nodumuza eşitliyoruz
func (l *LinkedList) AddNodeToBack(data int) {

if l.len == 0 {
n := ListNode{}
n.data = data
l.Head = &n
l.len++

} else {
last := ListNode{data: data}
current := l.Head
for current.next != nil {
current = current.next
}
current.next = &last
last.prev = current
l.len++
return

}

}

Çift Yönlü Listenin Ortasına Eleman Ekleme

Şimdi ise iki nodun ortasına bir node ekleyeceğiz.

  • Yeni nodumuzu dışarıdan girilen sıraya ekleyeceğiz. Yani dışarıdan girilen değer eğer 5 ise yeni nodumuz 4 ve 5. nodlarımız arasına eklenecek
  • Öncelikle head nodumuzdan başlayarak nodumuzdan bir önceki nodumuza kadar geleceğiz.
  • Buraya kadar gelmemiz için Current ve prev diye birer node tanımlıyoruz ve bu nodumuz döngü içerisinde ekleyeceğimiz nodun sırasından bir öncesine kadar getiriyoruz. Her seferinde prev nodumuz current nodumuzun bir önceki değerini tutacak.
  • Döngü istediğimiz noda geldiğinde (current=n.node olduğunda) döngüden çıkıp prev nodumuzun kuyrugunu (n) ekleyeceğimiz noda eşitliyoruz.
  • Ekleyeceğimiz nodun previni prev noduna eşitliyoruz.
  • Ekleyeceğimiz nodun kuyruğunu current noduna current nodunun previni ise ekleyeceğimiz noda eşitliyoruz.
  • Kod yapısı ise şu şekilde;
func (l *LinkedList) AddNodeToBetween(data, num int) {
n := ListNode{}

if l.len == 0 {
n.data = data
l.Head = &n
l.len++
} else {
current := l.Head
prev := current

for i := 0; i < num-1; i++ {
prev = current
current = current.next
}
n.data = data
prev.next = &n
n.prev = prev
n.next = current
current.prev = &n
l.len++
return
}
}

Çift Yönlü Listenin Başından Eleman Çıkarma

Aslında ekleme ile aynı mantıktadır.

  • Head nodumuzu head.next noduna eşitliyoruz ve listemizin boyutunu bir azaltıyoruz.
  • Head nodumuzdan sonraki nodun previni ise null değere eşitliyoruz.
func (l *LinkedList) RemoveFromFront() {
if l.len == 0 {
fmt.Println("Don't have Node")
}
l.Head = l.Head.next
l.Head.next.prev = nil
l.len--
}

Çift Yönlü Listenin Sonundan Node Çıkarma

  • Öncelikle listemizin sonundan eleman çıkartmak için current ve prev olarak iki tane node oluşturuyoruz.
  • Sonra current nodumuzu listemizin head noduna eşitliyoruz.
  • Sonra bir for döngüsünde current nodumuzun kuyruğu null değer olana kadar currenti önce prev nodumuza eşitliyoruz sonra currentin kuyruğundaki noda eşitliyoruz.
  • Döngü tamamlandığında prev nodumuz sondan bir önceki node oluyor. Prev nodumuzun kuyruğuna ve current nodumuzun previne null değerini atıyoruz. Böylelilikle son nodumuz döngüden çıkmış oluyor.
func (l *LinkedList) RemoveFromBack() {
if l.len == 0 {
fmt.Println("Don't have Node")
}
var prev *ListNode
current := l.Head
for current.next != nil {
prev = current
current = current.next
}
if prev != nil {
prev.next = nil
current.prev = nil
} else {
l.Head = nil
}
l.len--
return
}

Çift Yönlü Listenin Tüm Elemanlarını Çıkarma

  • Tüm elemanları çıkartmak için current ve prev olmak üzere iki tane node tanımlıyoruz.
  • Sonra current nodumuza listemizin ilk elemanına eşitliyoruz.
  • Daha sonra current nodumuzun kuyruğu null olana kadar dönecek bir for döngüsü oluşturuyoruz.
  • Döngüde current nodumuzun previni null değere eşitliyoruz
  • Sonra döngümüzde prev nodumuzu current nodumuza eşitliyoruz. Ardından current nodumuzu da kuyruğuna eşitliyoruz. Prev nodumuzun kuyruğunuda null olarak eşitliyoruz.
  • Döngüden çıkınca Head nodumuzu da null değere eşitliyoruz.
  • Böylelikle döngü sonunda baştan itibaren tüm nodlar dongüden çıkartılmış oluyor.
func (l *LinkedList) RemoveAll() {
if l.Head == nil {
fmt.Println("List is Empty")
}
var prev *ListNode
current := l.Head
for current.next != nil {
current.prev = nil
prev = current
current = current.next
prev.next = nil
}
l.Head = nil
l.len = 0
return
}

Çift Yönlü Listenin Tüm Elemanlarını Gösterme

  • Yine bir tane current nodu oluşturup bunu listemizin head döğümüne eşitliyoruz.
  • Sonra bu nodun datasını ekrana yazdırıyoruz ve for döngüsünde current boş olana kadar kuyruğundaki noda eşitliyoruz.
  • Bu kadar şimdi kodu gösterelim
func (l *LinkedList) ListOfAll() {
if l.Head == nil {
fmt.Println("List is Empty")
}
current := l.Head
for current != nil {
fmt.Println(current.data)
current = current.next
}
}

Çift Yönlü Listede Arama

  • Bir tane current nodu ve count tanımlıyoruz.
  • Bu current nodumuzu listenin head noduna eşitliyoruz.
  • Daha sonra listedeki eleman sayısı kadar dönecek bir for yapısı oluşturuyoruz.
  • Bu for yapımızda bir if ile current nodumuzdaki data aldığımız dataya eşitse count ile datamızın listede kaçıncı sırada olduğunu yazıyoruz.
  • Eşit değilse current nodumuzu kuyruğuna eşitleyip count değerini bir artırıyoruz.
  • Eğer aranan veri listede yoksa for döngüsünden çıktıktan sonra verini listemizde olmadığını belirtiyoruz.
func (l *LinkedList) SearchInList(data int) {   if l.Head == nil {
fmt.Println("List is empty")
} else {
count := 1
current := l.Head

for i := 1; i < l.len; i++ {

if current.data == data {
fmt.Printf("Your Data %d your data count : %d", current.data, count)
fmt.Println()
break
}
current = current.next
count++
}

if current.data != data {
fmt.Printf("%d not found in list", data)
fmt.Println()
}
}
return
}

Tek Yönlü Dairesel Liste

Tek yönlü listeden tek farkı son nodun kuyruğu ilk elemanı gösterir.

Çift Yönlü Dairesel Liste

Bu listelerde ise ilk nodun previ son nodu, son nodun kuyruğu ilk nodu gösterir.

Kaynakça:

Prof. Dr. Erkan Tanyıldızı Ders Notları

https://www.geeksforgeeks.org/linked-list-set-3-deleting-node/

https://dev.to/divshekhar/golang-linked-list-data-structure-h20#:~:text=What%20is%20a%20Linked%20List,uses%20arrays%20under%20the%20hood.

--

--

Samet Avcı

Software developer in building next-generation web applications backend with Golang.I am eager to learn and use new generation software technologies.