解法一:第一次看到这题目,想到最简单、最直觉的解法就是:遍历字符串,将第一个字符和最后一个交换,第二个和倒数第二个交换,依次循环,即可,于是有了第一个解法:
字符串反转_字符串char* strrev1(const char* str)
字符串反转_字符串
字符串反转_字符串{
字符串反转_字符串  int len = strlen(str);
字符串反转_字符串  char* tmp = new char[len + 1];
字符串反转_字符串  strcpy(tmp,str);
字符串反转_字符串        
字符串反转_字符串  for (int i = 0; i < len/2; ++i)
字符串反转_字符串  {
字符串反转_字符串    
字符串反转_字符串    char c = tmp[i];
字符串反转_字符串    tmp[i] = tmp[len-i-1];
字符串反转_字符串    tmp[len-i-1] = c;
字符串反转_字符串    
字符串反转_字符串  }
字符串反转_字符串    
字符串反转_字符串  return tmp;
字符串反转_字符串
字符串反转_字符串}
这里是通过数组的下标方式访问字符串的字符,实际上用指针直接操作即可。解法二正是基于此,实现代码为:
字符串反转_字符串char* strrev2(const char* str)
字符串反转_字符串{
字符串反转_字符串
字符串反转_字符串  char* tmp = new char[strlen(str) + 1];
字符串反转_字符串  strcpy(tmp,str);    
字符串反转_字符串  char* ret = tmp;    
字符串反转_字符串    
字符串反转_字符串  char* p = tmp + strlen(str) - 1;    
字符串反转_字符串    
字符串反转_字符串  while (p > tmp)    
字符串反转_字符串  {    
字符串反转_字符串    char t = *tmp;    
字符串反转_字符串    *tmp = *p;    
字符串反转_字符串    *p = t;    
字符串反转_字符串    
字符串反转_字符串    --p;    
字符串反转_字符串    ++tmp;    
字符串反转_字符串  }    
字符串反转_字符串    
字符串反转_字符串  return ret;    
字符串反转_字符串}
显然上面的两个解法中没有考虑时间和空间的优化,一个典型的优化策略就是两个字符交换的算法优化,我们可以完全不使用任何外部变量即完成两个字符(或者整数)的交换,这也是一个很经典的面试题目。特别是一些嵌入式硬件相关编程中经常要考虑寄存器的使用,因此经常有不使用任何第三个寄存器即完成两个寄存器数据的交换的题目。一般有两个解法,对应这里的解法三和解法四。
解法三的实现代码为:
字符串反转_字符串char* strrev3(const char* str)
字符串反转_字符串{    
字符串反转_字符串  char* tmp = new char[strlen(str) + 1];    
字符串反转_字符串  strcpy(tmp,str);    
字符串反转_字符串  char* ret = tmp;    
字符串反转_字符串    
字符串反转_字符串  char* p = tmp + strlen(str) - 1;    
字符串反转_字符串  while (p > tmp)    
字符串反转_字符串  {    
字符串反转_字符串    *p ^= *tmp;    
字符串反转_字符串    *tmp ^= *p;            
字符串反转_字符串    *p ^= *tmp;
字符串反转_字符串    
字符串反转_字符串    --p;    
字符串反转_字符串    ++tmp;    
字符串反转_字符串  }
字符串反转_字符串    
字符串反转_字符串  return ret;
字符串反转_字符串    
字符串反转_字符串}
解法四的实现代码为:
字符串反转_字符串char* strrev4(const char* str)
字符串反转_字符串{    
字符串反转_字符串  char* tmp = new char[strlen(str) + 1];    
字符串反转_字符串  strcpy(tmp,str);    
字符串反转_字符串  char* ret = tmp;
字符串反转_字符串    
字符串反转_字符串  char* p = tmp + strlen(str) - 1;    
字符串反转_字符串  while (p > tmp)    
字符串反转_字符串  {    
字符串反转_字符串    *p = *p + *tmp;    
字符串反转_字符串    *tmp = *p - *tmp;    
字符串反转_字符串    *p = *p - *tmp;    
字符串反转_字符串        
字符串反转_字符串    --p;    
字符串反转_字符串    ++tmp;    
字符串反转_字符串  }
字符串反转_字符串
字符串反转_字符串  return ret;
字符串反转_字符串    
字符串反转_字符串}
实际上我们还可以通过递归的思想来解决这个问题,思想很简单:每次交换首尾两个字符,中间部分则又变为和原来字符串同样的问题,因此可以通过递归的思想来解决这个问题,对应解法五的实现代码为:
字符串反转_字符串char* strrev5(char* str,int len)
字符串反转_字符串
字符串反转_字符串{    
字符串反转_字符串  if (len <= 1)    
字符串反转_字符串    return str;    
字符串反转_字符串    
字符串反转_字符串  char t = *str;    
字符串反转_字符串  *str = *(str + len -1);    
字符串反转_字符串  *(str + len -1) = t;    
字符串反转_字符串    
字符串反转_字符串  return (strrev5(str + 1,len - 2) - 1);
字符串反转_字符串    
字符串反转_字符串}
 
以下给出一个测试程序
字符串反转_字符串void P(char *a)
字符串反转_字符串{
字符串反转_字符串  printf("%s\n",a);
字符串反转_字符串}
字符串反转_字符串
字符串反转_字符串int main(int argc,char* argv[])
字符串反转_字符串{    
字符串反转_字符串  char* str = "hello";    
字符串反转_字符串  P(str);    
字符串反转_字符串    
字符串反转_字符串  char* str2 = strrev1(str);    
字符串反转_字符串  P(str2);    
字符串反转_字符串    
字符串反转_字符串  char* str3 = strrev2(str2);    
字符串反转_字符串  P(str3);    
字符串反转_字符串    
字符串反转_字符串  char* str4 = strrev3(str3);    
字符串反转_字符串  P(str4);    
字符串反转_字符串    
字符串反转_字符串  char* str5 = strrev4(str4);    
字符串反转_字符串  P(str5);    
字符串反转_字符串    
字符串反转_字符串  char* str6 = strrev5(str5,strlen(str5));    
字符串反转_字符串  P(str6);    
字符串反转_字符串    
字符串反转_字符串  return 0;
字符串反转_字符串    
字符串反转_字符串}
 你就可以看到字符串"hello""olleh"交替输出了。
  说明:1)这里解法中没有认真考虑输入字符串的合法性和特殊长度(如NULL、一个字符等)字符串的处理;2)前4个算法不改变输入字符串的值,解法五修改了输入字符串。
方法四中利用异或来实现两个数的交换,这种方法是第一次见到,原理如下
异或是一种基于二进制的位运算,用符号XOR表示,其运算法则是对运算符两侧数的每一个二进制位,同值取0,异值取1。它与布尔运算的区别在于,当运算符两侧均为1时,布尔运算的结果为1,异或运算的结果为0。
异或运算最常见于多项式除法,不过它最重要的性质还是自反性:A XOR B XOR B = A,即对给定的数A,用同样的运算因子(B)作两次异或运算后仍得到A本身。这是一个神奇的性质,利用这个性质,可以获得许多有趣的应用。
例如,所有的程序教科书都会向初学者指出,要交换两个变量的值,必须要引入一个中间变量。但如果使用异或,就可以节约一个变量的存储空间:
设有A,B两个变量,存储的值分别为a,b,则以下三行表达式将互换他们的值
表达式 (值)
A=A XOR B (a XOR b)
B=B XOR A (b XOR a XOR b = a)
A=A XOR B (a XOR b XOR a = b)
类似地,该运算还可以应用在加密,数据传输,校验等等许多领域。