字典树 总结

初学
用数组来建树

// 用数组模拟 一般优于结构体 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
using namespace std;
const int maxn = 1e5 + 10;
int tire[maxn][26]; //字典树,  数组建树 
int exist[maxn];//单词是否为输入的 
int sum[maxn];//包含相同前缀数,即该点经过次数 
int tot = 0;

void insert(char *s){//插入 
	int len = strlen(s);
	int root = 0;
	for(int i = 0; i < len; ++ i){
		int id = s[i] - 'a';
		if(tire[root][id] == -1){
			tire[root][id] = ++ tot;
			exist[tot] = 0;
		}	
		root = tire[root][id];
		sum[root] ++;	
	}
	exist[root] = 1;//该节点是存入的单词最后一位,表示该单词是存在的 
}

//查找有 查找单词是否存在 和 查找前缀 
int find(char *s){//查找是否为插入单词 
	int len = strlen(s);
	int root = 0;
	for(int i = 0; i < len; ++ i){
		int id = s[i] - 'a';
		if(tire[root][id] == -1)//不存在 
			return -1;
		root = tire[root][id];
	}
	if(exist[root] == 1)//如果只是查找前缀的话,就不需要判断exist了 
		return 1;
	else
		return -1;
}

int find_num(char *s){//查找前缀s出现的次数 
	int len = strlen(s);
	int root = 0;
	for(int i = 0; i < len; ++ i){
		int id = s[i] - 'a';
		if(tire[root][id] == -1)//不存在 
			return 0;
		root = tire[root][id];
	}
	return sum[root];
}


void delete(char *s){
	int len = strlen(s);
	int rt = 0, cnt = 0;
	int num[1000], rt = 0;
	for(int i = 0; i < len; ++ i){
		int id = s[i] - 'a';
		rt = tire[rt][id];
		if(sum[rt] == 1){//存单路节点, 到时候可以删除,多个分支就不可删 
			num[cnt] = rt;
			cnt ++;
		}
		else
			st = rt;
	}
	exist[id] = 0;
	for(int i = 0; i < cnt; ++ i){
		tire[st][num[i]] = 0;
		st = num[i];
	}
}

用结构体 与 指针建树

//用结构体 与 指针来建树

typedef struct tire{
	int sum, exist;
	tire *next[26],
}tire; 

tire *root;

tire *build(){
	tire *k = new(tire);
	k->sum=0;
	memset(k->next,0,sizeof(k->next));
    return k;
}

void insert(char *s){
	tire *r = root;
	char *word = s;
	while(*word){
		int id = *word - 'a';
		if(r->next[id] == NULL)
			r->next[id] = build();
		r = r->next[id];
		r->sum ++;
		word ++;
	}
	r->exist = 1;
}

int search(char *s){
	tire *r = root;
	char *word = s;
	while(*word){
		int id = *word - 'a';
		if(r->next[id] == NULL)
			return 0;
		r->next[id];
		word ++;
	}
	//return r->exist;
	return r->sum;
}

题目
hdu 1251 模板题

//数组
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = 1e6 + 10;
int tire[maxn][26];
int sum[maxn];
int tot = 0;

void insert(char *s){
	int len = strlen(s);
	int rt = 0;
	for(int i = 0; i < len; ++ i){
		int id = s[i] - 'a';
		if(tire[rt][id] == 0)
			tire[rt][id] = ++ tot;
		rt = tire[rt][id];
		sum[rt] ++;	
	}
}

int search_sum(char *s){//查找前缀出现次数 
	int len = strlen(s);
	int rt = 0;
	for(int i = 0; i < len; ++ i){
		int id = s[i] - 'a';
		if(tire[rt][id] == 0)
			return 0;
		rt = tire[rt][id];
	}
	return sum[rt];
}

char s[20];

int main(){//两种读入判断 空行 的方法 
	//while(cin.getline(s,12)){
	//	if(strlen(s) == 0)
	//		break;
	//	
	//}
	while(gets(s)){//空行。gets读入的回车符会自动转换为NULL。
		if(s[0] == NULL)
			break;
		insert(s);
	}
	while(~scanf("%s", s)){
		printf("%d\n", search_sum(s));
	}
}




//结构体
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

typedef struct tire{
	int sum, exist;
	tire *next[26];
}tire;

tire *root;

tire *build(){
	tire *k = new(tire);
	for(int i = 0; i < 26; ++ i)
		k->next[i] = NULL;
	k->sum = 0;
	return k;
}

void insert(char *s){
	tire *r = root;
	int len = strlen(s);
	for(int i = 0; i < len; ++ i){
		int id = s[i] - 'a';
		if(r->next[id] == NULL)
			r->next[id] = build();
		r = r->next[id];
		r->sum ++;
	}
}

