zoukankan      html  css  js  c++  java
  • C++高性能转换大小写算法

    简述

    有一个需求,是需要将URL中的query参数的key全部转换为小写或者大写,键值对的数量有点多,但全部都是英文字母,无需考虑非字母的情况。
    实现比较快的做法是使用STL或C标准库中的转换接口,如下:

    #include <string> 
    #include <cctype> 
    #include <algorithm>
    
    // 字符串中的大写字符转小写
    std::string strtolower(std::string s)
    {
        transform(s.begin(), s.end(), s.begin(), ::tolower);
        return s;
    }
    
    // 字符串中的小写字符转大写
    std::string strtoupper(std::string s)
    {
        transform(s.begin(), s.end(), s.begin(), ::toupper);
        return s;
    }
    

    这个方法虽然很好,但是效率不是很高。
    分析了一下ascii码的码值,发现大小写字母的ascii码之间是有规律的。

    原理

    英文字母的ASCII码值表示如下

    对比一下其二进制形式

    对比使用的是OSChina的在线工具http://tool.oschina.net/diff/

    从对比的结果可以看出,大写字母与小写字母的差别仅是一个比特位的不同
    因为它们的这个规律,可以写出下面的转换函数(如果输入不是字母,转出的结果会有错误)
    可以查看数字0-9的ascii码值,可以看出它们的第6位都是0,所以转为小写的算法不会影响数字的值。
    转小写算法中受到影响的,只有ascii码二进制表示中第六位为0的部分。其中非字母部分如下表

    #include <iostream>
    #include <string>
    #include <stdint.h>
    // 更优化
    std::string strtoupper(std::string s)
    {
        if(s.empty()){return s;}
        size_t len = s.size() + 1;
        size_t alignlen = len + 8 - (len % 8);
        s.resize(alignlen);
        size_t ec = alignlen / 8;
        uint64_t* p8 = (uint64_t*)s.data();
        for(size_t i=0;i<ec;++i){
            p8[i] &= 0xDFDFDFDFDFDFDFDF;
        }
        s.resize(len-1);
        return s;
    }
    
    // 未做进一步优化
    std::string strtolower(std::string s)
    {
        size_t len = s.size();
        size_t ec = len /8;
        uint64_t* p8 = (uint64_t*)s.data();
        for(size_t i=0;i<ec;++i){
            p8[i] |= 0x2020202020202020;
        }
        uint8_t* p1 = (uint8_t*)(p8 + ec);
        len %= 8;
        for(size_t i=0;i<len;++i){
            p1[i] |= 0x20;
        }
        return s;
    }
    

    性能测试

    测试代码如下:

    int main()
    {
        //std::cout << "Hello, world!
    ";
        for(size_t i=0;i<1000000;++i){
        std::string s = strtoupper("qwertyuiopasdfghjklzxcvbnm````````QWERTYUIOPASDFGHJKLZXCVBNM");
        //std::cout<<s<<std::endl;
        s = strtolower("qwertyuiopasdfghjklzxcvbnm								QWERTYUIOPASDFGHJKLZXCVBNM");
        //std::cout<<s<<std::endl;
        }
        return 0;
    }
    

    --编译时候请勿优化,否则可能被优化掉!--
    测试结果如下:
    使用STL算法结果如下

    time ./teststl
    ./teststl  7.88s user 0.03s system 100% cpu 7.904 total
    

    自写代码测试结果如下

    time ./test
    ./test  0.93s user 0.00s system 99% cpu 0.928 total
    

    可以看到,其性能有差异。(应用场景有限)

  • 相关阅读:
    [LeetCode 1029] Two City Scheduling
    POJ 2342 Anniversary party (树形DP入门)
    Nowcoder 106 C.Professional Manager(统计并查集的个数)
    2018 GDCPC 省赛总结
    CF 977 F. Consecutive Subsequence
    Uva 12325 Zombie's Treasure Chest (贪心,分类讨论)
    Poj 2337 Catenyms(有向图DFS求欧拉通路)
    POJ 1236 Network of Schools (强连通分量缩点求度数)
    POJ 1144 Network (求割点)
    POJ 3310 Caterpillar(图的度的判定)
  • 原文地址:https://www.cnblogs.com/oloroso/p/7384709.html
Copyright © 2011-2022 走看看