zoukankan      html  css  js  c++  java
  • 不申请变量和空间反转字符串

    要求:不申请变量和空间 反转字符串 ,用一个函数实现。 异或^交换或者加减交换的典型应用! VIA 笔试题

    基本思路:从 两头往中间做字符交换 。字符串最后一个字符是 '/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'; // 恢复原来改变后的串

    }

    return s;

    }

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

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

    void tail2head(char* s)

    {

    if(strlen(s)==1)

    {

    return;

    }

    else if(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'

    }

  • 相关阅读:
    C/S架构引用Lodop 如何在C#调用web打印控件Lodop
    Lodop打印设计(PRINT_DESIGN)里的快捷键
    Lodop打印控件中PRINT_INITA()和PRINT_PAGESIZE()宽高
    LODOP打印控件关联输出各内容
    如何判断使用的是Lodop还是C-Lodop
    Lodop代码设置打印机等信息后 设置预览可重选
    Lodop打印控件输出页码(超文本和纯文本页码)
    PhotoShop不用魔棒、钢笔 建立较平整的选区 P进电脑屏幕里
    uniq命令详解
    sort命令详解
  • 原文地址:https://www.cnblogs.com/xmphoenix/p/2257715.html
Copyright © 2011-2022 走看看