์ค์ํํธ๋ก ๊ตฌํํ๋ ์๋ฃ๊ตฌ์กฐ 4: ๋๋ธ ๋งํฌ๋ ๋ฆฌ์คํธ(Doubly Linked List)
๋๋ธ ๋งํฌ๋ ๋ฆฌ์คํธ(Doubly Linked List)

๋๋ธ ๋งํฌ๋ ๋ฆฌ์คํธ๋ ๋งํฌ๋ ๋ฆฌ์คํธ์ ๊ฐ๋ ์ ๊ฐ์ง๋ง ๊ฐ ๋ ธ๋๊ฐ ์์ ์ ์ด์ ๋ ธ๋๊น์ง ์๊ณ ์๋ค๋ ์ ์์ ๋ค๋ฆ ๋๋ค. ๊ธฐ์กด ๋งํฌ๋ ๋ฆฌ์คํธ๋ ๊ฐ ๋ ธ๋๊ฐ ๋ฐ๋ก ๋ค์ ๋ ธ๋์ ์ฐธ์กฐ ๊ฐ๋ง ์๊ณ ์์ง๋ง, ์ด๋ฒ์๋ ์์ ์ ์์ชฝ์ ๋ ธ๋๋ฅผ ๋ชจ๋ ์ฐธ์กฐํ๊ธฐ ๋๋ฌธ์ ์ญ์ ๋ ์ฝ์ ์ฐ์ฐ์ ๊ตฌํ์ด ์กฐ๊ธ ๋ ์ฌ์์ง๋๋ค.
๋ผ๋ ๋ง๋ค๊ธฐ
Node
import Foundation class Node<T: Equatable> { let id: Int let data: T var next: Node? = nil var prev: Node? = nil init(id: Int, data: T) { self.id = id self.data = data } }
๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ณ ๋ฆฌ์คํธ๋ฅผ ๊ตฌ์ฑํ ๋ ธ๋๋ ๊ฐ์ ์์ ์ id, ์ ์ฅํ ๋ฐ์ดํฐ, ์ด์ ๋ ธ๋์ ๋ํ ์ฐธ์กฐ๊ฐ๊ณผ ๋ค์ ๋ ธ๋์ ๋ํ ์ฐธ์กฐ๊ฐ์ ๊ฐ์ง๋๋ค.
Doubly Linked List
struct DoublyLinkedList<T: Equatable> { var head: Node<T>? var tail: Node<T>? var front: Node<T>? { return head } var back: Node<T>? { return tail } func showAll() { var now = head print("===== Linked List ======") while now != nil { now?.next == nil ? print("id: \(now!.id) | data: \(now!.data)") : print("id: \(now!.id) | data: \(now!.data) -> ") now = now?.next } print("========================") } }
๋งํฌ๋ ๋ฆฌ์คํธ๋ head ์ tail ํ๋กํผํฐ๋ฅผ ๊ฐ์ง๋๋ค. head ๋ ํ์ฌ ๋งํฌ๋ ๋ฆฌ์คํธ์์ ๊ฐ์ฅ ์์ ์๋ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํค๊ณ , tail์ ๊ฐ์ฅ ๋ค์ ์๋ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํต๋๋ค.
front, back ์ head์ tail ํ๋กํผํฐ๋ฅผ ํตํด์ ๊ฐ์ฅ ์ ๋ ธ๋์ ๋ง์ง๋ง ๋ ธ๋์ ์ฐธ์กฐ ๊ฐ์ ๋ฐํํ๊ณ , ๋งํฌ๋ ๋ฆฌ์คํธ์ ๋ ธ๋ ๋ชฉ๋ก์ ์์๋๋ก ํ์ธํ ์ ์๋ showAll ๋ฉ์๋๋ฅผ ๊ตฌํํ์ต๋๋ค.
์ถ๊ฐ (add) - O(1)
์๋ก์ด ๋ ธ๋๋ฅผ ๋ฆฌ์คํธ ๊ฐ์ฅ ๋์ ์ถ๊ฐํ๋ ์ฐ์ฐ์ tail ํฌ์ธํฐ๋ฅผ ์ด์ฉํด์ O(1)์ ์ํํ ์ ์์ต๋๋ค. ๋ ๊ฐ์ง ๊ฒฝ์ฐ๊ฐ ์์ ์ ์๋๋ฐ์,
1) ๋งํฌ๋ ๋ฆฌ์คํธ์ ์๋ฌด ๋ ธ๋๋ ์๋ ๊ฒฝ์ฐ

