变位词程序的设计与实现---编程珠玑第二章读后感

清明节期间无事,想起以前买的几本书,就好好看了看,老实说编程珠玑写的不错

强烈向大家推荐:

步入正题。

题目:

给定一个英语词典,找出其中的所有的变位词集合,例如,“pots”“stop”“tops”互为变位词,因为每一个单词都可以通过改变其他单词中字母的顺序来得到。

初次结识这个题目,我以为是简单的排列,这个很简单嘛,就是把一个单词的字母全排列一边,然后就罗列了所有的组合,刷刷写下程序,下面是我的几个全排列程序,有两种种方法,一种是自己实现的,另外一种是调用next_permutation:

代码如下:

View Code
 1 #include <stdio.h>
2 #include <algorithm>
3 using namespace std;
4 void print_permutation(int n,int* A,int cur) //
5 {
6 int i,j;
7 if(cur==n)
8 {
9 for(i=0;i<n;++i)
10 printf("%d ",A[i]);
11 printf("\n");
12 }
13 else for(i=1;i<=n;++i)
14 {
15 int ok=1;
16 for(j=0;j<cur;++j)
17 if(A[j]==i) ok=0;
18 if(ok)
19 {
20 A[cur]=i;
21 print_permutation(n,A,cur+1);
22 }
23 }
24 }
25
26
27 void char_permutation(int n,char *C,char *arr,int cur)
28 {
29 int i,j;
30 if(cur==n)
31 {
32 for(i=0;i<n;++i)
33 printf("%c ",arr[i]);
34 printf("\n");
35 }
36 else for(i=0;i<n;++i)
37 {
38 int ok=1;
39 for(j=0;j<cur;++j)
40 if(arr[j]==C[i]) ok=0;
41 if(ok)
42 {
43 arr[cur]=C[i];
44 char_permutation(n,C,arr,cur+1);
45 }
46 }
47 }
48
49 int _tmain(int argc, _TCHAR* argv[])
50 {
51 int A[10]={1,2,3,4,5,6,7,8,9,10};
52 char C[12]={'s','t','o','p','u','g','d','z','s','t','b','v' };
53 char arr[8];
54 //char_permutation(8,C,arr,0);
55 //print_permutation(10,A,0);
56 while(next_permutation(C,C+12))
57 {
58 for(int i=0;i<12;++i)
59 printf("%c ",C[i]);
60 printf("\n");
61 }
62 return 0;
63 }
64
65
66


 

然后发现不对啊,人家是要找英语词典的已存在的单词之间的变位词关系。而不是说给出字母,求变位词集合有多大。后悔自己太武断了,没有理解清楚题意。仔细研读下书本,

字典中有很多单词,我们可以把字典看作是一本书,书是什么,是文件,因此,我们可以从一个文件中读取由一堆单词组成的集合,好了,如何判断同位词,如果采用一个单词全排列然后在在字典查询的方案,作者的字典单词数目是 2300000个,仅考虑一种情况,有22个字母组成的单词,有22!的组合,22!≈1.124*10^21,即使假设以闪电一样的速度每百亿分之一秒执行一种排列,这也要消耗数十年,那么换一种策略,采用逐个比对,假设简单的变位词比较耗时一微妙,那么总时间是230 000*230 000*1us =52900*10^6=14.7小时,还是很大。

因此作者提出了新的算法。如下图

pants                                       anps pants                          anps pants

pots                                        opst pots                             anps snap                           pans snap

opt             ------sign函数----> opt opt   ------sort函数---->  opt opt   -------输出--->      opt

snap                                        anps snap                            opst pots                            pots stop tops

stop                                        opst stop                              opst stop

tops                                        opst tops                              opst tops

sign函数是抽象出每一个变位词集合的标准型,sort是对标准型排序,然后输出个变位词集合元素。

 

首先对每个单词来一次单词中的字母排序,给所有待排序的变位词集合总结一个标准型,我们形象称呼他为“党员”,党员代表同一类的变位词集合参与识别,根据每个单词隶属党员的不同,进而确定他属于哪一类集合。简单说,党员就是集合的标识