int find(char *s){
	tire *r = root;
	int len = strlen(s);
	for(int i = 0; i < len; ++ i){
		int id = s[i] - 'a';
		if(r->next[id] == 0)
			return 0;
		r = r->next[id];
	}
	return r->sum;
}

char s[20];
int main(){
	root = build();
	while(gets(s)){
		if(s[0] == NULL)
			break;
		insert(s);
	}
	while(~scanf("%s", s)){
		printf("%d\n", find(s));
	}
}

hdu 2072

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int maxn = 2e6 + 10;
int tire[maxn][26];
int exist[maxn];
int ans = 0;
int tot = 0; 
void insert(char *s){
	int len = strlen(s);
	int rt = 0;
	for(int i = 0; i < len; ++ i){
		int id = s[i] - 'a';
		if(tire[rt][id] == 0){
			tire[rt][id] = ++ tot;
			exist[tot] = 0;
		}
		rt = tire[rt][id];
	}
	if(exist[rt] == 0){
		ans ++;//ans 记录出现次数,去除重复 
		exist[rt] = 1;
	}
} 



char s[maxn];
char temp[maxn];
int main(){
	while(gets(s)){
		ans = 0;
		exist[0] = 0;
		if(s[0] == '#')
			break;
		int len = strlen(s);
		int cnt = 0;
		for(int i = 0; i < len; ++ i){
			if(s[i] != ' ')
				temp[cnt ++] = s[i];
			else{		
				temp[cnt] = '\0';
				if(temp[0] != '\0')
					insert(temp);
				cnt = 0;
			}
		}
		if(temp[0] != '\0')
			insert(temp);
		printf("%d\n", ans); 
		for(int i = 0; i <= tot; ++ i)
			exist[i] = 0;
	}
}

将输入的字符串按字典序排序小到大输出

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int maxn = 1e6 + 10;
int tire[maxn][26];
int exist[maxn];
int tot = 0;

void insert(char *s){
	int len = strlen(s);
	int rt = 0;
	for(int i = 0; i < len; ++ i){
		int id = s[i] - 'a';
		if(tire[rt][id] == 0){
			tire[rt][id] = ++ tot;
			exist[tot] = 0;
		}
		rt = tire[rt][id];
	}
	exist[rt] = 1;
}

char temp[maxn];
void sort_string(int rt, int cnt){// 按字典序排序输出 
	for(int i = 0; i < 26; ++ i){
		int ccnt = cnt;
		if(tire[rt][i] != 0){
			temp[ccnt ++] = 'a' + i;
			temp[ccnt] = '\0';
			if(exist[tire[rt][i]] == 1)
				printf("%s\n", temp);
			sort_string(tire[rt][i], ccnt);
		}
	}
}

char s[maxn];
int main(){
	while(~scanf("%s", s)){
		insert(s); 
	}
	sort_string(0, 0);
}

POJ 2001

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int maxn = 1e6 + 10;
int tire[maxn][26];
int sum[maxn];
int tot = 0;

void insert(char *s){
	int len = strlen(s);
	int rt = 0;
	for(int i = 0; i < len; ++ i){
		int id = s[i] - 'a';
		if(tire[rt][id] == 0)
			tire[rt][id] = ++ tot;
		rt = tire[rt][id];
		sum[rt] ++;
	}
}

void print_shortest_prefix_substring(char *s){//输出最短的代表自己的字符串 
	int len = strlen(s);
	int rt = 0;
	char temp[22];
	int cnt = 0;
	for(int i = 0; i < len; ++ i){
		int id = s[i] - 'a';
		rt = tire[rt][id];
		if(sum[rt] != 1)
			temp[cnt ++] = id + 'a';
		else{
			temp[cnt ++] = id + 'a';
			break;
		}		
	}	
	temp[cnt] = '\0';
	printf("%s\n", temp);
}

char s[1010][22];
int main(){
	int cnt = 0;
	while(~scanf("%s", s[cnt])){
		insert(s[cnt++]);
	}
	for(int i = 0; i < cnt; ++ i){
		printf("%s ", s[i]);
		print_shortest_prefix_substring(s[i]);
	}
}

POJ 3630

#include<cstdio>
#include<cstring>

using namespace std;
const int maxn = 1e6 + 10;
int tire[maxn][10];
int sum[maxn];
int exist[maxn];
int tot = 0;

