### 问题描述
(来源于**《编程珠玑》第2版**的第2章第11页问题 C)
Given a dictionary of english words,find all sets of anagrams,For instance, “posts”,”stop”and ”tops” are all anagrams of one another because each can be formed by permuting the letters of the others.[译] 给定一个英语字典,找出其中的所有变位词集合。例如,“pots”、“stop”和“tops”互为变位词,因为每一个单词都可以通过改变其他单词中字母的顺序来得到。
### 方案一
按照书上给出的解法,先对每一个单词生成相应的“签名”(“signature”),即把单词中的字母按照字母表的顺序重新排列,例如stop 重新排列成opst , 然后把有相同signature的单词归为一组输出。基本过程如下:
![](https://box.kancloud.cn/bb1ebed78a023e8c8a09ceb0e78cb75d_588x185.png)
其中sign()函数用于生成每一个单词的”签名“,如何生成呢?由于每个单词的长度一般都很短(不超过10个字母)于是可选择用**直接插入排序法**。其他的数据结构和函数很简单,直接看代码吧!
### 代码:
~~~
#include<stdio.h>
#include<string.h>
#define MAX_WORD 100 /* the max length of a word */
#define MAX_NUM 100 /* the max number of words in a dictionary */
struct Word{
char ch[MAX_WORD];/*a word*/
char sig[MAX_WORD];/*signature*/
int flag;/*has been print or not*/
};
struct Word dic[MAX_NUM];
/*put in*/
int putin();
void putout(int count);
/*generate a word’s signature */
void sign(int count);
void insertSort(char * arr,int left,int right);
/* main() */
int main(void){
int count;
int i;
count=putin();
sign(count);
putout(count);
return 0;
}
int putin() {
int c=0;
while(scanf(“%s”,dic[c].ch)!=EOF)
{
strcpy(dic[c].sig,dic[c].ch);
dic[c].flag=0;
c++;
}
return c;
}
void sign(int count) {
int cnt,i,len;
for(cnt=0;cnt<count;cnt++)
{
len=strlen(dic[cnt].ch);
insertSort(dic[cnt].sig,0,len);
dic[cnt].sig[len]=‘\0′;
}
}
void insertSort (char * arr,int left,int right){
int i,j;
char temp;
for(i=left+1;i<right;i++){
if(arr[i-1]>arr[i]){
temp=arr[i];
j=i-1;
do{
arr[j+1]=arr[j];
j–;
}while(j>=left && arr[j]<temp);
arr[j+1]=temp;
}
}
}/* insertSort */
void putout(int cnt) {
int i,j;
for(i=0;i<cnt;i++){
if(dic[i].flag==0){
printf(“———-%s———-\n“,dic[i].sig);
printf(“%s\n“,dic[i].ch);
dic[i].flag=1;
for(j=0;j<cnt;j++){
if(strcmp(dic[i].sig,dic[j].sig)==0&&dic[j].flag==0){
dic[j].flag=1;
printf(“%s\n“,dic[j].ch);
}
}
}
}
}
~~~
### 方案二
我们获得的”啊哈!灵机一动“就是标识字典中的每一个词,使得在相同变位词类中的单词具有相同的标识。然后,将所有具有相同标识的单词集中在一起。这将原始的变位词问题简化为两个子问题:选择标识和集中具有相同标识的单词。 对第一个问题,我们可以使用基于排序的标识:将单词中的字母按照字母表顺序排列。要解决第二个问题,我们将所有的单词按照其标识的顺序排列。
### 代码:
~~~
#include <iostream>
#include <map>
#include <string>
#include <fstream>
using namespace std;
int compare_string(const void *a,const void *b){
return *((char*)(a)) - *((char*)(b));
}
void FindAnagram(char *file_name){
ifstream in_file(file_name);
string word_sort;
string word;
multimap<string,string> word_map;
while(in_file>>word){
word_sort = word;
qsort(word_sort.begin(),word_sort.length(),sizeof(char),compare_string);
word_map.insert(make_pair(word_sort,word));
}
multimap<string,string>::const_iterator iter = word_map.begin();
multimap<string,string>::const_iterator iter_end = word_map.end();
while(iter_end != iter){
cout<<iter->first<<":"<<iter->second<<endl;
++iter;
}
}
int main(){
FindAnagram("f://data.txt");
return 0;
}
~~~
**转载请注明出处:**[http://blog.csdn.net/utimes/article/details/8760350](http://blog.csdn.net/utimes/article/details/8760350)
- 前言
- 螺旋矩阵、螺旋队列算法
- 程序算法艺术与实践:稀尔排序、冒泡排序和快速排序
- Josephu 问题:数组实现和链表实现
- 杨辉三角形算法
- 位图排序
- 堆排序的实现
- Juggling算法
- 【编程珠玑】排序与位向量
- 取样问题
- 变位词实现
- 随机顺序的随机整数
- 插入排序
- 二分搜索
- 产生不重复的随机数
- 约瑟夫环解法
- 快速排序
- 旋转交换或向量旋转
- 块变换(字符反转)
- 如何优化程序打印出小于100000的素数
- 基本的排序算法原理与实现
- 利用马尔可夫链生成随机文本
- 字典树,后缀树
- B-和B+树
- 程序算法艺术与实践引导
- 程序算法艺术与实践:基础知识之有关算法的基本概念
- 程序算法艺术与实践:经典排序算法之桶排序
- 程序算法艺术与实践:基础知识之函数的渐近的界
- 程序算法艺术与实践:递归策略之矩阵乘法问题
- 程序算法艺术与实践:递归策略之Fibonacci数列
- 程序算法艺术与实践:递归策略基本的思想
- 程序算法艺术与实践:经典排序算法之插入排序
- 程序算法艺术与实践:递归策略之递归,循环与迭代