์ด ๊ฒฝ์ฐ์๋ ์๋ก์ด ๋ ธ๋๋ฅผ head์ tail์ด ๊ฐ๋ฆฌํค๊ฒ ํ๋ ๊ฒ์ผ๋ก ์ฝ๊ฒ ๋ ธ๋๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค.
2) ๋งํฌ๋ ๋ฆฌ์คํธ์ ๋ ธ๋๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ

์ด๋ฏธ ๋ฆฌ์คํธ์ ๋ ธ๋๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ์๋ tail์ด ๊ฐ๋ฆฌํค๋ ๋ค์ ๋ ธ๋๋ฅผ ์๋ก์ด ๋ ธ๋๋ก ์ง์ ํ๊ณ , ์๋ก์ด ๋ ธ๋์ ์ด์ ๋ ธ๋๋ฅผ tail์ด ๊ฐ๋ฆฌํค๋ ๋ ธ๋๋ก ์ง์ ํฉ๋๋ค.

๊ทธ๋ฆฌ๊ณ ์ด์ ๋ง์ง๋ง ๋ ธ๋๊ฐ ๋ณ๊ฒฝ๋์๊ธฐ ๋๋ฌธ์ tail๋ ํ ์นธ ์ค๋ฅธ์ชฝ์ผ๋ก ์ด๋์์ผ์ค๋๋ค.
์ด๋ค ๊ฒฝ์ฐ๋ ์ง tail์ ์ฌ์ฉํด ๋ง์ง๋ง ๋ ธ๋๋ฅผ ๋ฐ๋ก ์ฐธ์กฐํ ์ ์๊ธฐ ๋๋ฌธ์ ํญ์ O(1)์ด ๋ณด์ฅ๋ฉ๋๋ค. ์ ๋ก์ง์ ๊ตฌํํ๋ฉด ์ด๋ ๊ฒ ๋๊ฒ ์ฃ !
mutating func add(node: Node<T>) { if self.head == nil { self.head = node self.tail = node return } self.tail?.next = node node.prev = self.tail self.tail = node }
ํ์ (search) - O(N)
ํน์ ํ ๋ ธ๋๋ฅผ ํ์ํ๊ธฐ ์ํด์๋ ๋ฆฌ์คํธ์ ์ฒซ ๋ ธ๋์ธ head๋ถํฐ ๋ง์ง๋ง ๋ ธ๋์ธ tail ๊น์ง ๋ชจ๋ ๋ ธ๋๋ฅผ ๊ฒ์ฌํด๋ณด์์ผ ์ํ๋ ๋ ธ๋๋ฅผ ํ์ํ ์ ์์ต๋๋ค. ์ด๋ฅผ ์ํด์ ํ์ฌ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํค๋ ์ปค์์ธ now ํฌ์ธํฐ๋ฅผ ์ฌ์ฉํ๋ฉด ๋ค์ ๋ ธ๋๋ก ๊ณ์ ์ด๋ํ ์ ์์ต๋๋ค.

