S를 삽입/탐색/삭제할 때 : 좋은 시간복잡도이론적인 시간복잡도와는 별개로 실제로는 트라이가 해시, 이진 검색 트리에 비해 훨씬 느리다/
메모리를 아주 많이 차지하기 때문에 메모리 사용량이 병목이 될 수 있다.
(삭제를 하더라도 이전에 삽입한 정점들은 메모리에 계속 남아있게 되어 비효율적이다.)
그냥 문자열의 삽입/삭제/검색을 수행해야 하는 상황에서는 트라이보다 해시, 이진 검색 트리를 쓰는 것이 메모리와 시간 측면 모두에서 효율적이고 난이도도 낮다.
일반적인 상황에서는 해시나 이진 검색 트리를 사용하는게 좋으나 트라이의 성질을 사용해야 하는 문제에서는 트라이를 사용하자.
👉 (자동 완성, 접두사와 접미사와 관련된 무언가)
const int ROOT = 1;
int unused = 2;
const int MX = 10000 * 500 + 5; // 최대 등장 가능한 글자의 수
bool chk[MX]; // string의 끝인지 체크
int nxt[MX][26];
for(int i = 0; i < MX; i++)
fill(nxt[i], nxt[i]+26; -1);
int c2i(char C) {
return c - 'A';
}
unused를 이용하여 번호 부여MX는 최대 등장 가능한 글자 수. 문제의 제한 조건으로부터 유추하자.chk은 초록색 테두리로 나타냈던, 해당 정점이 문자열의 끝인지 여부를 저장하는 배열이다.nxt는 각 정점에서 자식 정점의 번호를 의미한다.c2i 함수는 글자를 배열의 인덱스로 변환하는 함수이다.insert 함수void insert(string& a) {
int cur = ROOT;
for(auto c : s) {
if(nxt[cur][c2i(c)] == -1)
nxt[cur][c2i(c)] = unused++;
cur = nxt[cur][c2i(c)];
}
chk[cur] = true;
}
cur : 현재 보고있는 정점, 초기값은 ROOTfind 함수 (탐색)bool find(string& s) {
int cur = ROOT;
for(auto c : s) {
if(nxt[cur][c2i(c)] == -1)
return false;
cur = nxt[cur][c2i(c)];
}
return chk[cur];
}
false 반환chk[cur] 반환void erase(string& s) {
int cur = ROOT;
for(auto c : s) {
if(nxt[cur][c2i(c)] == -1)
return;
cur = nxt[cur][c2i(c)];
}
chk[cur] = false;
}