解决这个问题的许多方法都出奇地低效和复杂。任何一种考虑单词中所有字母的排列的方法都注定了要失败。
eg:单词 “cholecystoduodenostomy” 有 22!(= 1.124*10^21) 种排列即使以闪电一样的速度第百亿分之一秒执行一种排列,也要消耗 1.1*10^9 秒。
秒就是一个纳世纪,则 1.1*10^9 秒就是数十年
啊哈!灵机一动。。。
第一、标识字典中的每一个词,使得在相同变位词类中的单词具有相同的标识
第二、将所有具有相同标识的单词集中在一起
对于第一个问题,我们可以使用基于排序的标识:将单词的字母按照字母表顺序排列。
eg:“deposit” 的标识就是 “deiopst”,这也是 “dopiest” 和其他任何在该类中的单词的标识。
要解决第二个问题,我们将所有的单词按照其标识的顺序排序。我所知道的关于该算法的最好的描述就是 Tom Cargill 的翻手表示:先用一种方式排序(水平翻手),再用另一种方式排序(垂直翻手)
原理分析:
排序。排序最显而易见的用处就是产生有序的输出。该输出既可以是系统规范要求的一部分,也可以是另一个程序(也许是一个二分搜索程序)的前期准备工作。但是在变位词问题中,排序并不是关注的焦点。排序是为了将相等的元素(本例中为标识)集中到一起。这些标识产生了另外一个排序应用:将单词内字母排序使得同一个变位词类中的单词具有标准型。通过给每条记录添加一个额外的关键字,并按照这些关键字进行排序,排序函数可以用于重新排列磁盘文件中的数据。
二分搜索。该算法在有序表中查找元素时极为高效。并且可用于内存排序或磁盘排序。唯一的缺陷就是整个表必须已知并且事先排好序。
标识:当使用等价关系来定义类时,定义一种标识使得类中的每一项都具有相同的标识,而该类以外的其他项则没有该标识,这是很有用的。对单词中的字母排序可以产生一个用于变位词类的标识。其他标识通过排序给出。然后使用一个计数来代表重复的次数(于是标识 “mississippi” 可以写成 “i4m1p2s4” 或将1省略 ---- “i4mp2s4”)。也可以使用一个包含26个整数的数组来标识每个字母出现的次数。标识的其他应用包括:美国联邦调查局用来索引指纹的方法,以及用来识别读音相同但是拼写不同的名字的 Soundex 启发方法:
![](https://img-my.csdn.net/uploads/201205/07/1336373399_7011.png)
变位词程序的操作流程演示
我的变位词程序按三个阶段的 “管道”组织,其中一个程序的输出文件作为下一个程序的输入文件。第一个程序标识单词,第二个程序排序标识后的文件,而第三个程序将这些单词压缩为每个变位词类一行的形式。
eg:仅有6个单词的字典的处理过程
![](https://img-my.csdn.net/uploads/201205/07/1336376635_3742.png)
需要做的工作:
1 . 对单词文件做预处理(大写字母全部转换为小写字母)
2 . 对单词中的字母,以升序排序,生成单词对应的 “标识”
3. 通过系统 sort 程序 对标识以升序排序 (将所有 具有相同标识的单词归拢在一起)
4. 将 具有相同标识的单词归为一类
5. 任意输入一个单词,通过 第“2”步的方法生成单词对应的 “标识”,用二分查找法,在第 “4” 步生成的单词类中找到该单词的变位词