now ๋ฅผ ์ด๋์ํค๋ ค๋ฉด ์ฌ๊ท์ ์ผ๋ก, ํน์ ๋ฐ๋ณต๋ฌธ์ ํตํด์ ํ์ฌ ๋ ธ๋์ ๋ค์ ๋ ธ๋๋ฅผ now๋ก ๋ณ๊ฒฝํด์ฃผ๋ฉด ๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ ์๋ก์ด now ๊ฐ ๊ฐ๋ฆฌํค๋ ๋ ธ๋๊ฐ ์ํ๋ ๋ ธ๋๋ผ๋ฉด ํด๋น ๋ ธ๋๋ฅผ ๊ทธ๋๋ก ๋ฐํํด์ฃผ๋ฉด ๋๊ฒ ์ฃ . ํ์์ ์ต์ ์ ๊ฒฝ์ฐ์๋ ์ ์ฒด ๋ ธ๋๋ฅผ ๋ค ๋์๋ด์ผ ํ๊ธฐ ๋๋ฌธ์ O(N)์ ์๊ฐ๋ณต์ก๋๊ฐ ์๊ตฌ๋๊ณ , ์ด์ค์ผ๋ก ์ฐ๊ฒฐ๋ ๋ฆฌ์คํธ๊ฐ ๊ทธ๋ค์ง ๋์์ด ๋์ง๋ ์์ต๋๋ค.
mutating func searchNode(with data: T) -> Node<T>? { var now = self.head while now?.data != data && now !== tail { now = now?.next } return now }
์ฝ์ (insert) - O(1) or O(N)
์ด์ค์ผ๋ก ์ฐ๊ฒฐ๋ ๋๋ถ์ ์ฝ์ ์ด ์กฐ๊ธ ๋ ์ฌ์์ก์ต๋๋ค. ์ฝ์ ์ฐ์ฐ์ ๊ฒฝ์ฐ์ ๋ฐ๋ผ์ O(1)์ ๋๋ ์๋ ์๊ณ , O(N)์ด ๊ฑธ๋ฆด ์๋ ์์ต๋๋ค.
1) ์ฝ์ ํ ์์น๊ฐ head๋ tail์ผ ๋ - O(1)
์๋ก์ด ๋ ธ๋๋ฅผ ์ฝ์ ํ ์์น๊ฐ head ๋ tail์ ์๋ค๋ผ๋ฉด ๋ณ๋์ ํ์๊ณผ์ ์์ด ๊ณง๋ฐ๋ก ์ฝ์ ์ด ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ์๊ฐ๋ณต์ก๋๊ฐ O(1)์ด ๋ฉ๋๋ค.

4๋ฒ๊ณผ 5๋ฒ ๋ ธ๋ ์ฌ์ด์ ์ ๋ ธ๋๋ฅผ ๋ผ์ ๋ฃ๊ณ ์ถ๋ค๊ณ ํด๋ณด๊ฒ ์ต๋๋ค.

์ฐ๋ฆฌ๋ ๋ง์ง๋ง ๋ ธ๋๊ฐ tail์ด๋ผ๋ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ tail์ ์ด์ ๋ ธ๋๋ฅผ ์ฐธ์กฐํด ๊ทธ ๋ค์ ๋ ธ๋๋ฅผ ์๋ก์ด ๋ ธ๋๋ก ์ง์ ํ๊ณ ,

์๋ก์ด ๋ ธ๋์ ์ด์ ๋ ธ๋๋ฅผ tail์ ์ด์ ๋ ธ๋๋ก ์ง์ ํฉ๋๋ค.

