今天,看一位学长的博客《递归的力量》,受到的启发还是很多的,以前写递归程序,从来都没有好好想过,这里为什么要用到递归,以及什么样的情况要用到递归。引用他博文中的一句话,也是思考的一个方式:可以用递归实现的场景要满足两个条件:
第一:这个问题是否可以分解为形式相同但规模更小的问题?
第二:如果存在这样一种分解,那么这种分解是否存在一种简单情境?
有一个例子是用递归判断一个回文序列,回文大家都知道就是类似abba 或者abcba这样的序列,判断回文的基本思想也就是首尾字符是相同的,由于他的对称性,那么可以得知,这各串是可分解的。那么有没有一种简单可终止的情况,那就是剩下最后一个字符或者没有字符的情况了,接下来就可以按照递归的思路写这个程序了。
然后,我自己就写了一下按照递归实现判断一个字符串是否是一个回文序列的C程序,写的过程中发现了以前曾今专门研究的问题,自己在这上面犯错误也真的是非常的惭愧。。。
1 #include<stdio.h>
2 #include<stdlib.h>
3
4 /*程序接受两个参数 param1 字符串 param2 字符串长度*/
5 int is_palindrome(char* para_str , int len);
6
7 int main(int argc , char* argv[])
8 {
9 int n = atol(argv[2]); /*C标准库函数,转换字符串为long int*/
10 if(is_palindrome(argv[1],n))
11 printf("this string is palindrome !\n");
12 return 0;
13 }
14
15 int is_palindrome(char* para_str , int len)
16 {
17 printf("Length: %d \n",len);
18 printf("%c ----- %c\n",para_str[0],para_str[len-1]);
19 if(len == 0 || len == 1)
20 return 1;
21 else
22 return((para_str[0] == para_str[len-1]) ? is_palindrome(++para_str,len-2) : 0);
23 /*这里更正了学长的一个小错误,参数应该是len-2*/
24 }
看学长的代码时发现了一个错误就是,参数的问题,应该是len-2,事实上每次是剪掉首尾的,然而当程序第一次执行的时候,结果是这个样子的
也就是说第一次递归后,字符指针并没有向后移动,于是乎。。。
我仔细的看这句代码,一遍一遍又一遍。。
return((para_str[0] == para_str[len-1]) ? is_palindrome(para_str++,len-2) : 0);
终于发现了那个问题就是++操作符,以前在《C和指针》上曾经理解过 i++ 和 ++i的区别,++是右结合的操作符,i++的执行过程是先获得i的一份拷贝,然后执行+1操作。注意这个拷贝地址是未知的,所以千万不要把i++或者++i来当做左值L-Value来使用。这种赋值当然是不合法的。
但是这还没完,其实这个是个编程习惯的问题,习惯了*str++这样的移动指针操作,在这里也惯性的这么写了,其实最好的风格应该是
return((para_str[0] == para_str[len-1]) ? is_palindrome(para_str+1,len-2) : 0);
因为这里实际上传递的是一个参数。以前网上有朋友说+1和++的区别,当然最大的区别就是前者不改变自身,更像一个“值”。。。。
这个问题并不是什么非常值得研究的东西,很小很小,但却是自己一直在犯的各种小错误,与各位共勉~
附上执行成功后的截图