zoukankan      html  css  js  c++  java
  • 【C/C++】字典树

    引用书籍:《算法竞赛入门到进阶》清华大学出版社

    字符串匹配问题

    • 有这样一个字符串的问题:在n个字符串中查找某个字符串是否存在?
    • 如果使用暴力的做法,逐个来匹配每个字符串,复杂度是O(nm),m是字符串的平均长度,这种做法效率很低。
    • 字典树:在上述问题中,如果像查字典一样,比如要查找单词"dog",先翻到字典中d对应的部分,再按顺序查找'o'和'g'。效率要高很多,字典树就是模拟这种操作的数据结构。

    例题(hdu 1251)

    • 用map实现:
    #include<bits/stdc++.h>
    
    using namespace std;
    
    int main(){
    	char str[12];
    	map<string, int>m;
    	while(fgets(str, 12, stdin)){ //也可以使用gets函数读入字符串,循环体的内容需要做微小的改动
    		int len = strlen(str);
    		if(len==1) break;
    		for(int i=len-1; i>0; i--){
    			str[i] = '';
    			m[str]++;
    		}
    	}
    	while(~scanf("%s",str)) printf("%d
    ",m[str]);
    	return 0;
    }
    
    • 用字典树实现(数组)
    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int maxn = 5e4 + 10;
    int tire[maxn*10][26];
    int book[maxn*10];
    int cnt;
    
    void Insert(char *str){
    	int len = strlen(str);
    	int root = 0;
    	for(int i=0; i<len; i++){
    		int id = str[i] - 'a';
    		if(!tire[root][id]) tire[root][id] = ++cnt;
    		root = tire[root][id];
    		book[root]++;
    	}
    }
    
    int Find(char *str){
    	int len = strlen(str);
    	int root = 0;
    	for(int i=0; i<len; i++){
    		int id = str[i] - 'a';
    		if(!tire[root][id]) return 0;
    		root = tire[root][id];
    	}
    	return book[root];
    }
    
    int main(){
    	cnt = 0;
    	memset(tire, 0, sizeof(tire));
    	memset(book, 0, sizeof(book));
    	char str[12];
    	while(gets(str)){
    		if(!strlen(str)) break;
    		Insert(str);
    	}
    	while(gets(str)) printf("%d
    ",Find(str));
    	return 0;
    }
    
    • 字典树还可以使用结构体指针来实现,但是空间复杂度相比于数组要差一些,因此并不常用,在此题中也会MLE
    #include<bits/stdc++.h>
    
    using namespace std;
    
    struct Trie{
    	Trie * next[26];
    	int num;
    	Trie(){
    		for(int i=0; i<26; i++) next[i] = NULL;
    		num = 0;
    	}
    };
    Trie root;
    
    void Insert(char *str){
    	int len = strlen(str);
    	Trie *p = &root;
    	for(int i=0; i<len; i++){
    		int id = str[i] - 'a';
    		if(p->next[id] == NULL)
    			p->next[id] = new Trie;
    		p = p->next[id];
    		p->num++;
    	}
    }
    
    int Find(char *str){
    	Trie *p = &root;
    	for(int i=0; str[i]; i++){
    		int id = str[i] - 'a';
    		if(p->next[id] == NULL)
    			return 0;
    		p = p->next[id];
    	}
    	return p->num;
    }
    
    
    int main(){
    	char str[12];
    	while(gets(str)){
    		if(!strlen(str)) break;
    		Insert(str);
    	}
    	while(gets(str)) printf("%d
    ",Find(str));
    	return 0;
    } 
    
  • 相关阅读:
    Oracle中模拟SQL中的isnull函数
    Delphi:在OnBeforePost事件中取消TDataSet.Post(Delphi: Canceling a TDataSet.Post in an OnBeforePost Event)
    DBGrid的输入焦点控制
    刷新dbgrid 而不失去当前行位置
    MoveTo和MoveBy
    接口及接口测试
    ()文献可视化--vosviewer入门
    给出先序和中序,给一个数找到位置并输出它左子树里最大的数
    Kruskal算法:最小生成树
    Prim算法:最小生成树
  • 原文地址:https://www.cnblogs.com/sdutzxr/p/12430994.html
Copyright © 2011-2022 走看看