์๊ณ ๋ฆฌ์ฆ ์คํฐ๋ ์ง๋์ฃผ ์ฃผ์ ๋ "๋ฌธ์์ด" ์ด์์ต๋๋ค. ํธ๋ผ์ด ํธ๋ฆฌ๋ฅผ ํ์ฉํ ๋ฌธ์ ๊ฐ ์ธ์์ ์ด์๊ณ , ๋ง์ด ํ์ฉ๋๋ ์๊ณ ๋ฆฌ์ฆ์ด๋ผ๊ณ ํฉ๋๋ค. ์ด๋ฒ์ฃผ Swift ์๊ณ ๋ฆฌ์ฆ ์ฑ ์์๋ ํธ๋ฆฌ ์ค, ํธ๋ผ์ด ํธ๋ฆฌ๋ฅผ ๊ณต๋ถํด์ ์ ๋ฆฌํด๋ณด๋ ค๊ณ ํฉ๋๋ค!
๐ ํ์ด ๋ฐฉ๋ฒ
์ด ๋ฌธ์ ์์๋ ์๋ ๊ทธ๋ฆผ์ผ๋ก ํํธ๋ฅผ ์คฌ์ด์. ์ฒ์ ๋ฌธ์ ๋ฅผ ๋ดค์ ๋ ํธ๋ผ์ด ํธ๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋ ์ํ์์ง๋ง, ์.. ๋ญ๊ฐ ํธ๋ฆฌ๊ตฌ์กฐ๋ฅผ ํ์ฉํด์ผํ๋ ๊ตฌ๋๋ฅผ ์๊ฒ ๋์์ฃ ! ๊ทธ๋์ ์ฐพ์๋ณด๋, ํธ๋ผ์ด ํธ๋ฆฌ๋ฅผ ํ์ฉํด์ ํธ๋ ๋ฌธ์ ๋ผ๋ ๊ฑธ ์๊ฒ ๋์์ต๋๋ค.
๐ก ํธ๋ผ์ด ํธ๋ฆฌ (Trie Tree) ?
ํธ๋ผ์ด ํธ๋ฆฌ๋ ๋ฌธ์์ด ๊ฒ์์ ๋ง์ด ์ฌ์ฉ๋๋ ์๊ณ ๋ฆฌ์ฆ์ด๋ค. ๋ชจ์๋ฆฌ(Edge) ์ Key ๋ฅผ ์ง๋๊ณ , ๋ ธ๋์ ๋ชจ๋ ์์์ ๋ ธ๋์ ์ฐ๊ด๋ ๋ฌธ์์ด์ ๊ณตํต ์ ๋์ฌ(Prefix)๋ฅผ ๊ณต์ ํ๋ค. Prefix Tree ๋ผ๊ณ ๋ ๋ถ๋ฅธ๋ค.
โ๏ธ ์ ·์ถ๋ ฅ
๊ฐ๋ฏธ๊ตด ๋ฌธ์ ๋ ์ ๋ ฅ๋ ์ ์ฒด ๋ฌธ์์ด์ ๋์ด์ฐ๊ธฐ๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ ธ๋๋ฅผ ๊ตฌ๋ถํด ์ฝ์ ํ๊ณ , ์ด๋ฅผ ์๊ฐํํด์ ์ถ๋ ฅํ๋ ๋ฌธ์ ์ ๋๋ค.
โ๏ธ Swift ์ฝ๋
ํธ๋ผ์ด ํธ๋ฆฌ๋ฅผ ์ ์ฉํ๊ธฐ ์ํด ๋ ธ๋์ ํธ๋ฆฌ ํด๋์ค๋ฅผ ๊ตฌํํ๊ณ , ์ฝ์ ๊ณผ ์ ์ฒด ํธ๋ฆฌ๋ฅผ ํ์ํ๋ ๋ฉ์๋๋ฅผ ๊ตฌํํ๋ฉด ๋ฉ๋๋ค.
import Foundation
class TrieNode {
var key: String?
weak var parent: TrieNode?
var children: [String: TrieNode] = [:]
var isLeaf: Bool {
return children.isEmpty
}
init(key: String? = nil, parent: TrieNode? = nil) {
self.key = key
self.parent = parent
}
}
class TrieTree {
// ํธ๋ผ์ด ํธ๋ฆฌ์ ๋ฃจํธ์ key ๋ nil์ด๋ค.
let root: TrieNode
init() {
root = TrieNode()
}
// ์
๋ ฅ ๋ฌธ์์ด์ ํตํด ๋
ธ๋๋ฅผ ์ฝ์
ํ๋ ๋ฉ์๋
func insert(words: [String]) {
var currentNode = root
let n = Int(words[0])!
for word in words[1...n] {
// ๋จ์ด๊ฐ ํ์ฌ ๋
ธ๋์ ์์ ๋
ธ๋์ ์ด๋ฏธ ์กด์ฌํ๋ ๊ฒฝ์ฐ -> ํ์ฌ ๋
ธ๋ ๋ณ๊ฒฝ
if let childNode = currentNode.children[word] {
currentNode = childNode
}
// ๋จ์ด๊ฐ ํ์ฌ ๋
ธ๋์ ์์ ๋
ธ๋์ ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ
// -> ๋
ธ๋ ์์ฑ, ์์ ๋
ธ๋ ์ถ๊ฐ, ํ์ฌ ๋
ธ๋ ๋ณ๊ฒฝ
else {
let newNode = TrieNode(key: word, parent: currentNode)
currentNode.children[word] = newNode
currentNode = newNode
}
}
}
// ํธ๋ผ์ด ํธ๋ฆฌ๋ฅผ ์ ์ฒด์ ์ผ๋ก ํ์ํ๋ ๋ฉ์๋
func traversal(node: TrieNode, depth: Int) {
// ํธ๋ฆฌ์ ๊ณ์ธต์ ๋ํ๋ด๊ธฐ ์ํ ์ถ๋ ฅ๋ฌธ - root๋ฅผ ์ ์ธํ ๋ชจ๋ ๋
ธ๋๊ฐ ์ถ๋ ฅ๋๋ค.
if let key = node.key {
var dash: String = ""
for _ in 0..<depth {
dash += "--"
}
print(dash + key)
}
// ์์ฌ๊ท ๋
ธ๋์ธ ๊ฒฝ์ฐ ์ฌ๊ท์ ์ผ๋ก ํธ์ถ๋ ๋ฉ์๋๋ฅผ ์ข
๋ฃํ๋ค.
guard !node.isLeaf else {
return
}
// ๋
ธ๋์ ์์๋ค์ ์ฌ์ ์์ผ๋ก ํ์ํ๊ธฐ ์ํด ๋์
๋๋ฆฌ๋ฅผ ์ ๋ ฌํ๋ค.
let sortedChildren = node.children.sorted(by: {$0.0 < $1.0})
// ๋
ธ๋์ ์์๋ค์ ์ฌ๊ท์ ์ผ๋ก ํ์ํ๋ค.
for child in sortedChildren {
traversal(node: child.value, depth: depth + 1)
}
}
}
// ์
๋ ฅ๊ณผ ํจ์ ํธ์ถ ๋ฑ
let N = Int(readLine()!)!
let trie = TrieTree()
for _ in 0..<N {
let line = readLine()!.split(separator: " ").map{String($0)}
trie.insert(words: line)
}
trie.traversal(node: trie.root, depth: -1)
Python3 ์ฝ๋
์ฒ์์ Python ์ผ๋ก ํ์ด๋ฅผ ์์ํ์ด์ ์ฐธ๊ณ ์ฉ์ผ๋ก ์ฌ๋ ค๋ก๋๋ค :)
class Node:
# key - ๋
ธ๋์ ํค, data : ์ ์ฒด ๋ฌธ์์ด, children : ์์ ๋
ธ๋ ๋์
๋๋ฆฌ
def __init__(self, key, data=None):
self.key = key
self.data = data
self.depth = 0
self.children = {}
class Trie:
def __init__(self):
self.head = Node(None)
def insert(self, string):
current_node = self.head
depth = 0
for s in string.split(' '):
# ์๋ก์ด ๋ฌธ์๊ฐ ๋
ธ๋์ ํ์์ ์๋ ๊ฒฝ์ฐ, ๋์
๋๋ฆฌ๋ฅผ ์์ฑ
if s not in current_node.children:
current_node.children[s] = Node(s)
# ํ์ฌ ๋
ธ๋๋ฅผ ๋ณ๊ฒฝ
current_node = current_node.children[s]
current_node.depth = depth
#print(current_node.key, current_node.data == None)
depth += 1
# ํ๋จ ๋
ธ๋์ ์ ์ฒด ๋ฌธ์์ด์ ์ ์ฅ
current_node.data = string
#print(current_node, current_node.data == None)
def traversal(self, current_node):
#current_node = self.head
if current_node.data:
return
children = sorted(current_node.children.keys())
for c in children:
depth = current_node.children[c].depth
print('--'*depth, end='')
print(c)
self.traversal(current_node.children[c])
N = int(input())
trie = Trie()
for _ in range(N):
data = input().split()
data = ' '.join(data[1:])
trie.insert(data)
trie.traversal(trie.head)