树与查找专题讨论2
集美大学树与查找专题讨论2
| 项目名称 | 内容 |
|---|---|
| 课程名称 | 数据结构 |
| 班级 | 网安2511、2512 |
| 学号 | 202521336002 |
| 学号 | 202521336035 |
| 实验项目名称 | 手机通讯录问题 |
一、目的(本次实验所涉及并要求掌握的知识点)
- 理解树的存储结构、核心原理,掌握插入、前缀查询等基本操作。
- 学习利用树解决字符串前缀匹配问题的方法替代遍历的暴力算法。
- 学习实现手机通讯录的前缀检索功能,完成初始化、姓名插入、前缀查询等核心功能。
- 理解算法优化思想,掌握树在实际场景中的应用。
二、自然语言描述查找过程
- 从根节点开始查找,在前缀字符串中从左到右读取字符,依次在树中进行匹配。
- 取出需要匹配的字符,检查当前所在节点的子节点中,是否存在匹配的节点。如果找不到对应节点,返回空;如果找到,就继续移动到子节点上继续匹配下一个前缀字符。
- 匹配完所有字符后,停留在所有以查找的前缀开头姓名的公共节点上。
- 从这个公共节点开始遍历所有子节点,将节点存储的信息记录下来,直到把所有姓名都找完。
- 将收集到的结果整理成列表,并返回。
三、实验内容与设计思想
树结构体
相关伪代码
treenode
child:【字符→子节点】的映射表 //存储当前字符对应的子节点
isEnd: 布尔值 // 标记:是否是某个姓名的最后一个字符
fullName: 字符串 // 存储完整的联系人姓名
节点初始化,isEnd = false,fullName = 空字符串
代码
struct treenode {
unordered_map<char, treenode*>child;
bool isend;
string fullname;
treenode():isend(false),fullname(""){}
};
模块1:姓名插入函数
函数相关伪代码
insert(name字符串)
temp=root // 从根节点开始遍历
// 逐个遍历姓名的每一个字符
for(char ch:name)
// 如果当前节点没有 ch 对应的子节点,就新建一个
if temp.child中不存在键ch
创建ch对应的子节点
移动到子节点,继续处理下一个字符
遍历完所有字符,标记为姓名结尾,并存储完整姓名
函数代码
void insert(const string& name) {
treenode* temp = root;
for (char ch : name) {
if (temp->child.find(ch) == temp->child.end()) {
temp->child[ch] = new treenode();
}
temp = temp->child[ch];
}
temp->isend = true;
temp->fullname = name;
}
模块2:前缀匹配函数
函数相关伪代码
match(index字符串)
result = 空字符串列表 // 存储最终匹配结果
temp=root 创建遍历指针指向根节点
// 逐个遍历前缀的每一个字符
for(char ch:index)
// 如果找不到对应字符,说明无匹配,直接返回空列表
if temp.child 中 不存在 键 ch
return result
移动到子节点,继续匹配
前缀匹配完成,递归搜索该节点下所有姓名
// 返回所有匹配的姓名
return result
函数代码
vector<string> match(const string& index) {
vector<string> result;
treenode* temp = root;
for (char ch : index) {
if (temp->child.find(ch) == temp->child.end()) {
return result;
}
temp = temp->child[ch];
}
search(temp, result);
return result;
}
模块3:搜索收集匹配前缀姓名函数
函数相关伪代码
search(node,result字符串列表)
// 如果当前节点是姓名结尾,把完整姓名加入结果
if(node->isend==true)
将 node->fullName 添加到 result 中
// 遍历当前节点的所有子节点,递归搜索
for(auto& pair:node->child)
search(子节点,result)
函数代码
void search(treenode* node, vector<string>& result) {
if (node->isend) {
result.push_back(node->fullname);
}
for (auto& pair : node->child) {
search(pair.second, result);
}
}
四、时间复杂度
模块1:姓名插入函数
- 遍历姓名字符m次循环,时间复杂度为O(m)
模块2:前缀匹配函数
- 遍历前缀共n个字符,遍历所有匹配姓名访问k个结果对应节点,时间复杂度为O(k+n)
模块3:搜索收集匹配前缀姓名函数
- 遍历子树,收集所有匹配的姓名,时间复杂度为O(t)
五、实验步骤和调试过程(实验步骤、测试数据设计、测试结果分析)
本机运行截图


六、总结
- 学会了使用c++实现手机通讯录的简易功能。
- 理解了树的前缀查询效率之高,时间复杂度仅跟前缀长度和结果数量有关。
- 掌握了树的插入、深度搜索遍历等操作,理解了树形结构在处理字符串方面的优势。

浙公网安备 33010602011771号