第二章 啊哈!算法(变位词)

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

“解决这个问题的许多方法都出奇地低效和复杂。任何一种考虑单词中所有字母的排列的方法都注定了要失败。而比较所有单词对的任何方法在我的机器上运行至少要花费一整夜的时间。”

我们获得的”啊哈!灵机一动“就是标识字典中的每一个词,使得在相同变位词类中的单词具有相同的标识。然后,将所有具有相同标识的单词集中在一起。这将原始的变位词问题简化为两个子问题:选择标识和集中具有相同标识的单词。

对第一个问题,我们可以使用基于排序的标识:将单词中的字母按照字母表顺序排列。要解决第二个问题,我们将所有的单词按照其标识的顺序排列。

书中的程序按照三阶段的”管道“组织,其中一个程序的输出文件作为下一个程序的输入文件。第一个程序sign()直接写在main函数里来标识单词,第二个程序排序sort()标识后的文件,而第三个程序squash()将这些单词压缩为每个变位词类一行的形式。

程序有一些局限在于要事先输入单词的个数,以for循环让输入停止,而且输入单词的长度不能长于20位。

// 实现变位词程序

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX 20
 
char *wordlist[MAX];
char *signlist[MAX];
//static int n;

int charcmp(const void *x, const void *y)
{
    return *(char *)x-*(char *)y;
} 

int stringcmp(const void *x, const void *y)
{
    return strcmp((char *)x,(char *)y);
}

void sort(int num)
{
     int i,j;
     char *temp1=NULL, *temp2=NULL;
     //int n=sizeof(signlist)/sizeof(signlist[0]);
     //printf("%d\n",num);
     //qsort(signlist, num, sizeof(char *), stringcmp);
     
     //交换法排序
     
     for(i=0;i<num;i++)
     {
                       for(j=i+1;j<num;j++)
                       {
                                           if(strcmp(signlist[j],signlist[i])<0)
                                           {
                                                                              temp1=signlist[i];
                                                                              signlist[i]=signlist[j];
                                                                              signlist[j]=temp1;
                                                                              temp2=wordlist[i];
                                                                              wordlist[i]=wordlist[j];
                                                                              wordlist[j]=temp2;
                                           }
                       }
     }
     
     for(i=0;i<num;i++)
         printf("%s %s\n",signlist[i],wordlist[i]);
}

void squash(num)
{
     int i;
     //char *Old=NULL, *New=NULL;
     char Old[MAX], New[MAX];  //利用字符数组而不是字符指针 
     for(i=0;i<num;i++)
     {
                       if(i==0)
                       {
                              strcpy(Old,signlist[i]);
                              //strcpy(Old,signlist[i]);
                              //Old=signlist[i];
                              printf("%s ",wordlist[i]);
                       } 
                       else
                       {
                            strcpy(New,signlist[i]);
                            //New=signlist[i];
                            if(strcmp(New,Old)==0)
                                printf("%s ",wordlist[i]);
                            else
                            {
                                printf("\n");
                                strcpy(Old,signlist[i]);
                                //Old=signlist[i];
                                printf("%s ",wordlist[i]);
                            }
                       }
     }
}

// 输入一组单词,产生字典序标识的单词组 
// scanf()按s格式符将字符串作为一个整体输入/输出:空格、回车或跳格(Tab)符作为输入数据的分隔符,因而不能被
// 读入,输入遇到这些字符时,系统认为输入结束 
int main()
{
    int n;
    char word[MAX], sign[MAX];
    //int i=j=0; 首先是输入然后转化为sign()
    int i,j;
    printf("Please input how many words are you going to input:");
    scanf("%d",&n);
    printf("Please input the words :\n");
    //while(scanf("%s",&word)!=EOF)
    for(i=0;i<n;i++)
    {
                                 //scanf("%s",wordlist[i]);
                                 scanf("%s",&word);
                                 wordlist[i]=(char *)malloc(sizeof(word));
                                 strcpy(wordlist[i],word);
                                 //strcpy(wordlist[i],word); 指针没有指向固定的位置 
                                 //wordlist[i]=word;
                                 //strcpy(word,)
                                 strcpy(sign, word);
                                 qsort(sign, strlen(sign), sizeof(char), charcmp);
                                 signlist[i]=(char *)malloc(sizeof(sign));
                                 strcpy(signlist[i],sign);
                                 //signlist[i]=sign;
                                 //strcpy(signlist[i],sign);
                                 //qsort(word, sizeof(word), sizeof(char), charcmp);  //指针没有指向固定的位置 
                                 //strcat(orderword[i], word);
                                 //i++;
                                 //printf("%s %s\n", word, sig);
                                 printf("%s %s\n",wordlist[i],signlist[i]);
                                 //i++;
    }
    printf("\n");
    //for(j=0;j<n;j++)
        //printf("%s %s\n",wordlist[j],signlist[j]);//
    /*
    while(strcmp(orderword[j],"\0"))
    {
                                    printf("%s\n",orderword[j]);
                                    j++;
    }
    */
    sort(n);
    //printf("%s %s\n",wordlist[i],signlist[i]);
    printf("\n");
    squash(n);
    for(i=0;i<n;i++)
    {
                    free(wordlist[i]);
                    free(signlist[i]);
    }
    return 0;
}

/* Test for the strcpy function
int main()
{
    char word[MAX], *p;
    scanf("%s", word);
    //strcpy(p,word);
    p=word;
    printf("%s", p);
    //printf("%c",*p);
    
    return 0;
}
*/
// Test for the sort algorithm
/*
int main()
{
    int i;
    char *word[]={"Pascal","Basic","Fortran","Java","Visiual C"}; //不需要定义数组的大小 
    int n=sizeof(word)/sizeof(word[0]);
    printf("%d\n",n);
    qsort(word, n, sizeof(char *), stringcmp);
     for(i=0;i<n;i++)
         printf("%s\n",word[i]);
    return 0;
} 
*/

效果如下:


参考资料:

qsort()在字符指针数组中的应用:

http://www.cnblogs.com/2011-9-13/archive/2011/11/13/2247349.html

http://www.cppblog.com/Joe/archive/2010/10/29/131746.aspx?opt=admin

字符串排序:《C语言使用教程》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值