本文主要分享算法设计思路,其中代码均原创,供大家参考和学习
文章目录
前言
开始学习数据结构的时候,很多像顺序表、二叉树、邻接链表的结构学会了完全不知道该在什么地方使用。到学习算法一段时间,做了些题目后,发现自己还是需要阅读一些博客和以前写过的数据结构去“启发式”的引导自己解决问题。其实我们一开始在学习数据结构的时候就应该去思考每个数据结构可以应用的场景,这样学习数据结构才有意思,才能“玩转数据结构”。
通讯录的拼音搜索也是我们常用的场景,“常用”、“不起眼”、但“有意思”。本项目也是我在大二数据结构课程设计的选题,分享一下我的思想给大家。
提示:问题描述很重要,大家以后做算法或者开发也一定要关注问题描述!!!
一、问题描述
1.概述
我们作为个人每天都使用通讯录(包括微信、qq中的通讯录),但考虑一个比较大的场景,许多大型企业也拥有企业的通讯录,可能有上千甚至上万人的名录,那么我们就希望做设计一个快速检索算法,能够通过输入部分的关键字的首拼字母快速的过滤出你想要的联系人。
2.具体要求
- 每个人的姓名可以从第一个字开始匹配,也可以从后面的字开始匹配,如“关云长”可以考虑“guanyun”,“guanyinchang”,“yunchang”,但不能考虑断开的情况,如“guanchang”。
- “多音字”匹配的所有可能,如“chang”可以考虑“zhang”和“chang”。(这里解释一下,为什么“chang”不单独只匹配“chang”,因为很多时候我们存了含多音,要保证假设用户不会“读”的情况下,仍然可以搜索到。)
- 每个汉字的音节可以只匹配部分前缀,如“关云长”可以用“gyc” ,“guyuchang”,“yunchang”,“yuc”得到匹配。
- 实现排序显示
- 相关数据结构、算法:哈希表,顺序表,递归回溯
二、数据存储方案
1.名字对应的音节组合
存储名字的每个字对应的音节采用“字符串”类型的顺序表“StringList”存储元素。一个顺序表结构存处一个名字的读音组合,比如“guanyunchang”可以存储为一个顺序表结构,“guan”存入item[0],“yun”存入item[1],“chang”存入item[2]。可以通过item[0][0]访问到‘g’。
其实这里也可以采用字符串类型数组,但是毕竟学习了数据结构,想练习一下顺序表的使用,并且自己写的顺序表在使用上更加灵活。
//顺序表
struct StringList {
string* item;
int capacity;
int length;
//构造函数
StringList(int c=10) {
capacity = c;
length = 0;
item = new string[capacity];
}
//添加元素
void append(string s) {
if (length == capacity) {
capacity += 10;
item = new string[capacity];
}
item[length++] = s;
}
//返回指定位置index的元素
string getItem(int index) {
return item[index];
}
//显示全部元素
void show() {
for (int i = 0; i < length; i++) {
cout << item[i] << " ";
}
cout << endl;
}
};
2.拼音库
拼音库可以用哈希表结构存储,这里用二维数组存储。
string hashs[Max_size][Max_size];//拼音库hashs表
C++处理拼音库(不如Java和C#方便),我采用的拼音表我提前处理过,我在这里给出资源链接。(大家下载保存为txt文件,设置ANSI编码格式)
读取拼音表的方式(我的方式,大家可以参考,避免大家踩坑!)
//初始化hashs拼音库表
void initHashMap() {
string str;
ifstream inf;
//保存为ANSI编码格式
inf.open("yinjie.txt");
while (getline(inf, str