我们需要对党员来排序,然后,输出党员代表的变位词集合。但是问题来了,我们排序了党员,但是无法保证群众还是跟党走,比如说我们排序了anps 如何来保证pants和snap作为他的伴随数组呢,因此我们要解决跟党走的问题。我想到了multimap 这个STL容器真的是非常好用,将党员作为主键,字典单词作为伴随成员。

代码如下:

View Code
  1 #include<stdlib.h>
2
3 #include<map>
4
5 #include<string>
6
7 #include<algorithm>
8
9 #include<iostream>
10
11 #include<iomanip>
12
13
14
15 #define LOCAL
16
17 #define WORDMAX 100
18
19 usingnamespace std;
20
21
22
23
24
25 int charcomp(constvoid *x,constvoid *y)
26
27 {
28
29 return (*(char *)x-*(char *)y);
30
31 }
32
33
34
35 int strcomp(constvoid *x,constvoid *y)
36
37 {
38
39 return strcmp((char *)x,(char *)y);
40
41 }
42
43
44
45
46
47
48
49 void Sign(char (*word)[20],char (*sig)[20],int n)
50
51 {
52
53 for(int i=0;i<n;++i)
54
55 {
56
57 qsort(sig[i],strlen(sig[i]),sizeof(char),charcomp);
58
59 printf("%s %s",sig[i],word[i]);
60
61 printf("\n");
62
63 }
64
65 }
66
67
68
69
70
71
72
73 void Sort(char (*word)[20],char (*sig)[20],int n)
74
75 {
76
77 qsort(sig,n,sizeof(sig[0]),strcomp);
78 }
79
80
81
82 int _tmain(int argc, _TCHAR* argv[])
83
84 {
85
86 #ifdef LOCAL
87
88 freopen("data.txt","r",stdin);
89
90 #endif
91
92 char sig[WORDMAX][20],word[WORDMAX][20];
93
94 char tmp[20];
95
96 int i=0,n=0;
97
98 while(scanf("%s ",tmp)!=EOF) //此处有可能溢出
99
100 {
101
102 strcpy(sig[i],tmp);
103
104 i++;
105 }
106
107 for(;n<i;++n)
108
109 strcpy(word[n],sig[n]);
110
111
112
113 Sign(word,sig,n);
114
115 Sort(word,sig,n);
116
117 #ifndef LOCAL
118
119 multimap<string,string> sig_word;
120
121 for( i=0;i<n;++i)
122
123 sig_word.insert(make_pair((string)(sig[i]),(string)(word[i])));
124
125 multimap<string,string>::iterator pos;
126
127 for(i=0;i<n;++i)
128
129 {
130
131 if(i!=0&&!strcmp(sig[i],sig[i-1])) continue;
132
133 cout<<sig[i]<<": "<<endl;
134
135 for(pos=sig_word.lower_bound((string)(sig[i]));pos !=sig_word.upper_bound((string)(sig[i]));++pos)
136
137 cout<<""<<pos->second<<endl;
138 }
139
140 #endif
141
142
143
144 #ifdef LOCAL
145
146 multimap<char *,char *> sig_word;
147
148 for( i=0;i<n;++i)
149
150 sig_word.insert(make_pair(sig[i],word[i]));
151
152 multimap<char *,char *>::iterator pos;
153
154 for(i=0;i<n;++i)
155
156 {
157
158 if(i!=0&&!strcmp(sig[i],sig[i-1])) continue;
159
160 cout<<sig[i]<<": "<<endl;
161
162 for(pos=sig_word.lower_bound(sig[i]);pos !=sig_word.upper_bound(sig[i]);++pos)
163
164 cout<<""<<pos->second<<endl;
165
166 }
167
168 #endif
169
170 return 0;
171
172 }

 

 

 

编程珠玑是一本好书,要从头到尾好好看一遍。上述两个开关的地方都可以做,所以采用开闭原则

posted on 2012-04-05 19:50  北冥茶花开  阅读(597)  评论(2编辑  收藏  举报

导航