编程珠玑之第二章习题6

来源:互联网 发布:域名备案批量查询 编辑:程序博客网 时间:2024/05/16 17:19

问题描述:

20世纪70年代末期,贝尔实验室开发出了“用户操作的电话号码簿辅助程序”,该程序允许雇员使用标准按键电话在公司电话号码簿中查找电话号码。要查找该系统设计者的名字Mike Lesk,可以按“LESK*M*”(也就是“5375*6*”),随后,系统会输出他的电话号码。这样的服务现在随处可见。该系统中出现的一个问题是,不同的名字有可能具有相同的按键编码。在Lesk的系统中发生这种情况时,系统会询问用户更多的信息。给定一个大的名字文件(例如标识的大城市电话号码簿),如何定位这些“错误匹配”呢?(当Lesk在这种规模的电话号码簿上做实验时,他发现错误匹配发生的概率仅仅是0.2%。)如何实现一个以名字的按键编码为参数,并返回所有可能匹配名字的函数?

问题解析:

1、标准的按键电话中,按键与字母是一对多的映射关系(如:2——>A B C) 那么以按键作为标识,对电话簿中的人名进行标识,那么每个人名就有了一个唯一的标识。

2、有了标识,那么就可以创建对应的结构了,诸如:(标识, 用户文件(用户名,电话,地址等)); 这里标识——用户文件是一对多的关系。

3、所有的用户文件加入到该结构中后,依标识排序(用户名排序),排好序就可以在用户输入时,采取二分搜索来查找对应的用户文件了。

解答方案:

不完整解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#include <cstdio>
#include <cstdlib>      // qsort
#include <cctype>       // toupper\tolower
#include <cstring>      // strlen
#include <cassert>      // assert

#define     MAXUSERNUM  1000        // 用户数
#define     WORDMAX     100         // 姓名最大长度
#define     MAXNUMBER   10          // 标识相同的用户数
#define     PHONELEN    11          // 电话长度
#define error( str )         fatal_error( str )
#define fatal_error( str )   fprintf( stderr, "%s\n", str ), exit( 1 )


/************************************************************************/
// 函数名称:chartonum
// 函数目的:获取对应字符的标识
// 函数参数:字符ch
// 函数返回:字符ch对应的标识
// 使用条件:
/************************************************************************/

char chartonum(char ch)
{
    if (!isalpha(ch))  return '0';

    switch(toupper(ch)){
    case 'A'case 'B'case 'C':  return '2';
    case 'D'case 'E'case 'F':  return '3';
    case 'G'case 'H'case 'I':  return '4';
    case 'J'case 'K'case 'L':  return '5';
    case 'M'case 'N'case 'O':  return '6';
    case 'P'case 'Q'case 'R':  case 'S':  return '7';
    case 'T'case 'U'case 'V':  return '8';
    case 'W'case 'X'case 'Y':  case 'Z':  return '9';
    defaultbreak;
    }

    return '0';
}

/************************************************************************/
// 函数名称:getsign
// 函数目的:获得输入姓名对应的标识
// 函数参数:sign:姓名标识 fullname:姓名
// 函数返回:姓名标识
// 使用条件:fullname格式为由两个单词组成,姓在前,名在后,中间用空格隔开
//           比如:Hu Johnny 、Green Jim、Lesk Mike
/************************************************************************/

char* getsign(char* sign, char* fullname)
{
    while (isspace(*fullname)) { fullname++; } // 先去除前面的空格

    bool bspace = false;
    while (*fullname != '\0'){
        if (bspace == true) {
            if (isspace(*fullname)) { fullname++; continue; }
            else {
                *sign++ = chartonum(*fullname); *sign++ = '*';
                fullname++; break;
            }
        }

        if (isspace(*fullname)) {
            bspace = true; *sign++ = '*';
            fullname++; continue;
        }

        if (isalpha(*fullname)){ *sign++ = chartonum(*fullname);}
        fullname++;
    }
    *sign = '\0';

    return sign;
}

int main()
{
    char fullname[WORDMAX], sign[WORDMAX];

    printf("please input a fullname:\n");
    while (fgets(fullname, WORDMAX, stdin) != NULL && fullname[0] != '\n'){
        char* ch= strchr(fullname, '\n');  // 查找换行符
        if (ch) { *ch = '\0'; }  // 删除换行符

        getsign(sign, fullname);

        printf("fullname--->sign: %s--->%s\n", fullname, sign);
        printf("please input a fullname:\n");
    }

    
输出结果:


这里我只实现了怎样将姓名与标识进行映射,其他的还来得及实现,所有电话用户信息的存储可以创建一个结构体,之后可以用C++的map来完成该存储、排序等操作,如果使用纯的C语言,可以自己实现List进行存储,以后有时间在说!

心得疑惑:

1、怎样改用散列来实现该程序?数据库系统呢?


1 0