还是第一次发博文呢.嗯,最近在尝试每天做一道编程题,当然,我要求自己只能用C语言实现.一方面可增加自己对C函数库的熟悉程度,另一方面也想增加自身的编码经验.毕竟,感觉平时Code的时间严重不够.对于一个职业Coder来说这样肯定不太好嘛!
好吧,回到正题吧.今天的题目内容很常规.就是判断用户输入的字符串是否是一个回文串,当然,难度稍微增加那么点,就是同时能够在一个字符串中找到所有的回文子串同时输出.想必,关于回文串的定义就没什么可说的了吧,比如"abba"就是个回文串,此外,还要能找出字符串"abc12321ddw"中的两个回文子串"12321"和"dd".自然,网上也有很多关于回文串判断的代码,但别人的代码终究不是自己写出来的,自然找不到感觉,所以就自己操练了一遍,好找一找感觉.
好了,我将问题分成了两个部分来做:
首先,我必须要能够判断一个字符串是一个回文串.那么回文串有什么特点呢?比如串"aba", "abba",仔细观察,会发现一些对称的特点.可以想象,手中有一张纸,我们现在要做的不过就是将这张纸给对折起来就好咯!所以,就有了下面的代码.我用它来判断字符串是否是回文串.当然,算法自然没什么优势,我对代码的追求是,首先它能运行,其次才是性能.
1 //函数功能:判断一个字符串是否是回文串. 2 //入口参数:str--指向字符串的指针 3 //返回:1--是回文串,0--不是回文串 4 int IsPalindromeString(const char* str) 5 { 6 assert(str != NULL); 7 // printf("%s\n", str); 8 int flag = 1; 9 int len = strlen(str); 10 int i_begin = 0; 11 int i_end = len - 1; 12 //如果长度为1,则fei回文串. 13 if (len <= 1) 14 { 15 flag = 0; 16 } 17 else 18 { 19 //想象将字符串进行折叠,若发现某个字符不重合,则判断一定不是回文串,否则是个回文串. 20 for (; i_begin <= i_end; i_begin++, i_end--) 21 { 22 if (tolower(str[i_begin]) != tolower(str[i_end])) 23 { 24 flag = 0; 25 break; 26 } 27 } 28 } 29 return flag; 30 }
查看代码
好了,继续往下分析.我们以这样的一个字符串为例:"acd12321dfe",显然,我们很容易看出来中间的"12321"是个回文子串,但计算机可没那么聪明,那该怎么做呢?自然,我还是用了比较笨的办法咯.用两个游标i和j.这两个游标开始分别指向串首和串尾.然后,我们将从i开始到j结束的所有字符提取到一个临时串中并判断是否是回文串.通过不断地移动最终把所有的回文子串查找出来.
自然而然地,我们显然要有个能够提取子串函数来完成字符串提取工作,于是就有了下面的函数咯,注意,我将一句话中可能存在的空格,标点符号等给忽略了,比如经典的回文语句"Able was I ere I saw Elba"很显然是个回文语句,所以,不能因为其中的空格或者大小写问题就造成误判:
1 //函数功能:从源串中提取指定长度的子串到目的缓冲区保存 2 //入口参数:dest--指向目的缓冲区的指针, src--指向源串的指针,start--起始位置,end--结束位置 3 //返回:void 4 void SubString(char* dest, const char* src, int start, int end) 5 { 6 assert(dest != NULL && src != NULL); 7 //下面是一种比较笨的复制字符串的方法. 8 //,.?! will not copy. 9 int i = 0, j = start; 10 while (j <= end) 11 { 12 if (src[j] == ‘ ‘|| src[j] == ‘,‘ || src[j] == ‘.‘ || 13 src[j] == ‘?‘ || src[j] == ‘!‘ || src[j] == ‘\‘‘) 14 { 15 j++; 16 } 17 else 18 { 19 dest[i++] = src[j++]; 20 } 21 } 22 }
查看代码
想一想,现在我们还需要一个查找一个字符串所有回文子串的函数了.于是便有了下面的函数.它用来接受用户输入的字符串,并将字符串中所有能构成的回文子串给打印出来.
代码中,使用了malloc()函数申请了临时存储空间,用来存放每次用于测试的子串.算法估计算不上优,但是可正常工作了.
1 //函数功能:查找一个字符串中所有的回文串并且打印出来 2 //入口参数:str(指向一个字符串的指针) 3 //返回:void 4 void FindPalindromeSubString(const char* str) 5 { 6 assert(str != NULL); 7 int len = strlen(str); 8 int i = 0, j = 0, tmpPos = i, k = 0; 9 //申请开辟一块缓冲区,用来存放测试串. 10 char* pBuff = (char*)malloc((len + 1) * sizeof(char)); 11 if (pBuff == NULL) 12 return; 13 14 for (i=0; i<len; i++) 15 { 16 for (j=(len - 1); j>=tmpPos; j--) 17 { 18 if (str[i] == str[j]) 19 { 20 memset(pBuff, ‘\0‘, (len + 1) * sizeof(char)); 21 SubString(pBuff, str, i, j); 22 if (IsPalindromeString(pBuff)) 23 { 24 //当查找到回文子串时就打印出来. 25 printf("#%d, length=%d: %s\n", ++k, (int)strlen(pBuff), pBuff); 26 tmpPos = j + 1; 27 } 28 } 29 } 30 } 31 32 if (k < 1) 33 { 34 printf("没有找到回文子串.\n"); 35 } 36 free(pBuff); 37 pBuff = NULL; 38 }
查看代码
好了,我们来看看main函数的实现代码吧,然后结束我们这个枯燥的话题吧^_^
1 int main(void) 2 { 3 char ch[MAXLEN] = {‘\0‘}; 4 while (1) 5 { 6 memset(ch ,‘\0‘, MAXLEN * sizeof(char)); 7 printf("请输入字符串,程序将会输出所有的回文子串:\n"); 8 fgets(ch, MAXLEN * sizeof(char), stdin); 9 FindPalindromeSubString(ch); 10 printf("\n"); 11 } 12 return 0; 13 }
查看代码
总结下,以上代码所使用的算法并非最优解,只代表我个人的解题思路,如果希望能找到更好的算法,CSDN的博客上也可以搜索到的.
上面的代码,我在gcc4.8.2下编译并正常运行,来看看在Ubuntu14.04下测试的结果吧!
顺便给Ubuntu做个广告吧!^_^,Good.
更改日志:
2014-4-28日,修改了FindPalindromeSubString()函数.第一,增加了一个判断,防止无意义的拷贝;第二,防止因为有类似"abcdcbabcdc"这样的重叠回文串判断错误!
版权声明:本文为博主原创文章,未经博主允许不得转载。