int flag = 1;
void insert(char *s){
	int len = strlen(s);
	int rt = 0;
	for(int i = 0; i < len; ++ i){
		int id = s[i] - '0';
		if(tire[rt][id] == 0){
			tire[rt][id] = ++ tot;
			exist[tot] = 0;
		}	
		rt = tire[rt][id];
		sum[rt] ++;
		if(exist[rt] == 1)//只要在某个字符串路径上出现其他串的最后一位,flag=0 
			flag = 0; 
	}
	exist[rt] = 1;
	if(exist[rt] == 1 && sum[rt] > 1)
		flag = 0; 
}

void init_tire(int rt){//初始化 
	for(int i = 0; i < 10; ++ i){
		if(tire[rt][i]){
			inittire(tire[rt][i]);
			tire[rt][i] = 0;
		}	
	}
}

int t, n;
char s[20];
int main(){
	scanf("%d", &t);
	while(t--){
		scanf("%d", &n);
		flag = 1;
		tot = 0;
		for(int i = 0; i < n; ++ i){
			scanf("%s", s);
			insert(s);
		}
		if(flag)
			printf("YES\n");
		else
			printf("NO\n");
		for(int i = 0; i <= tot; ++ i){
			sum[i] = 0;
			exist[i] = 0;
		}
		init_tire(0);
	}
}

light oj 1224

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
const int maxn = 2e6 + 10;
int tire[maxn][4];
int sum[maxn];
int maxx = 0;
int tot = 0;

void insert(char *s){
	int len = strlen(s);
	int rt = 0;
	for(int i = 0; i < len; ++ i){
		int id = 0;
		if(s[i] == 'C')
			id = 1;
		else if(s[i] == 'G')
			id = 2;
		else if(s[i] == 'T')
			id = 3;
		if(tire[rt][id] == 0)
			tire[rt][id] = ++ tot;
		rt = tire[rt][id];
		sum[rt] ++;
		if(sum[rt] * (i + 1) > maxx)
			maxx = sum[rt] * (i + 1);
	}
}

int n, t;
char s[52];
int main(){
	int cnt = 1;
	for(scanf("%d", &t); t; --t){
		scanf("%d", &n);
		tot = 0;
		maxx = 0;
		for(int i = 0; i < n; ++ i){
			scanf("%s", s);
			insert(s);
		}
		printf("Case %d: %d\n", cnt++, maxx);
		for(int i = 0; i <= tot; ++ i){
			sum[i] = 0;
			for(int j = 0; j < 4; ++ j)
				tire[i][j] = 0;
		}
	}
}

POJ1451

#include<cstdio>
#include<map>
#include<cstring>
#include<algorithm>
#include<string>
#include<iostream>
using namespace std;
const int maxn = 1e6 + 10;
int tire[maxn][26];
int sum[maxn];
map<string, int> map1;
map<string, string> map2;
int alpha_to_int[30];
int tot;

void init(){
	for(int i = 0; i <= 17; ++ i)
		alpha_to_int[i] = i / 3 + 2;
	alpha_to_int[18] = 7;
	for(int i = 19; i < 25; ++ i)
		alpha_to_int[i] = (i-1) / 3 + 2;
	alpha_to_int[25] = 9; 
}

void insert(char *s, int num){
	int len = strlen(s);
	int rt = 0;
	string temp_int = "", temp_alpha = "";
	for(int i = 0; i < len; ++ i){
		int id = s[i] - 'a';
		temp_int += alpha_to_int[id] + '0';
		temp_alpha += id + 'a';
		if(tire[rt][id] == 0)
			tire[rt][id] = ++ tot;
		rt = tire[rt][id];
		sum[rt] += num;
		if(sum[rt] > map1[temp_int]){
			map1[temp_int] = sum[rt];
			map2[temp_int] = temp_alpha;	 
		}
	}
}
int t, n, num;
char s[110];
int main(){
	int cnt = 1;
	init();
	for(scanf("%d", &t); t; --t){
		map1.clear();
		map2.clear();
		scanf("%d", &n);
		tot = 0;
		for(int i = 0; i < n; ++ i){
			scanf("%s %d", s, &num);
			insert(s, num);
		}
		scanf("%d", &n);
		printf("Scenario #%d:\n", cnt ++);
		for(int i = 0; i < n; ++ i){
			scanf("%s", s);
			int len = strlen(s);
			string temp = "";
			for(int j = 0; j < len-1; ++ j){
				temp += s[j];
				if(!map2.count(temp))//map1[temp])
					printf("MANUALLY\n"); 
				else
					printf("%s\n",map2[temp].c_str());
					//cout << map2[temp] << endl;
			}
			printf("\n");
		}
		printf("\n");
		for(int i = 0; i <= tot; ++ i){
			sum[i] = 0;
			for(int j = 0; j < 26; ++ j)
				tire[i][j] = 0;
		}
	}
}

posted @ 2020-07-13 00:06  wansheking  阅读(21)  评论(0)    收藏  举报