关于Trie树的建立

trie树,又称字典树,是一种用于字符串的简单数据结构.

这种数据结构虽然简单,但在异或这种位运算加速的时候特别灵活,且也是AC自动机的基础数据结构.

这种树就是将一些字符串直接表示在一棵树上,合成了一个整体.

这个整体的构建思想,就是定义根节点为空,接下来根节点会有一些儿子节点,每个儿子节点对应了一个字符,表示这个字符串的第一个字符,接下来每个节点也会有一些儿子节点,也分别表示一个字符,表示这个字符串接下来的一个字符.

特别的,有些节点会有特殊的标记,表示这个节点是否是一串字符串的结尾.

也就是说,在这棵树上,一个字符串是靠最后一个节点确定的.

例如下面一棵trie树:


其中橙色的表示打了标记是结尾字符.

那么我们就可以确定这棵树中的字符串有{ab,ae,ac,cd},而且这样做节省了一部分空间.

那么实现的过程怎么办呢?

我们在trie树上的结构体存如下几个信息:

1.当前结点代表什么字符.

2.当前节点有哪些儿子,且存下儿子的节点编号.

3.是否是一个单词结尾.

具体如下:

struct trie_tree{
  int next[26];
  char c;
  bool end;
}trie[N+1];

我们可以先建树,直接见一个空节点表示root:

int top=0;
void build(){
  trie[top=0].c='\0';
  memset(trie,0,sizeof(trie));      //初始化整个数组 
}

那么若要插入一个字符串,我们就看当前结点的下一个节点是否已创建,若已创建,直接遍历下去;若未创建,直接重新建一个节点,并将当前结点的一个儿子设为此节点,继续遍历下去.

最后字符串结束时,要打上一个标记.

具体代码实现如下:

void ins(string s){      //新插入一个字符串s 
  int j=0,n=s.size();
  for (int i=0;i<n;i++)
    if (trie[j].next[s[i]-'A']==0) trie[++top].c=s[i]-'A',trie[j].next[s[i]-'A']=top,j=top;      //若不存在这么一个儿子节点,新建节点后往下遍历 
    else j=trie[j].next[s[i]-'A'];      //否则,直接往下遍历 
  trie[j].end=1;      //打上一个标记 
}

查询某个字符串是否在trie树中,可以直接从根节点开始遍历.

只要遍历到一个节点的下一个节点在trie树上没有,姐可以返回false了.

若遍历完了,我们也要判断一下这个节点是否是结束节点,也就是看end标记是否为true.

代码如下:

bool in(string s){
  int j=0,n=s.size();
  for (int i=0;i<n;i++)
    if (trie[j].next[s[i]-'A']==0) return false;      //若没有节点,返回false 
    else j=trie[j].next[s[i]-'A'];      //继续往下遍历 
  if (trie[j].end) return true;      //判断是否是结尾 
  else return false;
}

那么这个就差不多了.

一般来说trie树就是这么两个操作.

那么总的trie树如下:

struct trie_tree{
  int next[26];
  char c;
  bool end;
}trie[N+1];
int top=0;
void build(){
  trie[top=0].c='\0';
  memset(trie,0,sizeof(trie));      //初始化整个数组 
}
void ins(string s){      //新插入一个字符串s 
  int j=0,n=s.size();
  for (int i=0;i<n;i++)
    if (trie[j].next[s[i]-'A']==0) trie[++top].c=s[i]-'A',trie[j].next[s[i]-'A']=top,j=top;      //若不存在这么一个儿子节点,新建节点后往下遍历 
    else j=trie[j].next[s[i]-'A'];      //否则,直接往下遍历 
  trie[j].end=1;      //打上一个标记 
}
bool in(string s){
  int j=0,n=s.size();
  for (int i=0;i<n;i++)
    if (trie[j].next[s[i]-'A']==0) return false;      //若没有节点,返回false 
    else j=trie[j].next[s[i]-'A'];      //继续往下遍历 
  if (trie[j].end) return true;      //判断是否是结尾 
  else return false;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/80464527