์ด์ ์ด์ ๋ ธ๋์ ์ ๋ ธ๋์ ์ฐ๊ฒฐ์ ๋๋ฌ์ผ๋ ๋ง์ง๋ง ๋ ธ๋์ธ tail์ ์ด์ ๋ ธ๋๋ฅผ ์ ๋ ธ๋๋ก, ์ ๋ ธ๋์ ๋ค์ ๋ ธ๋๋ฅผ tail๋ก ์ง์ ํด์ฃผ๋ฉด ์๋ก์ด ๋ ธ๋์ ์ฝ์ ์ด ์์ฑ๋ฉ๋๋ค.
2) ์ฝ์ ํ ์์น๊ฐ head๋ tail์ด ์๋ ๋ - O(N)
์ฝ์ ํ ์์น๊ฐ head๋ tail์ด ์๋๋ผ๋ฉด ํด๋น ์์น๋ฅผ ํ์์ ํตํด ์ฐพ์์ฃผ์ด์ผ ํฉ๋๋ค. ๋๋ฌธ์ ์์น๋ฅผ ํ์ํ๋ ์๊ฐ O(N)๊ณผ 1๋ฒ ์ฒ๋ผ ์ค์ ์ฝ์ ์ ์งํํ๋ ๊ณผ์ O(1) ์ด ์๊ตฌ๋์ด์ ์๊ฐ ๋ณต์ก๋๋ O(N)์ด ๋ฉ๋๋ค. ํ์ + ์ฝ์ ์ด ์ค์ ๋ก ์๊ตฌ๋๋ ๊ฒ์ด์ฃ .
mutating func insert(node: Node<T>, after id: Int) { guard head != nil else { return } var now = self.head if id == self.tail!.id { self.add(node: node) } while now?.id != id && now != nil { now = now?.next } if now === self.tail { self.tail = node } node.next = now?.next now?.next?.prev = node now?.next = node node.prev = now } mutating func insert(node: Node<T>, before id: Int) { guard head != nil else { return } var now = self.head if id == self.tail?.id { now = self.tail } else { while now?.id != id && now != nil { now = now?.next } } if now === self.head { self.head = node } now?.prev?.next = node node.prev = now?.prev now?.prev = node node.next = now }
์ญ์ (delete) - O(1) or O(N)
์ญ์ ์ฐ์ฐ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฝ์ ๊ณผ ๋์ผํ๊ฒ ํน์ ํ ๋ ธ๋๊น์ง์ ํ์์ด ํ์ํ๊ณ ์ดํ์ ์ญ์ ๊ฐ ์งํ๋ฉ๋๋ค. ๋ฐ๋ผ์ ์ญ์ ํ ๋ ธ๋๊ฐ head๋ tail์ผ ๊ฒฝ์ฐ๋ ํ์์ด ํ์์์ผ๋ O(1)์ด ๋๊ณ , ๊ทธ ์ธ์ ๋ ธ๋๋ค์ O(N)์ด ๋ฉ๋๋ค.
์ญ์ ํ๋ ๊ณผ์ ์ ์๋์ ๊ฐ์ต๋๋ค.

3๋ฒ ๋ ธ๋๋ฅผ ์ญ์ ํ๋ค๊ณ ํด๋ณผ๊ฒ์!

์ญ์ ํ ๋ ธ๋์ ๋ค์ ๋ ธ๋๊ฐ ์ญ์ ํ ๋ ธ๋์ ์ด์ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํค๊ฒ ํฉ๋๋ค.

๊ทธ๋ฆฌ๊ณ ์ญ์ ํ ๋ ธ๋์ ์ด์ ๋ ธ๋๊ฐ ์ญ์ ํ ๋ ธ๋์ ๋ค์ ๋ ธ๋๋ฅผ ๊ฐ๋ฆฌํค๊ฒ ํฉ๋๋ค. ๊ทธ๋ฆผ์์ ๋ณผ ์ ์๋ฏ์ด ์ด์ 3๋ฒ ๋ ธ๋๋ now ํฌ์ธํฐ์ ์ํด์๋ง ์ฐธ์กฐ๊ฐ ๋๋๋ฐ์, now ํฌ์ธํฐ๋ ์ญ์ ํจ์๊ฐ ์ข ๋ฃ๋๋ฉด ํจ๊ป ์ฌ๋ผ์ง๋ ๋ณ์์ด๊ธฐ ๋๋ฌธ์ ARC์ ์ํด ํจ์๊ฐ ์ข ๋ฃ๋๋ฉด์ 3๋ฒ ๋ ธ๋๋ ์ฌ๋ผ์ง๊ฒ ๋ฉ๋๋ค.

