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


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

    强烈向大家推荐:

    步入正题。

    题目:

    给定一个英语词典,找出其中的所有的变位词集合,例如,“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 }
     

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

  • 相关阅读:
    Elastic的should + bool 多字段完全匹配或查找
    MySQL慢日志
    Elastic的IN查找
    Elastic的字符串查找
    JavaScript获取当前时间戳
    原码, 反码, 补码学习笔记
    PHP渲染压缩HTML
    JavaScript的深拷贝
    JavaScript的变量的let const var的区别
    关于一个值该不该default null的判定
  • 原文地址:https://www.cnblogs.com/cslave/p/2433630.html
Copyright © 2020-2023  润新知