热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

处理字符串的最快方法

如何解决《处理字符串的最快方法》经验,为你挑选了1个好方法。

我有一个文本文件来阅读和处理20000行.在文本文件中,我想读取点坐标并分配给DirectX进行渲染.文本文件的快照

我使用std :: ifstream,getline,stringstream来获取点坐标.在构建win32程序然后开始运行之后,读取并存储数组中的点坐标需要很长时间.(5分钟通过20000行文本文件).代码如下:

struct PointCoord { std::string PtName; float PtX = 0.0; float PtY = 0.0;}
PointCoord *PointPtr = NULL;
PointCoord pointcoord;

std::ifstream File_read(FileNameTXT);    
while (getline(File_read, TextHandler))
        {
            std::istringstream iss;
            std::string skip;
            if (TextHandler.find("  POINT ") != std::string::npos)
            {
                iss.str(TextHandler);
                std::string TempX, TempY;
                iss >> skip;
                iss >> pointcoord.PtName;                         

                //pointcoord pass value to PointCoord
                iss >> TempX;
                iss >> TempY;

                pointcoord.PtX = std::stof(TempX.c_str());
                pointcoord.PtY = std::stof(TempY.c_str());

                //dynamically store the points coordiantes
                if (PointPtr == NULL)
                {
                    PointPtr = new PointCoord[1];                     

                    //PointCoord pass value to PointPtr
                    PointPtr[0] = pointcoord;
                    Pt_Count++;
                }
                else
                {
                    PointCoord *Temp = PointPtr;
                    PointPtr = new PointCoord[Pt_Count + 1];

                    for (UINT i = 0; i 

我还使用std :: fread在字符串缓冲区中一次读取整个文本文件,这很快(在几秒钟内完成读取).然后在类似的代码中使用stringstream将点坐标存储在动态数组中,这也太慢了.

欢迎任何建议.非常感谢.



1> WhozCraig..:

这段代码中最令人讨厌的事情不是字符串解析; 它为每个新读取的点调整目标数组的大小.你读的越多,它就越糟糕.最终,它成为O(n ^ 2)的复制操作.

为了给你一个想法如何不好说是,考虑的基本总和n自然数,因为这是你做了多少对象结构,破坏,和复印件:

n(n + 1)/ 2 =(20000*20001)/ 2 = 创建,复制和销毁200010000个对象

因此,字符串解析不是问题.被解析的20000行文本与超过2亿个对象构造,析构和副本相比相形见绌.


你不需要做任何这些.std::vector根据文件大小使用适当的容器,例如并接近初始保留.然后,只需生成点并将它们移动到容器中.

这样做的一个例子,包括生成一个100000点的测试文件(你问的大小的5倍),如下所示:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

struct Point
{
    std::string name;
    float x;
    float y;
};

std::vector readFile(std::string const& fname)
{
    std::vector res;

    std::ifstream inp(fname);
    if (inp.is_open())
    {
        // gather file size for a rough approximation of reserve
        inp.seekg(0, std::ios::end);
        auto flen = inp.tellg();
        inp.seekg(0, std::ios::beg);
        res.reserve(flen/40);

        std::string line;
        while (std::getline(inp, line))
        {
            auto pos = line.find("POINT");
            if (pos != std::string::npos)
            {
                std::istringstream iss(line.substr(pos+5));
                Point pt;
                if (iss >> pt.name >> pt.x >> pt.y)
                    res.emplace_back(std::move(pt));
            }
        }
    }

    return res;
}


int main()
{
    using namespace std::chrono;

    std::mt19937 prng(std::random_device{}());
    std::uniform_real_distribution dist(-100.0, 100.0);

    // generate test data
    std::ofstream outf("testpoints.txt");
    for (int i=1; i<=100000; ++i)
        outf <<"POINT  \"" <(tp1-tp0).count() <<"ms\n";
    v.clear();
}

产量

在2015双核i7 MacBook Air笔记本电脑上运行,发布模式构建产生以下结果:

Read 100000 points in 164ms

一个可能更合适的容器: std::deque

最后,您真正需要的是一个允许在最后快速插入的容器,同时在调整大小期间最小化(或消除)元素复制.当然,正如上面的代码所示,设置对a的储备std::vector是一种方法.另一个选择是使用一个专门用于端插入的容器,同时仍然主要是缓存友好的(不完美的std::vector,但肯定比链接列表更好,这对于插入非常好,但对于枚举来说是可怕的).

这正是std::deque将要做的.上面的代码,更改为std::deque,允许您消除reserve-guess,并简单地开始关闭序列末尾的节点,这将随着序列的增长自动添加更多页面:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

struct Point
{
    std::string name;
    float x;
    float y;
};

std::deque readFile(std::string const& fname)
{
    std::deque res;

    std::ifstream inp(fname);
    if (inp.is_open())
    {
        std::string line;
        while (std::getline(inp, line))
        {
            auto pos = line.find("POINT");
            if (pos != std::string::npos)
            {
                std::istringstream iss(line.substr(pos+5));
                Point pt;
                if (iss >> pt.name >> pt.x >> pt.y)
                    res.emplace_back(std::move(pt));
            }
        }
    }

    return res;
}


int main()
{
    using namespace std::chrono;

    std::mt19937 prng(std::random_device{}());
    std::uniform_real_distribution dist(-100.0, 100.0);

    // generate test data
    std::ofstream outf("testpoints.txt");
    for (int i=1; i<=100000; ++i)
        outf <<"POINT  \"" <(tp1-tp0).count() <<"ms\n";
    v.clear();
}

产量

Read 100000 points in 160ms

如果您的需求需要连续的序列,那么这种std::vector方法就是您的选择.如果您只是需要随机访问元素并希望快速插入,那么std::deque可能更适合.想一想,选择最适合自己的.


摘要

摆脱那个可怕的扩展算法.这是你代码中的痛点.将其替换为几何调整大小算法,并从头开始粗略估计您需要的元素数量.或者使用适合最佳插入的容器.无论哪种方式,它都比你现在拥有的更好.


推荐阅读
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • 本文介绍了一种划分和计数油田地块的方法。根据给定的条件,通过遍历和DFS算法,将符合条件的地块标记为不符合条件的地块,并进行计数。同时,还介绍了如何判断点是否在给定范围内的方法。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • 本文介绍了Web学习历程记录中关于Tomcat的基本概念和配置。首先解释了Web静态Web资源和动态Web资源的概念,以及C/S架构和B/S架构的区别。然后介绍了常见的Web服务器,包括Weblogic、WebSphere和Tomcat。接着详细讲解了Tomcat的虚拟主机、web应用和虚拟路径映射的概念和配置过程。最后简要介绍了http协议的作用。本文内容详实,适合初学者了解Tomcat的基础知识。 ... [详细]
  • 本文介绍了一个程序,可以输出1000内能被3整除且个位数为6的所有整数。程序使用了循环和条件判断语句来筛选符合条件的整数,并将其输出。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
author-avatar
购物狂RZBZ_719
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有