今天照例,写了一发hihocoder,是关于Trie字典树的,于是顺便再复习下字典树吧。
Trie是一种树,非常实用的一种树,使用Trie还可以写AC自动机。在字符串处理上面有非常好的效率。
首先介绍下字典树的定义。
在使用C++的时候,可以这么定义字典树
#define N 26 //字典树中的字母数量
typedef struct node{
int num; //用于计数
char val; //表示这个节点代表的字符是什么
int ch[N]; //儿子节点
}
由于最近我开始深入学习Java了,所以也写一下Java的定义:
class Trie{
int num = 0;
char val = '\0';
Trie parent = null;
ArrayList<Trie> ch = new ArrayList<Trie>();
public Trie( char c, Trie p ) {
this.val = c;
this.parent = p;
}
public void add( Trie child ) {
ch.add(child);
}
public int getValue() {
return this.num;
}
public int getChildNum() {
return ch.size();
}
}
因为Java没有结构体,所以要使用类,正好可以在里面把Trie要使用的一些方法顺便定义了。
当明确了字典树的定义之后,其实字典树就很直观了。就是一种特殊的树,其每一个节点代表一个字符,从根节点到该节点的路劲上的所有节点按顺序组合在一起就是一个字符串。而每一个节点的num值,就是代表以到这个节点的字符串为前缀的字符串有多少个。
大概结构就是这样…详细的关于树的内容….可以参考二叉树…
概念不难,关键在于灵活运用。
下面给出用python3写的Trie…
class Trie(object):
"""docstring for Trie"""
def __init__(self, c, p):
self.num = 0
self.val = c
self.ch = []
self.parent = p
def add( self, child ):
self.ch.append(child)
def getValue( self ):
return self.num
def getChildSize( self ):
return len( self.ch )
root = Trie('$', -1)
def Insert( string ):
p = root
for s in string:
flag = False
for child in p.ch:
if child.val == s:
p = child
p.num += 1
flag = True
break
if not flag:
q = Trie( s, p )
p.add(q)
p = q
p.num += 1
#以字符串string为前缀的字符串个数
def Query( string ):
p = root
for s in string:
flag = False
for child in p.ch:
if child.val == s:
p = child
flag= True
break
if flag == False:
return 0
return p.getValue()
n = int( input("please input n: ") )
for i in range(n):
string = input("please input string: ")
Insert( string )
m = int( input("please input m: ") )
for i in range(m):
string = input("please input query string: ")
print ( Query(string) )
下面附上hihocoder-1014-Trie树的ac代码:
import java.io.IOException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
public class Main {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
BufferedReader reader = new BufferedReader( new InputStreamReader( System.in ) );
BufferedWriter writer = new BufferedWriter( new OutputStreamWriter( System.out ) );
Trie root= new Trie('$', null);
int n = Integer.parseInt( reader.readLine() );
for( int i = 0; i < n; ++i ) {
String str = reader.readLine();
Trie p = root;
int len = str.length();
for( int j = 0; j < len; ++j ) {
boolean flag = false;
int cur = p.getChildNum();
for( int k = 0; k < cur; ++k ) {
Trie tmp = p.ch.get(k);
if( tmp.val == str.charAt(j) ) {
p = tmp;
++p.num;
flag = true;
break;
}
}
if( !flag ) {
Trie node = new Trie( str.charAt(j), p );
p.add(node);
p = node;
++p.num;
}
}
}
int m = Integer.parseInt( reader.readLine() );
for( int i = 0; i < m; ++i ) {
String str = reader.readLine();
int ans = 0;
Trie p = root;
int len = str.length();
for( int j = 0; j < len; ++j ) {
boolean flag = false;
int cur = p.getChildNum();
for( int k = 0; k < cur; ++k ) {
Trie tmp = p.ch.get(k);
if( tmp.val == str.charAt(j) ) {
p = tmp;
ans = p.getValue();
flag = true;
break;
}
}
if( !flag ) {
ans = 0;
break;
}
}
writer.write(ans + "\r\n");
writer.flush();
}
}
}
class Trie{
int num = 0;
char val = '\0';
Trie parent = null;
ArrayList<Trie> ch = new ArrayList<Trie>();
public Trie( char c, Trie p ) {
this.val = c;
this.parent = p;
}
public void add( Trie child ) {
ch.add(child);
}
public int getValue() {
return this.num;
}
public int getChildNum() {
return ch.size();
}
}