数据结构——从英文字典树到中文字典树
昨天面试电话中的一道题,题目如下:
1、给你一个姓名的集合,查找你的名字是否在里面出现。
我的回答是用set,把集合中所有的姓名放到set集合中,直接用find查找我的姓名在这个集合里面是否出现。
2、追问,如果要搜索姓氏为叶的人,输入关键字叶,那么会出现所有姓为叶的人,应该如何设计?
当时的回答是,姓为key,名为value,存放到multimap中,使用multimap中的count函数统计key为叶的个数,然后用find函数找到第一个key为叶的指针,使用迭代器从该指针向后查找count个元素,判断这count个元素中是否有姓名为叶x的人。后来想想我的方法其实可以优化的,网上的思路基本上都是采用字典树,但仅针对英文单词。如果把字典树和我的在面试时候的方法结合起来就非常棒了(可惜当时没想到>_<)。
- 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
- 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
- 每个节点的所有子节点包含的字符都不相同。
#define MAX_CHILD 26
struct trie_node
{trie_node(){count = 0;for (int i = 0; i < MAX_CHILD; i++){child[i] = NULL;}}int count;//表示以该节点结束的单词的个数trie_node *child[MAX_CHILD];//存放孩子节点指针的数组
};
例如中文字符串:数字、数据、数据集、数据库、数理化、测试、计量、记事本、计算机、计算器。那中文字典树如下:
#include <string>
#include <map>
#include <vector>
#include <iostream>
#define CH_SIZE 3//汉字大小linux为3,win为2
using namespace std; struct trie_node
{ trie_node() { count = 0; } int count;//表示以该汉字结束的字符串个数 map<string, trie_node *> child;//键值为当前汉字,实值为后面汉字节点的指针
}; class trie
{
public: trie(); ~trie(); void insert_str(string str);//插入字符串 trie_node *search_str(string str);//查询字符串 trie_node *search_str_pre(string str_pre);//查询字符串前缀 void delete_str(string str);//删除字符串 vector<string> get_str_pre(string str);//返回所有前缀为str的字符串 void clear();//清空
private: void add_str(trie_node *root, string pre_str, vector<string> &ret); //递归添加以pre_str为前缀的字符串到ret集合
private: struct trie_node *root;
}; trie::trie()
{ root = new trie_node();
} trie::~trie()
{
} //插入字符串
void trie::insert_str(string str)
{ if (root == NULL || str == "") { return ; } trie_node *cur_node = root; for (int i = 0; i < str.size();) { string sub_str = str.substr(i, CH_SIZE); map<string, trie_node *>::iterator iter = cur_node->child.find(sub_str); if (iter == cur_node->child.end())//如果在map中没有找到则插入新节点 { trie_node *tmp_node = new trie_node(); cur_node->child.insert(pair<string, trie_node *>(sub_str, tmp_node)); cur_node = tmp_node; } else//如果找到了value即为指向下一个节点的指针 { cur_node = iter->second; } i = i + CH_SIZE ; } cur_node->count++;
} //删除字符串
void trie::delete_str(string str)
{ trie_node *find_node = search_str(str); if (find_node) { find_node->count--; }
} //查询字符串前缀
trie_node * trie::search_str_pre(string str)
{ if (str == "") { return root; } if (NULL == root ) { return NULL; } trie_node *cur_node = root; int i; for ( i = 0; i < str.size(); ) { string sub_str = str.substr(i, CH_SIZE); map<string, trie_node *>::iterator iter = cur_node->child.find(sub_str); if (iter == cur_node->child.end()) { return NULL; } else { cur_node = iter->second; } i = i + CH_SIZE; } if (i == str.size()) { return cur_node; } else { return NULL; }
} //查询字符串
trie_node * trie::search_str(string str)
{ trie_node * find_pre_node = search_str_pre(str); if (find_pre_node != NULL) { if (find_pre_node->count == 0) { return NULL; } else { return find_pre_node; } }
} //清空
void trie::clear()
{ vector<trie_node *> que; que.push_back(root); while (!que.empty()) { for (map<string, trie_node *>::iterator iter = root->child.begin(); iter != root->child.end(); iter++) { que.push_back(iter->second); } trie_node *del_node = que.front(); que.pop_back();delete del_node; }
} //递归添加以pre_str为前缀的字符串到ret集合
void trie::add_str(trie_node *root, string pre_str, vector<string> &ret)
{ for (map<string, trie_node *>::iterator iter = root->child.begin(); iter != root->child.end(); iter++) { add_str(iter->second, pre_str + iter->first, ret); } if (root->count != 0) { ret.push_back(pre_str); }
} //返回所有前缀为str的字符串
vector<string> trie::get_str_pre(string str)
{ vector<string> ret; trie_node *find_node = search_str_pre(str); if (find_node != NULL) { add_str(find_node, str, ret); } return ret;
}
int main()
{trie t;int n;string str;vector<string> ret;cout << "please input the num of the dictionary:" << endl;cin >> n;for (int i = 0; i < n; i++){cin >> str;t.insert_str(str);}cout << "please input the key word:" << endl;cin >> str;ret = t.get_str_pre(str);for (vector<string>::iterator iter = ret.begin(); iter != ret.end(); iter++){cout << *iter << endl;}return 0;
}
数据结构——从英文字典树到中文字典树相关推荐
- Trie树 -- 高效的字典树
文章目录 简介 原理 构造一棵Trie树 使用Trie树进行查询 实现 模拟(瞎暴力)实现 空间优化 简介 Trie树是一种数据结构,它有一个好听的中文名字,叫"字典树".顾名思义 ...
- 012-数据结构-树形结构-哈希树[hashtree]、字典树[trietree]、后缀树
一.哈希树概述 1.1..其他树背景 二叉排序树,平衡二叉树,红黑树等二叉排序树.在大数据量时树高很深,我们不断向下找寻值时会比较很多次.二叉排序树自身是有顺序结构的,每个结点除最小结点和最大结点外都 ...
- 字符串处理【字典树】 - 原理 字典树详解
字符串处理[字典树] - 原理 字典树详解 字典树,又称Trie树.单词查找树,是一种树形结构,也是哈希树的一种变种,主要用于统计.排序和存储大量的字符串(但不限于字符串),所以经常被搜索引擎系统用于 ...
- dmol3给定关键字不在字典中_python中的数据结构与算法(2):字典与集合
1. 字典是什么 字典是便于信息检索的一种数据结构,鉴于信息检索在程序中无处不在,字典的使用场景也非常广泛,包括许多 python 内部机制的实现,也依赖字典结构,比如命名空间的管理等. 检索一般是根 ...
- 字典树实现_trie 字典树的实现方法
trie 字典树 (前缀树) 什么是字典树 又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文 ...
- 字典树(单词查找树、Trie)
文章目录 单词查找树 1 基本概念 2 字典树的应用 3 字典树基本操作的实现 4 参考资料 单词查找树 1 基本概念 百度百科对字典树的介绍为:是一种树形结构,是一种哈希树的变种. < ...
- 字典树(Trie/前缀树)
目录 字典树的概念 字典树的逻辑 字典树的实现 易混点剖析 代码示例 字典树的概念 字典树(Trie)是一种空间换时间的数据结构,是一棵关于"字典"的树.主要用于统计.排序和保存大 ...
- 字典树与01字典树详解
[镇楼] 不满足于粗浅的表面了解字典树吗,今天!由我给大家带来!字典树与01字典树的解析!! 目录 [引入] [字典树] [01字典树] [引用参考] [引入] 字典是干啥的?查找字的.那么字典树 ...
- 从Trie树(字典树)和后缀树
从Trie树(字典树)谈到后缀树 转载:http://blog.csdn.net/v_july_v/article/details/6897097#t22 感谢作者,侵删. 引言 常关注本blog的读 ...
最新文章
- MySQL锁表解决方法
- 求素数的方法完整归纳,学的不仅是“求素数”!
- No transaction aspect-managed TransactionStatus in scope
- 最近一直因为工作的事情,耽误学习了
- 第一篇:你不一定了解的推荐系统
- okHttp3连接池简单使用
- springboot的学习笔记,这个很重要
- p12文件和mobileprovision文件导入到xcode如何使用
- 《RFID技术与应用》试题库(含答案)
- 考察数据结构——第三部分:二叉树和BSTs[译]
- c语言源文件经过编译后生成文件的后缀是什么?
- 还在用vuex吗,pinia(菠萝头)才香
- 互联网和人工智能之间,主要是什么关系?
- 2022世界杯看球指南
- 英语字母表及其冠词用法
- 如何在VM16上安装虚拟机(win7)及联网
- 大数据Spark(三):框架模块初步了解
- 脏读、重复读、幻读;
- 启发式搜索的实现,特性
- EXCEL函数之“VLOOKUP”
热门文章
- July文章《从头到尾彻底理解KMP(2014年8月22日版)》中,关于求解next数组,进一步理解如何递归前缀索引 k=next[k]
- 美国电视剧小超人剧情在线
- 吐秀山下,菜子湖畔,一年四季,家乡盛景
- PDF去除水印(1)-根据文本移除对象
- 微信小程序的抽奖页面
- 移除Selenium的浏览器window.navigator.webdriver等20多个指纹特征
- html+css实战181-header-logo和导航
- 自定义原生相机+拍照+GLSurfaceView+Camera
- 自动驾驶路径规划论文解析(1)
- 数字摄影测量学 计算航片邻接矩阵