第 2 章 第 6 题 通讯录模糊检索问题 标识法实现

问题分析

  输入:名字的数字标识

  输出:通讯录中所有和该标识匹配的记录

  约束:错误匹配的概率不能太高

解答思路

  1. 给通讯录中的记录附加上标识字段( 数字 )

  2. 将通讯录中的记录按照标识字段进行排序

  3. 用户输入要查找的人的名字的标识字段( 这里的标识字段类型要经过整理才能转换为 1 中的标识字段类型 详见下面代码的相关部分注释 )

  4. 顺序输出所有和 3 中标识字段匹配的记录

代码实现

  1 #include <iostream>
  2 #include <fstream>
  3 #include <string>
  4 #include <map>
  5 
  6 using namespace std;
  7 
  8 // 初始化通讯录函数
  9 // --- 为每个记录附加一个标识符字段
 10 void init( multimap<string, string> &m, fstream &io );
 11 
 12 // 标识符获取函数
 13 // --- 将名字字符串转化为对应的标识符
 14 string getST( const string & name );
 15 
 16 // 查询记录函数
 17 // --- 根据用户给定的标识符,检索通讯录并输出结果。
 18 void search( multimap<string, string> &m, string &st );
 19 
 20 int main(void)
 21 {
 22     // 打开通讯录
 23     string filename;
 24     cout << "输入要创建的数据文件名: " << endl;
 25     cin >> filename;
 26 
 27     fstream io;
 28     io.open(filename.c_str());
 29     if (!io) {
 30         cout << "打开文件失败!" << endl;
 31         return 1;
 32     }
 33 
 34     // 初始化通讯录
 35     multimap<string, string> m;
 36     init(m, io);
 37 
 38     // 获取用户输入标识符
 39     string st;
 40     cout << "请输入要查找人名的数字标识符: ";
 41     cin >> st;
 42 
 43     // 检索通讯录并输出结果
 44     search(m, st);
 45 
 46     // 关闭文件流
 47     io.close();
 48 
 49     return 0;
 50 }
 51 
 52 void init(multimap<string, string> &m, fstream &io) {
 53     string name;
 54     string st;
 55 
 56     // 遍历通讯录,并将各组信息及对应标识符存入 multimap 表中。
 57     while (io >> name) {
 58         st = getST(name);
 59         m.insert(make_pair(st, name));
 60     }
 61 
 62     return;
 63 }
 64 
 65 string getST(const string & name) {
 66     string st = "000000000";
 67 
 68     for (int i=0; i<name.length(); i++) {
 69         if (name[i] == 'a' || name[i] == 'b' || name[i] == 'c') 
 70             st[0]++;
 71         if (name[i] == 'd' || name[i] == 'e' || name[i] == 'f') 
 72             st[1]++;
 73         if (name[i] == 'g' || name[i] == 'h' || name[i] == 'i') 
 74             st[2]++;
 75         if (name[i] == 'j' || name[i] == 'k' || name[i] == 'l') 
 76             st[3]++;
 77         if (name[i] == 'm' || name[i] == 'n' || name[i] == 'o')
 78             st[4]++;
 79         if (name[i] == 'p' || name[i] == 'q' || name[i] == 'r')
 80             st[5]++;
 81         if (name[i] == 's' || name[i] == 't' || name[i] == 'u')
 82             st[6]++;
 83         if (name[i] == 'v' || name[i] == 'w' || name[i] == 'x')
 84             st[7]++;
 85         if (name[i] == 'y' || name[i] == 'z') 
 86             st[8]++;
 87     }
 88 
 89     return st;
 90 }
 91         
 92 void search( multimap<string, string> &m, string &st )
 93 {
 94     // 将用户输入的标识符格式转换成内存中存放的标识符格式
 95     string st1 = "000000000";
 96     for (int i=0; i<st.length(); i++) {
 97         int t = (int)st[i] - (int)'0';
 98         st1[t]++;
 99     }
100 
101     // 检索通讯录,并获取结果范围。
102     multimap<string, string> :: iterator up, low;
103     low = m.lower_bound(st1);
104     up = m.upper_bound(st1);
105 
106     // 切记要加入以下程序段,否则可能会因为无法读取下面的 low->first 而发生错误。
107     if (low == up && low == m.end()) {
108         cout << "无任何匹配记录" << endl;
109         return;
110     }
111 
112     // 打印检索到的记录
113     cout << endl << "找到如下人名: " << endl;
114     while (low->first != up->first) {
115         cout << low->second << endl;
116         low++;
117     }
118 
119     cout << endl << endl;
120 
121     return;
122 }

运行测试

  1. 建立带有如下记录的通讯录( 普通文本格式 )

  

  2. 按照以下规则:

  abc  0  def  1  ghi  2  jkl  3  mno  4

  pqr  5  stu  6  vwx  7  yz  8

  建立并输入要查询的人名的标识符,如要查 fangmeng ,则可输入 10424142 并获取查询结果:  

  

小结

  1. 通过修改标识符的生成格式比对规则,可以形成不同的模糊匹配规则。使用何种模糊匹配规则应结合具体情况决定。

  2. 标识法的灵活性体现在可以根据不同的需要建立不同意义的标识

 

 

posted on 2014-04-02 15:37  空山悟  阅读(190)  评论(0编辑  收藏  举报

导航