트리의 재귀적 구조를 이해하자!
1. 트리의 루트: A
2. A의 Degree: 3
3. Leaf: K, L, F, G, M, I, J
4. D의 Parent: A
5. D의 Children: H, I, J
6. H의 Siblings: I, J
7. 트리의 depth: 4
8. 노드 M의 ancestors: H, D, A
9. 노드 D의 descendants: H, I, J, M
트리에서 children의 순서는 중요하지 않기 때문에 특정 노드의 어떤 children이더라도 leftmost할 수 있다!
i
에서 최대 개 노드를 가진다.k
인 이진 트리는 최대 개 노드를 가진다.k
인 이진 트리의 노드 개수가 개인 이진 트리n
개가 depth가 k
인 정 이진 트리 안에서 노드 n
번까지 상응하는 이진 트리i
를 통해 찾을 수 있음 → i/2, 2i, 2i+1
세 가지 방식을 통해 표현 (루트 노드는 parent가 없는 예외 존재)import Foundation
let mockTree = ["nil", "A", "B", "C", "D", "E", "F", "G", "H", "I"]
func inorderTraverse(idx: Int) {
if idx * 2 < mockTree.count {
inorderTraverse(idx: idx * 2)
}
print(mockTree[idx], terminator: " ")
if idx * 2 + 1 < mockTree.count {
inorderTraverse(idx: idx * 2 + 1)
}
}
inorderTraverse(idx: 1)
// H D I B E A F C G
let mockTree = ["nil", "A", "B", "C", "D", "E", "F", "G", "H", "I"]
func preorderTraverse(idx: Int) {
print(mockTree[idx], terminator: " ")
if idx * 2 < mockTree.count {
preorderTraverse(idx: idx * 2)
}
if idx * 2 + 1 < mockTree.count {
preorderTraverse(idx: idx * 2 + 1)
}
}
preorderTraverse(idx: 1)
// A B D H I E C F G
import Foundation
let mockTree = ["nil", "A", "B", "C", "D", "E", "F", "G", "H", "I"]
func postorderTraverse(idx: Int) {
if idx * 2 < mockTree.count {
postorderTraverse(idx: idx * 2)
}
if idx * 2 + 1 < mockTree.count {
postorderTraverse(idx: idx * 2 + 1)
}
print(mockTree[idx], terminator: " ")
}
postorderTraverse(idx: 1)
// H I D E B F G C A
leftThread
, rightThread
라는 두 개의 추가적인 프로퍼티 필요dangling thread pointer
): 새로운 루트 노드를 만들어서 기존 이진 트리와 연결 가능. 기존 이진 트리의 루트 노드는 새롭게 생긴 노드의 왼쪽 서브 트리로 연결됨rightThread
가 참이라면 중위 순회의 successor는 우측 자식. 그렇지 않다면 노드에 연결된 자식 노드의 좌측 자식을 향해 leftThread
가 참일 때까지 탐색.우선순위 큐를 구현하기 위해서는
heap
이라는 자료구조가 필요하다!
- 최대 트리: 각 노드의 키 값이 자식 노드의 키 값보다 큰 트리
- 최대 힙: 최대 트리이자 동시에 완전 이진 트리인 경우
- 최소 트리: 최대 트리의 최소 버전
- 최소 힙: 최소 트리이자 동시에 완전 이진 트리인 경우
완전 이진 트리이기 때문에 배열을 통해 효율적으로 표현 가능
import Foundation
struct Heap<T> {
var nodes = [T]()
let sort: (T, T) -> Bool
init(sort: @escaping(T, T) -> Bool) {
self.sort = sort
}
var isEmpty: Bool {
return nodes.isEmpty
}
var count: Int {
return nodes.count
}
func peek() -> T? {
return nodes.first
}
func leftChild(from parentIndex: Int) -> Int {
return parentIndex * 2 + 1
}
func rightChild(from parentIndex: Int) -> Int {
return parentIndex * 2 + 2
}
func parentIndex(from childIndex: Int) -> Int {
return (childIndex - 1) / 2
}
mutating func push(_ element: T) {
nodes.append(element)
siftUp(from: count-1)
}
mutating func siftUp(from index: Int) {
var child = index
var parent = parentIndex(from: child)
while child > 0 && sort(nodes[child], nodes[parent]) {
nodes.swapAt(child, parent)
child = parent
parent = parentIndex(from: child)
}
}
mutating func pop() -> T? {
guard !isEmpty else { return nil }
nodes.swapAt(0, count-1)
defer {
siftDown(from: 0)
}
return nodes.removeLast()
}
mutating func siftDown(from index: Int) {
var parent = index
while true {
let left = leftChild(from: parent)
let right = rightChild(from: parent)
var candidate = parent
if left < count && sort(nodes[left], nodes[candidate]) {
candidate = left
}
if right < count && sort(nodes[right], nodes[candidate]) {
candidate = right
}
if parent == candidate {
return
}
nodes.swapAt(parent, candidate)
parent = candidate
}
}
}
var minHeap = Heap<Int>(sort: <)
minHeap.push(1)
minHeap.push(10)
minHeap.push(100)
minHeap.push(5)
minHeap.push(4)
minHeap.push(3)
minHeap.push(2)
minHeap.push(20)
while !minHeap.isEmpty {
guard let node = minHeap.pop() else { break }
print(node, terminator: " ")
}
// 1 2 3 4 5 10 20 100
import Foundation
class Node<T> {
var data:T
var leftChild: Node?
var rightChild: Node?
init(data: T, leftChild: Node? = nil, rightChild: Node? = nil) {
self.data = data
self.leftChild = leftChild
self.rightChild = rightChild
}
}
struct BST<T> where T : Comparable {
var root: Node<T>?
}
func searchIterative(_ element: T) -> T? {
var root = self.root
while root != nil {
if root!.data == element {
return element
} else if root!.data > element {
root = root!.leftChild
} else {
root = root!.rightChild
}
}
return nil
}
func searchRecursive(_ root: Node<T>?, _ element: T) -> T? {
if root != nil {
if root!.data == element {
return element
} else if root!.data > element {
return searchRecursive(root!.leftChild, element)
} else {
return searchRecursive(root!.rightChild, element)
}
}
return nil
}
func inorderTraverse(_ root: Node<T>?) {
if root != nil {
inorderTraverse(root?.leftChild)
print(root!.data)
inorderTraverse(root?.rightChild)
}
}
func preorderTraverse(_ root: Node<T>?) {
if root != nil {
print(root!.data)
preorderTraverse(root?.leftChild)
preorderTraverse(root?.rightChild)
}
}
func postorderTraverse(_ root: Node<T>?) {
if root != nil {
postorderTraverse(root?.leftChild)
postorderTraverse(root?.rightChild)
print(root!.data)
}
}
mutating func insert(_ element: T) {
let node = Node(data: element)
if let root = root {
insert(root, node)
} else {
self.root = node
}
}
func insert(_ root: Node<T>, _ node: Node<T>) {
if root.data > node.data {
if let leftChild = root.leftChild {
insert(leftChild, node)
} else {
root.leftChild = node
}
} else {
if let rightChild = root.rightChild {
insert(rightChild, node)
} else {
root.rightChild = node
}
}
}
mutating func delete(_ element: T) {
root = delete(root, element)
}
func delete(_ root: Node<T>?, _ element: T) -> Node<T>? {
guard let root = root else { return nil }
if root.data == element {
if root.leftChild == nil && root.rightChild == nil {
return nil
}
if root.leftChild == nil {
return root.rightChild
}
if root.rightChild == nil {
return root.leftChild
}
if let leftmost = getLeftmost(root.rightChild) {
root.data = leftmost.data
}
// min 값
root.rightChild = delete(root.rightChild, root.data)
} else if element < root.data {
root.leftChild = delete(root.leftChild, element)
} else {
root.rightChild = delete(root.rightChild, element)
}
return root
}
func getLeftmost(_ root: Node<T>?) -> Node<T>? {
var root = root
while root?.leftChild != nil {
root = root?.leftChild
}
return root
}
k
키 값을 기준으로 small
, mid
, big
세 가지로 구성 가능k
개의 정렬된 시퀀스, runs
가 하나의 정렬된 시퀀스로 병합되는 경우run
: 여러 개의 레코드로 구성, key
데이터를 기준으로 오름차순 구성k
개의 runs
안에 각각 n
개의 레코드 존재runs
큐에서 pop
되는 노드들이 가장 하단부 8개 노드에 입력, 각각 비교를 통해 부모 노드의 값이 결정, 마지막 루트 노드 값이 정해질 때까지 결정됨import Foundation
struct DisjointTree {
private var nodes = Array(repeating: -1, count: 100)
// 100개 사이즈 할당
private var setPointers = Set<Int>()
mutating func makeSet(setLabel: Int) {
nodes[setLabel] = setLabel
setPointers.insert(setLabel)
}
mutating func insertSet(setLabel: Int, elements: [Int]) {
if setPointers.contains(setLabel) {
for element in elements {
nodes[element] = setLabel
}
}
}
mutating func unionSet(setLabel1: Int, setLabel2: Int) {
if setPointers.contains(setLabel1) && setPointers.contains(setLabel2) {
nodes[setLabel2] = setLabel1
}
}
func getSet(setLabel: Int) {
if setPointers.contains(setLabel) {
for item in nodes.enumerated() {
if item.element == setLabel {
print(item.offset, terminator: " ")
if item.offset != setLabel && setPointers.contains(item.offset) {
getSet(setLabel: item.offset)
}
}
}
}
}
}
var disjointTree = DisjointTree()
disjointTree.makeSet(setLabel: 1)
disjointTree.makeSet(setLabel: 2)
disjointTree.insertSet(setLabel: 1, elements: [3, 4, 5, 6, 7, 8])
disjointTree.insertSet(setLabel: 2, elements: [9, 11, 13, 15])
disjointTree.getSet(setLabel: 1)
// 1 3 4 5 6 7 8
disjointTree.getSet(setLabel: 2)
// 2 9 11 13 15
disjointTree.unionSet(setLabel1: 1, setLabel2: 2)
disjointTree.getSet(setLabel: 1)
// 1 2 9 11 13 15 3 4 5 6 7 8