트라이란?
- 트라이는 문자열의 집합을 표현하는 트리 자료구조 입니다.
- 트라이는 집합에 포함된 문자열의 접두사들에 대응되는 노드들이 서로 연결된 트리 입니다.
- 트라이는 문자열 집합 내에서 원하는 원소를 찾는 작업을 O(M) 시간만에 할 수 있습니다.
- M: 문자열의 최대길이
※참고※
문자열을 다루는 작업은 정수나 실수 등의 다른 자료형을 다루는 것과 다르다. 정수나 실수형 변수는 그 크기가 항상 정해져 있기 때문에 비교에 상수 시간 이 걸린다고 가정해도 되는 반면, 문자열 변수를 비교하는 데는 최악의 경우 문자열의 길이에 비례하는 시간이 걸리기 때문입니다.
트라이 특징
- 루트노드에서 한 노드까지 내려가는 경로에서 만나는 글자들을 모으면 해당 노드에 대응되는 접두사를 얻을 수 있기 때문에 각 노드에 대응되는 문자열을 저장할 필요가 없다.
- 트라이의 한 노드를 표현하는 객체는 자손 노드들을 가리키는 포인터 목록, 해당 노드가 종료 노드인지를 나타내는 불린 값 변수 로 구성된다.
- 포인터 목록은 동적 배열로 구현하는 것이 아니라, 입력에 등장할 수 있는 모든 문자에 각각 대응되는 원소를 갖는 고정길이 배열로 구현 됩니다.
- 각 노드가 26개짜리 포인터 배열 을 가지고 있다.
- 이 배열의 0번째 원소는 대응되는 문자열 맨 뒤에 글자 A를 붙이는 경우 얻을 수 있는 문자열 노드의 포인터를 나타낸다. 만약 해당 노드가 없다면 NULL을 저장한다.
- 트라이 구조는 메모리를 엄청나게 낭비하는 단점 을 가지고 있지만, 다음노드를 찾는 과정에서 어떤 탐색도 필요하지 않다는 장점 을 가지고 있다.
트라이 예시
- M: 문자열의 최대길이
※참고※
문자열을 다루는 작업은 정수나 실수 등의 다른 자료형을 다루는 것과 다르다. 정수나 실수형 변수는 그 크기가 항상 정해져 있기 때문에 비교에 상수 시간 이 걸린다고 가정해도 되는 반면, 문자열 변수를 비교하는 데는 최악의 경우 문자열의 길이에 비례하는 시간이 걸리기 때문입니다.
- 포인터 목록은 동적 배열로 구현하는 것이 아니라, 입력에 등장할 수 있는 모든 문자에 각각 대응되는 원소를 갖는 고정길이 배열로 구현 됩니다.
- 각 노드가 26개짜리 포인터 배열 을 가지고 있다.
- 이 배열의 0번째 원소는 대응되는 문자열 맨 뒤에 글자 A를 붙이는 경우 얻을 수 있는 문자열 노드의 포인터를 나타낸다. 만약 해당 노드가 없다면 NULL을 저장한다.
아래 그림은 문자열 집합 arr={“BE”,”BET”,”BUS”,”TEA”,”TEN”}를 저장하는 트라이 예시입니다.
트라이 구현 코드
toNumber()
[0, ALPABETS-1] 범위의 숫자로 변환해 주는 함수- 알파벳 대문자가 아니라 소문자, 숫자 등으로 출현하는 문자가 달라질 때는 이부분만 바꿔 사용한다.
insert()
트라이 구조를 만드는 함수find()
해당 문자열을 찾는 함수- 찾아낸 문자열에 대응되는 노드가 종료 노드인지 아닌지에 대해서는 신경 쓰지 않는다.
- 트라이가 표현하는 집합에 해당 문자열이 진짜로 존재하는지 확인하기 위해서는 반환된 노드의 terminal 멤버가 참인지 확인해야 한다.
insert(), find()
의 시간복잡도는 모두 문자열의 길이 M에 선형 비례한다. O(M)
Reference
- 종만북 - 26장 트라이