最近在阅读编程珠玑,真是一本爱不释手的好书啊,对于实际编程中经常遇到的问题,引导读者去思考,去寻找最佳的解决方案。
废话不多说。问题描述如下:
给定一本英语单词词典请找出一个给定单词的所有变位词。例如“dog”这个单词,它的变位词可能有“dgo”,“ogd”,“god”等几个。书中给出的解决方案是给每个单词配一个标签。例如“dog”的吧标签是"d1g1o1",思想就是统计每个字母出现的次数。例如单词“totto”,那么它的标签是"t3o2",这样如果两个单词是变位词,那么他们的标签是一样的。
总结一下,我们需要做的是三件事。
1.对字典中的所有单词设置标签。
2.对字典中的字按照他们的标签排序。
3.对指定的单词实现变位词查找
代码如下:代码使用c++,编译环境是vs2010,可能代码中有不少用到stl知识的,看不懂的请自行脑补。
// 问题描述,给定一本字典和一个单词,找出字典中所有这个单词的变形体.如dog,如果字典中出现dgo,odg,等,那么符合查找条件
//1.为字典中字符串的每个单词设置签名,具有相同变形体的字符串的签名相同
//2.对所有字符串按照签名字典排序,在签名相同的情况下,按照字符串本身排序.
//问题来自编程珠玑第二章第一个问题,。查找效率一定要关注!计划两个小时完成。。。。
//yoghurt2014/7/26 武汉大学
//花了一个小时,实验成功单个单词的变形体索引。加上一个简单的循环,可以实现数组中所有的字符串
// 明天完成按照变形体索引排序。
//熟悉一下list下排序算法的使用。
#include<iostream>
#include <algorithm>
#include <vector>
#include <list>
#include <string>
#include <iterator>
using namespace std;
const int maxamount = 10000;
struct directionary{ //定义一个结构体
string word; //单词本身
string wordindex; //单词变形体编号
};
directionary findstring; //需要查找的单词,这里为了程序方便,我使用了结构体
bool sort_by_wordindex(const directionary *d1,const directionary *d2) //根据单词变形体编号排序
{
return d1->wordindex < d2->wordindex;
}
bool findwordindex(const directionary *d) //在字典中寻找和指定单词相同的单词变形体
{
return d->wordindex == findstring.wordindex;
}
void computewordindex(directionary &s) //计算单词的变形体编号,如“dog”,则变形体为“d1g1o1”
{
int array26[26] = {0}; //每个单词中字母出现的次数初始化为0
for (int i = 0; i < s.word.length();++i){ //统计单词中每个字母出现的次数
char c = s.word[i];
array26[int(c-'a')] ++;
}
int num = 0;
for (int i = 0 ;i < 26;++i){ //统计不一样字母的个数
if (array26[i])
num++;
}
s.wordindex.resize(num*2); //为变位词开辟存储空间
int n = 0;
for (int i = 0;i < 26;++i){
if (array26[i]){
//cout << char(i+'a');
s.wordindex[n++] = char(i+'a'); //把字母字符给变位词复制
//cout << array26[i];
s.wordindex[n++] = char(array26[i]+48); //把数字字符给变位词复制
}
}
}
int main()
{
int array26[26] = {0}; //代表一个字符串中每个出现的次数 如dogg,那么
directionary *d = new directionary[maxamount]; //初始化的字典中,有10000个单词,这差不多一般字典只有这么多了
d[0].word = "dog";
d[1].word = "odg";
d[2].word = "god";
d[3].word = "ogd";
for (int i = 4;i < maxamount;++i){
d[i].word = "jiajia";
}
d[800].word = "dgo";
//把元素装进list中啊。
list<directionary*>l; //这里我选择的容器list,好吧,我觉得最好的set,或者map容器,可以实现实现对数查找
for (int i = 0;i < maxamount;++i){
l.push_back(&d[i]);
}
list<directionary*>::iterator liteator;
for(liteator = l.begin();liteator !=l.end();++liteator){
for (int k = 0;k < 26;++k){
array26[k] = 0;
}
for (int i = 0; i < (*liteator)->word.length();++i){
char c = (*liteator)->word[i];
array26[int(c-'a')] ++;
}
int num = 0;
for (int i = 0 ;i < 26;++i){
if (array26[i])
num++;
}
(*liteator)->wordindex.resize(num*2);
int n = 0;
for (int i = 0;i < 26;++i){
if (array26[i]){
//cout << char(i+'a');
(*liteator)->wordindex[n++] = char(i+'a');
//cout << array26[i];
(*liteator)->wordindex[n++] = char(array26[i]+48);
}
}
}
//最后一步,实现对单个输入单词的所有变形词的查找.
cout << "input the string you want to find:";
cin >> findstring.word;
//计算这个单词的变形体。
computewordindex(findstring);
liteator = find_if(l.begin(),l.end(),findwordindex);
while(liteator!=l.end())
{
if ((*liteator)->word != findstring.word){ //同义词应该不包括自己。。。。
cout << "和" << findstring.word << "属于同义词的单词有:" << (*liteator)->word << endl;
}
liteator = find_if(++liteator,l.end(),findwordindex); //进行下一轮迭代.
}
delete []d;
return 0;
}
代码中的不足时应该使用set或者map容器的,因为这些容器自带的find函数,可以实现对数时间的查找,效率更高!!