2022.10.10 (์)
ํ์ด๋?
ํ ํธ๋ฆฌ๋ ์ฌ๋ฌ ๊ฐ์ ๊ฐ ์ค์์ ๊ฐ์ฅ ํฌ๊ฑฐ๋ ์์ ๊ฐ์ ๋น ๋ฅด๊ฒ ์ฐพ๊ธฐ ์ํด ๋ง๋ ์ด์ง ํธ๋ฆฌ๋ก, ์งง๊ฒ ํ์ด๋ผ๊ณ ์ค์ฌ์ ๋ถ๋ฅด๊ธฐ๋ ํฉ๋๋ค. ํ์ ์์ ์ด์ง ํธ๋ฆฌ์ ํํ๋ฅผ ๋ ์ด์ผ ํ๊ณ , ๋ถ๋ชจ์ ๊ฐ์ ํญ์ ์์๋ค์ ๊ฐ๋ณด๋ค ํฌ๊ฑฐ๋ ์์์ผํฉ๋๋ค. ๋ฐ๋ผ์ ๋ฃจํธ ๋ ธ๋๋ ์์ ๋ ธ๋๋ณด๋ค ํญ์ ํฌ๊ฑฐ๋ ์๊ธฐ ๋๋ฌธ์ ์ต๋๊ฐ, ์ต์๊ฐ์ ํญ์ O(1) ์์ ์ฐฟ์ ์ ์์ต๋๋ค.
์ ํญ์ ์์ ์ด์งํธ๋ฆฌ์ฌ์ผ ํ๋์?
๋จ์ํ ์ต๋๊ฐ, ์ต์๊ฐ์ O(1)์์ ์ฐพ๊ธฐ ์ํด, "ํญ์ ์์ ์ด์ง ํธ๋ฆฌ ํํ"์ผ ํ์๋ ์์ต๋๋ค. ์์ ์ด์ง ํธ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ์ด์ ๋ ์ฝ์ ํ๊ฑฐ๋ ์ญ์ ํ ๋์ ์๋๋๋ฌธ์ ๋๋ค.
์๊ฐ ๋ณต์ก๋
๋ฐ์ดํฐ์ ์ฝ์ ๊ณผ ์ญ์ ์ ์๊ฐ๋ณต์ก๋๋ ๋ชจ๋ **O(logN)**์ ๋๋ค.
์์ ์ด์งํธ๋ฆฌ์ ์๋ฃ๊ตฌ์กฐ๋ ๋ฐฐ์ด์ด ๋ฉ๋๋ค. ๋ฐ๋ผ์ ๋ฐฐ์ด์ index๋ฅผ ํธ๋ฆฌ๋ก ๋ํ๋ด๋ ๋ฐฉ๋ฒ์ ์์์ผ ํฉ๋๋ค. ๋ถ๋ชจ๋ ธ๋์ ๋ฒํธ๊ฐ 1์ด๋ผ๊ณ ํ ๋, ์ผ์ชฝ ์์๋ ธ๋์ ์ค๋ฅธ์ชฝ ์์ ๋ ธ๋์ Index๋ 2์ 3์ผ๋ก ์๋์ ์์ ๊ฐ์ง๋๋ค.
์ผ์ชฝ ์์ ๋
ธ๋ index = ๋ถ๋ชจ๋
ธ๋ index * 2
์ค๋ฅธ์ชฝ ์์ ๋
ธ๋ index = ๋ถ๋ชจ๋
ธ๋ index * 2 + 1
๋ถ๋ชจ ๋
ธ๋ index = (์ผ์ชฝ) ์ค๋ฅธ์ชฝ ์์ ๋
ธ๋ index / 2
๋ค๋ฅธ ์์ผ๋ก๋ ํํํ ์ ์์ต๋๋ค. (index๊ฐ 0๋ถํฐ ์์์ผ ๋)
์ผ์ชฝ ์์ ๋ ธ๋ index = ๋ถ๋ชจ๋ ธ๋ index * 2 + 1
์ค๋ฅธ์ชฝ ์์ ๋ ธ๋ index = ๋ถ๋ชจ๋ ธ๋ index * 2 + 2
๋ถ๋ชจ ๋ ธ๋ index = ((์ผ์ชฝ) ์ค๋ฅธ์ชฝ ์์ ๋ ธ๋ index - 1) / 2
๊ทธ๋ผ ๋จผ์ Heap ๊ตฌ์กฐ์ฒด๋ฅผ ๋ง๋ค๊ฒ ์ต๋๋ค.
struct Heap<T: Comparable> {
var tree: [T] = []
init(withData data: T) {
tree.append(data)
tree.append(data)
}
}
Comparable
ํ๋กํ ์ฝ์ ์ค์ํ๋ ์ด์ ๋ ๋ถ๋ชจ์ ์์๋
ธ๋์ ๊ฐ์ ๋น๊ตํ๊ธฐ ๋๋ฌธ์
๋๋ค. ๋ํ, ์ด๊ธฐํํ ๋ data๋ฅผ ๋๋ฒ ์ฝ์
ํ๋ ์ด์ ๋ ๋ฐฐ์ด์ 0๋ฒ index๋ ์ฌ์ฉํ์ง ์๊ธฐ ๋๋ฌธ์ ์๋ฌด ์๋ฏธ์๋ ๊ฐ์ ์ฑ์๋ฃ๊ธฐ ์ํจ์
๋๋ค.
0๋ถํฐ ์์ํ ๊ฒฝ์ฐ, ํ ๋ฒ๋ง ์ฝ์ ํฉ๋๋ค.
๋ฐ์ดํฐ์ ์ฝ์
๋งฅ์ค ํ์ ๊ฒฝ์ฐ๋ง ์๊ฐํด ๋ณผ ๋, ์๋์ ๊ณผ์ ์ ๋ฐ๋ฆ ๋๋ค.
- ๊ฐ์ฅ ๋์ ์๋ฆฌ์ ๋ ธ๋๋ฅผ ์ฝ์ ํ๋ค.
- ๊ทธ ๋ ธ๋์ ๋ถ๋ชจ ๋ ธ๋๋ฅผ ์๋ก ๋น๊ตํ๋ค.
- ๋ ธ๋๊ฐ ๋ถ๋ชจ ๋ ธ๋๋ณด๋ค ํฌ๋ค๋ฉด ์๋ก ๊ฐ์ ๊ตํํ๋ค.
- ๋ถ๋ชจ ๋ ธ๋๊ฐ ๊ฐ์ฅ ํด ๋๊น์ง 2~3๋ฒ ๊ณผ์ ์ ๋ฐ๋ณตํ๋ค.
mutating func insert(_ data: T) {
// ๋น์๋ค๋ฉด ์ด๊ธฐํ๊ฐ ํ์ํฉ๋๋ค.
if tree.isEmpty {
tree.append(data)
tree.append(data)
return
}
// ๊ฐ์ฅ ๋ค์ ๋
ธ๋๋ฅผ ์ฝ์
ํฉ๋๋ค
tree.append(data)
var newNodeIndex = tree.count - 1
var parentNodeIndex = newNodeIndex / 2
while tree[parentNodeIndex] < tree[newNodeIndex] {
tree.swapAt(parentNodeIndex, newNodeIndex)
newNodeIndex = parentNodeIndex
parentNodeIndex = newNodeIndex / 2
// ํ์ฌ ๋
ธ๋๊ฐ ๋ฃจํธ๋
ธ๋์ด๋ฉด ๋์ด์ ๋น๊ตํ์ง ์์ต๋๋ค.
if newNodeIndex == 1 { break }
}
}
tree์์ ์๋ฌด ๊ฐ๋ ์กด์ฌํ์ง ์์ ๋ insert๊ฐ ๋๋ค๋ฉด ์ด๊ธฐํํ ๋์ฒ๋ผ 0๋ฒ ์ธ๋ฑ์ค์ ์ธ๋ชจ์๋ ๊ฐ์ ์ฑ์์ค์ผ ํฉ๋๋ค. ๊ฐ์ด ์๋ค๋ฉด, ๋ง์ง๋ง์ ๊ฐ์ ์ฝ์ ํ๊ณ 2~3๋ฒ์ ๊ณผ์ ์ ๋ฐ๋ณตํฉ๋๋ค. ํธ๋ฆฌ์ ๋ฃจํธ ๋ ธ๋์ index๋ 1์ด๋ฏ๋ก ์ธ๋ชจ์๋ ๊ฐ์ด ๋ค์ด์๋ index์ธ 0์ผ๋ก ๊ฐ์ง ์๋๋ก ํ์ถ ์กฐ๊ฑด์ ๋ฃ์ด์ค์ผ ํฉ๋๋ค.
๋ฐ์ดํฐ์ ์ญ์
๋ฐ์ดํฐ์ ์ญ์ ๋ ์ต๋๊ฐ์ธ ๋ฃจํธ๋ ธ๋๋ฅผ ์ ๊ฑฐํฉ๋๋ค.
- ๋ฃจํ ๋ ธ๋๋ฅผ ์ ๊ฑฐํ๋ค.
- ๋ฃจํธ ๋ ธ๋ ์๋ฆฌ์ ๊ฐ์ฅ ๋ง์ง๋ง ๋ ธ๋๋ฅผ ์ฝ์ ํ๋ค.
- ๋ฃจํธ์๋ฆฌ์ ์ฌ๋ผ๊ฐ ๋ง์ง๋ง ๋ ธ๋์ ์์ ๋ ธ๋๋ฅผ ๋น๊ตํ๋ค.
- ์๋ ์กฐ๊ฑด์ ๋ฐ๋ฅธ๋ค.
- ๋ถ๋ชจ๋ณด๋ค ๋ ํฐ ์์์ด ์๋ค๋ฉด ๊ตํํ์ง ์๊ณ ๋๋ธ๋ค.
- ๋ถ๋ชจ๋ณด๋ค ๋ ํฐ ์์์ด ํ๋๋ง ์์ผ๋ฉด ๊ทธ ์์ํ๊ณ ๊ตํํ๋ค.
- ๋ถ๋ชจ๋ณด๋ค ๋ ํฐ ์์์ด ๋์ด๋ผ๋ฉด ์์๋ค ์ค ํฐ ๊ฐ๊ณผ ๊ตํํ๋ค.
- ํด๋น ๋ ธ๋๊ฐ ๋์ด์ ๊ตํ๋์ง ์์ ๋๊น์ง 3~4๋ฒ ๊ณผ์ ์ ๋ฐ๋ณตํ๋ค.
func leftChildIndex(ofParentAt index: Int) -> Int {
return (2 * index)
}
func rightChildIndex(ofParentAt index: Int) -> Int {
return (2 * index) + 1
}
mutating func pop() -> T? {
guard !tree.isEmpty else { return nil }
if tree.count == 2 {
let value = tree[1]
tree.removeAll()
return value
}
tree.swapAt(1, tree.count - 1)
let value = tree.removeLast()
moveDown(from: 1)
return value
}
mutating func moveDown(from index: Int) {
var parent = index
while true {
let left = leftChildIndex(ofParentAt: parent)
let right = rightChildIndex(ofParentAt: parent)
var popped = parent
if left <= count && tree[left] > tree[popped] {
popped = left
}
if right <= count && tree[right] > tree[popped] {
popped = right
}
if popped == parent {
return
}
tree.swapAt(parent, popped)
parent = popped
}
}
tree์ index๊ฐ 1๋ถํฐ ์์ํ๊ธฐ ๋๋ฌธ์ ์์ ์กฐ๊ฑด 2๊ฐ์ง๊ฐ ๋ถ์ต๋๋ค. ๋น์์ ๋ nil ๋ฐํ, 2๊ฐ์ผ ๋ ๋ชจ๋ ์ญ์ ํ๊ณ ๋ง์ง๋ง๊ฐ ๋ฐํํ๊ธฐ.
ํ ์คํธํด๋ณด์.
var heap = Heap(withData: 10)
heap.insert(50)
heap.insert(20)
heap.insert(100)
print(heap.tree)
heap.pop()
heap.pop()
print(heap.tree)
// [10, 100, 50, 20, 10]
// [10, 20, 10]
์ ๋์ต๋๋ค!
์ต๋ํํธ๋ฆฌ๋ฅผ ๊ตฌํํ์ง๋ง ์ต์ํํธ๋ฆฌ๋ฅผ ๊ตฌํํ๋ ค๋ฉด ๋ง์ด๋์ค๋ก ๊ฐ์ ๋ณํํ์ฌ ์ง์ด๋ฃ์ ์๋ ์๊ณ ๊ตฌํํ ์ฝ๋์ ๋ถ๋ฑํธ๋ฅผ ๋ฐ๋๋ก ๋ฐ๊พธ๋ฉด ๋ฉ๋๋ค. ๋ฐ๋๋ก ๋ฐ๊ฟ๋ ค๋ฉด ๋ง์ด ๋ฐ๊พธ์ด์ผ ํ๊ธฐ ๋๋ฌธ์ initializer์์ ๋ฐ์ ์๋ ์์ต๋๋ค.
struct Heap<T: Comparable> {
var tree: [T] = []
let sort: (T, T) -> Bool
init(withData data: T, sort: @escaping (T, T) -> Bool) {
tree.append(data)
tree.append(data)
self.sort = sort
}
// ...
}
var heap = Heap(withData: 40, sort: >)
์ง๊ธ๊น์ง ๊ตฌํํ ์ฝ๋
struct Heap<T: Comparable> {
var tree: [T] = []
init(withData data: T) {
tree.append(data)
tree.append(data)
}
var isEmpty: Bool {
return tree.isEmpty
}
var count: Int {
return tree.isEmpty ? 0 : tree.count - 1
}
func top() -> T? {
return tree.isEmpty ? nil : tree[1]
}
mutating func insert(_ data: T) {
// ๋น์๋ค๋ฉด ์ด๊ธฐํ๊ฐ ํ์ํฉ๋๋ค.
if tree.isEmpty {
tree.append(data)
tree.append(data)
return
}
// ๊ฐ์ฅ ๋ค์ ๋
ธ๋๋ฅผ ์ฝ์
ํฉ๋๋ค.
tree.append(data)
var newNodeIndex = tree.count - 1
var parentNodeIndex = newNodeIndex / 2
while tree[parentNodeIndex] < tree[newNodeIndex] {
tree.swapAt(parentNodeIndex, newNodeIndex)
newNodeIndex = parentNodeIndex
parentNodeIndex = newNodeIndex / 2
// ํ์ฌ ๋
ธ๋๊ฐ ๋ฃจํธ๋
ธ๋์ด๋ฉด ๋์ด์ ๋น๊ตํ์ง ์์ต๋๋ค.
if newNodeIndex == 1 { break }
}
}
func leftChildIndex(ofParentAt index: Int) -> Int {
return (2 * index)
}
func rightChildIndex(ofParentAt index: Int) -> Int {
return (2 * index) + 1
}
mutating func pop() -> T? {
guard !tree.isEmpty else { return nil }
if tree.count == 2 {
let value = tree[1]
tree.removeAll()
return value
}
tree.swapAt(1, tree.count - 1)
let value = tree.removeLast()
moveDown(from: 1)
return value
}
mutating func moveDown(from index: Int) {
var parent = index
while true {
let left = leftChildIndex(ofParentAt: parent)
let right = rightChildIndex(ofParentAt: parent)
var popped = parent
if left <= count && tree[left] > tree[popped] {
popped = left
}
if right <= count && tree[right] > tree[popped] {
popped = right
}
if popped == parent {
return
}
tree.swapAt(parent, popped)
parent = popped
}
}
}
์ธ๋ฑ์ค๊ฐ 0๋ถํฐ ์์ํ ๋์ Heap์ ๊ตฌํ
struct Heap1<T: Comparable> {
var tree = [T]()
let sort: (T, T) -> Bool
init(sort: @escaping (T, T) -> Bool) {
self.sort = sort
}
var isEmpty: Bool {
return tree.isEmpty
}
var count: Int {
return tree.count
}
func peek() -> T? {
return tree.first
}
func leftChildIndex(ofParentAt index: Int) -> Int {
return (2 * index) + 1
}
func rightChildIndex(ofParentAt index: Int) -> Int {
return (2 * index) + 2
}
func parentIndex(ofChildAt index: Int) -> Int {
return (index - 1) / 2
}
mutating func insert(_ element: T) {
tree.append(element)
moveUp(from: tree.count - 1)
}
mutating func moveUp(from index: Int) {
var child = index
var parent = parentIndex(ofChildAt: child)
while child > 0 && sort(tree[child], tree[parent]) {
tree.swapAt(child, parent)
child = parent
parent = parentIndex(ofChildAt: child)
}
}
mutating func pop() -> T? {
guard !tree.isEmpty else { return nil }
if tree.count == 2 {
let value = tree[1]
tree.removeAll()
return value
}
tree.swapAt(1, tree.count - 1)
let value = tree.removeLast()
moveDown(from: 1)
return value
}
mutating func moveDown(from index: Int) {
var parent = index
while true {
let left = leftChildIndex(ofParentAt: parent)
let right = rightChildIndex(ofParentAt: parent)
var candidate = parent
if left < count && sort(tree[left], tree[candidate]) {
candidate = left
}
if right < count && sort(tree[right], tree[candidate]) {
candidate = right
}
if candidate == parent {
return
}
tree.swapAt(parent, candidate)
parent = candidate
}
}
}