์ ๊ณผ์ ์ ๊ตฌํํ๋ฉด ์ด๋ ๊ฒ ๋๊ฒ ์ฃ ?
mutating func deleteNode(with id: Int) -> Node<T>? { var now = self.head if id == self.tail?.id { now = self.tail } else { while now?.id != id && now != nil { now = now?.next } } let deleted = now deleted?.next?.prev = deleted?.prev deleted?.prev?.next = deleted?.next if deleted === head { self.head = deleted?.next } if deleted === tail { self.tail = deleted?.prev } return deleted }
๋ฆฌ์คํธ ๋ค์ง๊ธฐ - O(N)
๋ง์ง๋ง์ผ๋ก ์ผ๋ฐ ๋งํฌ๋ ๋ฆฌ์คํธ์์๋ ํ ์ ์๊ณ ๋๋ธ ๋งํฌ๋ ๋ฆฌ์คํธ์์๋ง ํ ์ ์๋ ๋ฐ์ ์ฐ์ฐ์ ์๊ฐํ๊ณ ๋ง์น๋ ค๊ณ ํฉ๋๋ค! ๊ฐ ๋ ธ๋๋ค์ ์์ ์ ์ด์ ๊ณผ ๋ค์ ๋ ธ๋ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ ์ด์ ์ ๋ค์์ผ๋ก, ๋ค์์ผ๋ก ์ด์ ์ผ๋ก ๋ณ๊ฒฝํด์ฃผ๋ฉด ๋ฉ๋๋ค.

์ด๋ ๊ฒ ์๋ ๋ฆฌ์คํธ๋ฅผ next์ prev๋ฅผ ๋ฐ์ ์์ผ์ ๋ค์ง์ผ๋ฉด,

์ด๋ ๊ฒ ๋๊ฒ ์ฃ ? ํ์ง๋ง ์์ง head ์ tail์ ์ด์ ์ํ์ ์๋์ ๊ฐ๋ฆฌํค๊ณ ์๊ธฐ ๋๋ฌธ์ ์ด๋๋ก ์ถ๋ ฅ์ ํ๋ฉด 1๋ฒ ๋ ธ๋๋ฅผ ์ถ๋ ฅํ ์ดํ์ ๊ณง๋ฐ๋ก nil์ด ๋ฐํ๋ฉ๋๋ค. head ์ tail๋ ๊ตํํด์ค์๋ค!

