编程珠玑之第三章习题5

来源:互联网 发布:c语言做游戏 编辑:程序博客网 时间:2024/05/17 06:32

问题描述:

5. 本习题处理英语中的一小部分连字符问题。下面所示的规则描述了以字母“c”结尾的单词的一些合法的连字符现象:
et-ic al-is-tic s-tic p-tic -ly-ic an-tic c-tic at-ic h-nic n-ic m-ic l-lic -clic l-ic h-ic f-ic d-ic -bic a-ic-mac i-ac
规则的应用必须按照上述顺序进行;因此,有连字符“eth-nic”(由规则“h-nic”捕获)和“clin-ic”(前一测试失败,然后满足“n-ic”).如何用函数来表达该规则?要求函数的输入为单词,返回值必须是后缀连字符。

问题解析:

1、对于给定的规则,要求按照顺序去遍历后缀连字符序列去查找后缀字符串,找到就返回,查找结束,不再往下进行。

2、查找规则的匹配,需要从右往左查找,在忽略连字符'-'的情况下如果后缀字符串完全匹配,则找到!

3、这里我将各个后缀字符串之间的空格换成了‘#’, 方便区分!

解决方案:

1、我从文件读取给定的规则,代码如下:

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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include <iostream>
#include <cstdio>
#include <cstdlib>  // exit()
#include <cassert>
#include <cstring>  // memset()
#include <cctype>   // strlen()

const int WORD_LENGTH   = 30;
const int DEFAULT_CAPACITY  =  1024;

#define error( str )         fatal_error( str )
#define fatal_error( str )   fprintf( stderr, "%s\n", str ), exit( 1 )

using namespace std;

/************************************************************************/
// 函数名称:create_postfix_lists
// 函数目的:创建后缀字符字符串序列
// 函数参数:fp指向文件的指针
// 函数返回:创建的字符串序列
// 使用条件:
/************************************************************************/

char* create_postfix_lists(FILE * fp)
{
    static char postfix_lists[DEFAULT_CAPACITY];
    int index = 0;
    while ( (postfix_lists[index] = getc(fp)) != EOF ){
        if ( isspace(postfix_lists[index]) ) {
            postfix_lists[index] = '#';    //  将空字符换成'#'
        }
        index++;
    }

    return postfix_lists;
}

/************************************************************************/
// 函数名称:myslice
// 函数目的:从给定的数组中获取后缀字符
// 函数参数:arr:要切割的数组 arraysize:数组长度  index_a\index_b:数组索引
// 函数返回:后缀字符
// 使用条件:
/************************************************************************/

char* myslice(const char* postfix_lists, int postfixlists_size, int index_a, int index_b)
{
    assert(index_a >= 0 && (index_b-index_a) >= 0 && index_b < postfixlists_size);

    static char postfix_chars[WORD_LENGTH];
    memset(postfix_chars, '\0', WORD_LENGTH);

    int index = 0;
    for (int i = index_a; i < index_b; i++){
        postfix_chars[index++] = postfix_lists[i];
    }

    //cout << postfix_chars << endl;
    return postfix_chars;
}

/************************************************************************/
// 函数名称:is_postfix_chars
// 函数目的:判断是否是后缀字符字符串
// 函数参数:word 单词   postfix_chars 一个后缀字符字符串
// 函数返回:如果是,返回true
// 使用条件:
/************************************************************************/

bool is_postfix_chars(const char* word, const char *postfix_chars)
{
    int i = strlen(word) -1;
    int j = strlen(postfix_chars) -1;

    while ( i >= 0 && j >= 0){
        if (postfix_chars[j] == '-'){   // '-'连字符的
            j--;  continue;
        }

        if ( word[i] == postfix_chars[j] ){ i--;  j--; }
        else { break; }
    }

    if (strlen(postfix_chars) > 0 && j == -1) {
            return true;
    }

    return false;
}

/************************************************************************/
// 函数名称:find_postfix
// 函数目的:从后缀字符字符串序列中查找给定单词的后缀字符串
// 函数参数:word 单词   postfix_chars 一个后缀字符字符串
// 函数返回:如果找到返回后缀字符串,如果找不到,返回NULL
// 使用条件:
/************************************************************************/

char* find_postfix(const char* word, const char *postfix_lists)
{
    size_t index_a = 0, index_b = 0;
    while (index_b < strlen(postfix_lists)){
        if (postfix_lists[index_b] == '#' || index_b == strlen(postfix_lists)-1 ) {

            char* postfix_chars = myslice(postfix_lists, strlen(postfix_lists), index_a, index_b);

            if (is_postfix_chars(word, postfix_chars)){ return postfix_chars; }

            index_a = index_b + 1;
        }

        index_b++;
    }

    return NULL;
}


int main()
{
    FILE* rfile = fopen("postfix_lists.txt""r");
    if (NULL ==  rfile){ fatal_error("不能打开postfix_lists.txt文件!\n"); }
    char* arr_lists = create_postfix_lists(rfile);
    fclose(rfile);

    cout << "给定的后缀连字符串序列是:" << arr_lists << endl;

    cout << "请输入单词:  ";

    char word[WORD_LENGTH];
    while (cin >> word){
        char* postfix_chars = find_postfix(word, arr_lists);
        cout << "单词" << word << "对应的后缀连字符是:" ;
        if (postfix_chars != NULL)
            cout << postfix_chars << endl;
        else
            cout <<"对不起,没找到!" << endl;

        memset(word, '\0'sizeof(word));
        cout << "请输入单词:  ";
    }


    return 0;
}
结果如下:


心得疑惑:

1、处理本题给定的问题关键是字符串划分.。

2、抱歉代码写的有点杂乱,有待优化!微笑

0 0