反转字符串(不申请变量和空间)

基本思路:从 两头往中间做字符交换 。字符串最后一个字符是 '/0' ,表示结束,没有实际意义,可以将它 当作中间变量,等处理完成后,再将最后一个字符置 '/0' 即可

***********************************************************************

void Reverse (char   *s) 

        if(strlen(s)== 1) // 当为一个字符时无需交换或奇数个

               return;

 

       if(*(s))   // 0 个或偶数个

        { 

               *s    =   *s   +   *(s+strlen(s)-1); 

               *(s+strlen(s)-1)   =   *s   -  *(s+strlen(s)-1); 

               *s   =   *s   -  *(s+strlen(s)-1); 

               // 实现字符串首末字符互换, 但加法可能会溢出

 

                *(unsigned   short*) (s+strlen(s)-1)   =  (*(s+strlen(s)-1))<<8;

               // 把字符串的最后一个字节往后移了一位, 利用了 0 = ‘/0

                // 当然也可以利用上面交换字符的方法,不过移位利用了 0 = ‘/0’ 的效率更高

               // 上面四步的本质是实现三个数两两互换,最简单的是两次两两互换

               // 但是目前结尾符是已知的,直接把第一个放到结尾处,最后一个放第一个,将

               // 最后一个用结尾符填上即可,只需三步,易于理解,前提是 有变量保存字符串的 // 长度

               // 但是由于 不能申请临时变量,移动了结尾符号后, strlen 函数就不能用 

               // 因此上述强制转换的方式是唯一的

 

               // 然后将去掉了首尾字符的新串传进去,递归调用

               Reverse (s+1);

              

               *(unsigned   short*)(s+strlen(s))   =  *(s+strlen(s)+1);

               // 将 ‘/0 逐步后移,还原更改后的子串  

        } 

        else 

       return;    

}

 

图示过程:字符串 abcdef

S+1 = Str = abcdef’/0’   abcdef’/0’ > fbcdea’/0’ > fbcde’/0’a

S+1 = Str = bcde’/0  fbcde’/0’a> fecdb’/0’a > fecd’/0’ba

S+1 = Str = cd’/0’   fecd’/0’ba > fedc’/0’ba > fed’/0’cba

S+1 = Str =’/0’    ,递归返回,此时 s= cd’/0’已经在上一步改为   d’/0’c > dc’/0’ > edcb’/0’ >fedcba’/0’

 

考虑串的长度为奇数的情况,当为奇数时,最后传进去的 串长度为 1 ,此时无需交互 ,应该直接退出。 因此在入口处补上判断奇偶的条件

if(strlen(s) == 1)

               return;

当然也可以在递归调用前 判断改动后的字符串长度 if( strlen (str+ 1) >= 2 )  ,才调用,可以消除奇数的影响

当原始字符串为一个时, 第一次就应该无任何处理的,所以在入口处判断更合理哦

 

×××××××××××××××××××××××××××××××

优化,不申请任何变量,支持链式操作,返回 char *

char  * Reverse(char   *s) 

        if(strlen(s)== 1)

               return s;

 

        if(*(s)) 

        { 

               *s    =   *s   +  *(s+strlen(s)-1); 

               *(s+strlen(s)-1)   =   *s   -  *(s+strlen(s)-1); 

               *s   =   *s   -  *(s+strlen(s)-1); 

               // 实现字符串首末字符互换,但加法可能会溢出

 

               *(unsigned   short*)(s+strlen(s)-1)   =  (*(s+strlen(s)-1))<<8;

              

               Reverse (s+1);

              

               *(unsigned  short*)(s+strlen(s))   =   *(s+strlen(s)+1); 

              

        } 

      

        return s;   // 此句没有,程序就错了,因为递归的最外层是进入 if(*(s)) 的,此时无返回值

}

 

×××××××××××××××××××××××××××××××

申请了 一个变量保存串的长度 ,一般面试这个程序就可以了,能写出这个其实已经很牛 b 了,整上面那个, 估计别人开始怀疑是以前做过这个题目了,呵呵,还得装傻点

char  * Reverse (char   *s) 

        if(strlen(s)== 1)

               return s;

 

        if(*(s)) 

        { 

               int len = strlen(s);

               *(s+len) =   *s;  

               *s   =  *(s+len-1);

               *(s+len-1) = '/0';

               // 首尾字符及结束符交换位置

 

                // 去掉首尾字符后再递归调用

               Reverse (s+1);

              

               //*(unsigned   short*)(s+strlen(s))   =  *(s+strlen(s)+1); 

               *(s+len-1) = *(s+len);

               *(s+len) = '/0'; // 恢复原来改变后的串

        } 

      

        returns; 

}

 

×××××××××××××××××××××××××××××××

将字符串的最后一个元素递归移动到队头,递归到达尾部,异或 ^ 交换,队尾元素前移一格,返回上层,再次交换,最后即将队尾移到队头

void   tail2head(char*   s) 

       if(strlen(s)==1)  

        { 

               return; 

        } 

        elseif(strlen(s)==2) 

        { 

               s[0] = s[1]^s[0];

               s[1] = s[1]^s[0];

               s[0] = s[1]^s[0];

               return; 

        } 

        else if(strlen(s)>2) 

        { 

               tail2head(s+1); 

               s[0] = s[1]^s[0];

               s[1] = s[1]^s[0];

               s[0] = s[1]^s[0];

        } 

}  

 

递归一次移动队尾至队头,更新队头至下一个元素,再次调用 tail2head ,最后即可全部逆序

char*   Reverse(char   *s) 

       if(strlen(s)>1) 

        { 

               tail2head(s);

               Reverse(s+1);

        }

       return   s;

}

此法元素移动次数最多,但是思路比较清晰 ,另外整个功能用了两个递归函数实现,打破了通常只有一个接口函数的固定思维

 

main() 

       char   streven[10]   =   "abcdef";

       char   strood[10]   =  "1234567";

       char   strone[10]   =   "1";

       char   strtwo[10]   =   "12";

 

        printf("string'abcdef' reversed is '%s'/n",Reverse(streven));

       printf("string '1234567' reversed is '%s'/n",Reverse(strood)); 

       printf("string '1' reversed is '%s'/n",Reverse(strone));

       printf("string '12' reversed is '%s'/n",Reverse(strtwo));

 

        return 0;

        //string'abcdef' reversed is 'fedcba'

        //string '1234567' reversed is '765123?' 当串的长度为奇数时好像还有点问题

//string '1234567' reversed is '7654321' 补充了判断条件后无误

        //string '1'reversed is '1'

        //string '12'reversed is '21'

}

 

 

 

#include<stdio.h>

#include<assert.h>

 

 

char * revert (char * str)

{

assert(str!=NULL);

char * pHead = str;

char * pEnd = str;

while( (*pEnd) != '\0')

pEnd++;

pEnd--;

char temp;

while(pHead<pEnd)

{

temp = *pHead;

*pHead = *pEnd;

*pEnd = temp;

pHead++;

pEnd--;

}

 

puts(str);

return str;

}

 

int main()

{

char str[] = "abcdefgh";

 

puts(revert(str));

 

getchar();

return 0;

}

posted @ 2015-09-26 23:18  Uncle_Nucky  阅读(307)  评论(0编辑  收藏  举报