์ด์ ์๋ฒฝํ๊ฒ ๋ค์ง์ด์ง ๋งํฌ๋ ๋ฆฌ์คํธ๊ฐ ๋์์ต๋๋ค!
์ ๊ณผ์ ์ ๋ํ ๊ตฌํ์ ์ด๋ ์ต๋๋ค.
mutating func reverse() { var now = head while now != nil { let nowNext = now?.next now?.next = now?.prev now?.prev = nowNext now = now?.prev } let nowHead = self.head self.head = self.tail self.tail = nowHead }
์ ์ฒด ์ฝ๋
// | |
// DoublyLinkedList.swift | |
// DoublyLinkedList | |
// | |
// Created by ์ ์ฌํ on 2021/12/11. | |
// | |
import Foundation | |
struct DoublyLinkedList<T: Equatable> { | |
var head: Node<T>? | |
var tail: Node<T>? | |
var front: Node<T>? { | |
return head | |
} | |
var back: Node<T>? { | |
return tail | |
} | |
mutating func add(node: Node<T>) { | |
if self.head == nil { | |
self.head = node | |
self.tail = node | |
return | |
} | |
self.tail?.next = node | |
node.prev = self.tail | |
self.tail = node | |
} | |
mutating func searchNode(with data: T) -> Node<T>? { | |
var now = self.head | |
while now?.data != data && now !== tail { | |
now = now?.next | |
} | |
return now | |
} | |
mutating func deleteNode(with id: Int) -> Node<T>? { | |
var now = self.head | |
if id == self.tail?.id { | |
now = self.tail | |
} else { | |
while now?.id != id && now != nil { | |
now = now?.next | |
} | |
} | |
let deleted = now | |
deleted?.next?.prev = deleted?.prev | |
deleted?.prev?.next = deleted?.next | |
if deleted === head { | |
self.head = deleted?.next | |
} | |
if deleted === tail { | |
self.tail = deleted?.prev | |
} | |
return deleted | |
} | |
mutating func insert(node: Node<T>, after id: Int) { | |
guard head != nil else { return } | |
var now = self.head | |
if id == self.tail!.id { | |
self.add(node: node) | |
} | |
while now?.id != id && now != nil { | |
now = now?.next | |
} | |
if now === self.tail { | |
self.tail = node | |
} | |
node.next = now?.next | |
now?.next?.prev = node | |
now?.next = node | |
node.prev = now | |
} | |
mutating func insert(node: Node<T>, before id: Int) { | |
guard head != nil else { return } | |
var now = self.head | |
if id == self.tail?.id { | |
now = self.tail | |
} else { | |
while now?.id != id && now != nil { | |
now = now?.next | |
} | |
} | |
if now === self.head { | |
self.head = node | |
} | |
now?.prev?.next = node | |
node.prev = now?.prev | |
now?.prev = node | |
node.next = now | |
} | |
mutating func reverse() { | |
var now = head | |
while now != nil { | |
let nowNext = now?.next | |
now?.next = now?.prev | |
now?.prev = nowNext | |
now = now?.prev | |
} | |
let nowHead = self.head | |
self.head = self.tail | |
self.tail = nowHead | |
} | |
func showAll() { | |
var now = head | |
print("===== Linked List ======") | |
while now != nil { | |
now?.next == nil | |
? print("id: \(now!.id) | data: \(now!.data)") | |
: print("id: \(now!.id) | data: \(now!.data) -> ") | |
now = now?.next | |
} | |
print("========================") | |
} | |
} |
GitHub - jeonyeohun/Data-Structures-In-Swift: ๐ท๐ปโโ๏ธ STL ์ ์์ด.. ์ค์ํํธ๋ก ๊ตฌํํ๋ ์๋ฃ๊ตฌ์กฐ
๐ท๐ปโโ๏ธ STL ์ ์์ด.. ์ค์ํํธ๋ก ๊ตฌํํ๋ ์๋ฃ๊ตฌ์กฐ. Contribute to jeonyeohun/Data-Structures-In-Swift development by creating an account on GitHub.
github.com
์๋ฃ๊ตฌ์กฐ ์๋ฆฌ์ฆ์ ์ฝ๋๋ค์ ์ด ๋ ํฌ์์ ๋ชจ๋ ํ์ธํ ์ ์์ด์!
'๐ฎ ์จ-์์ค > ๐ฆด ์๋ฃ๊ตฌ์กฐ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
๋๊ธ
์ด ๊ธ ๊ณต์ ํ๊ธฐ
-
๊ตฌ๋
ํ๊ธฐ
๊ตฌ๋ ํ๊ธฐ
-
์นด์นด์คํก
์นด์นด์คํก
-
๋ผ์ธ
๋ผ์ธ
-
ํธ์ํฐ
ํธ์ํฐ
-
Facebook
Facebook
-
์นด์นด์ค์คํ ๋ฆฌ
์นด์นด์ค์คํ ๋ฆฌ
-
๋ฐด๋
๋ฐด๋
-
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
๋ค์ด๋ฒ ๋ธ๋ก๊ทธ
-
Pocket
Pocket
-
Evernote
Evernote
๋๊ธ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.