2014-12-04 81 views
0

我有一个函数读取文件夹中的文件(我正在使用boost)。我也试图只保留2个文件(它们是日志文件,所以它们被旋转,并且我不想在第三个文件中保留旧的日志=日志)。我将这些文件的名字存储在一个列表中,但是因为读取操作没有按照创建时间顺序完成,所以我需要对列表进行排序。我的情况最好是什么:矢量还是列表?

我知道

载体擅长:

  • 通过访问他们的位置索引(固定时间)单个元素。
  • 以任意顺序(线性时间)对元素进行迭代。
  • 从其末尾添加和移除元素(恒定分摊时间)。

优点列出容器:

  • 高效插入和移除元件的容器中的 (恒定的时间)的任何地方。
  • 高效的移动元素和容器内或甚至不同容器之间的元素块(恒定时间)。
  • 以正向或反向顺序(线性时间)对元素进行迭代。

我不知道什么是做到这一点的最好办法:使用列表或载体?

要我

  • 使用矢量和排序它上升,从端删除,添加新元素(在结束时),重新排序等; 或
  • 使用列表并对其进行升序排序,从头开始删除,在结尾添加新元素,度假村等;

  • 是排序,只需要在开始的时候,因为我每次插入文件名是最后创建的?
  • 如果列表/向量是排序的,那么什么时候使用它?
  • 如果我使用std::is_sorted可以不分拣每次吗?

一些更多的信息:

由于升压的文件旋转没有“删除文件,如果太多”状态,只有“有磁盘空间不足”,我有实现了保留最后两个文件的这一步骤,或者在每次创建新文件时移除最老的文件,并且有2个日志文件。所以每次创建一个新的日志文件时,我都会验证文件列表,如果有足够的文件(2个或更多),只需删除较旧的文件。由于该文件的名称是logs_%N.log,我不知道,如果该文件logs_X1.log是年龄超过logs_X2.log

如:我重新启动应用程序,还有文件logs_51.log,logs_52.log,其中之一是要被删除?假设它将删除logs_51.log并创建logs_0.log,如果我再次重新启动它,将会有logs_52.log和logs_0.log。哪一个是现在要被删除?)

这就是为什么我需要的那种,因为应用程序可能会重新启动,而我读的现有文件,完成有更多的空间,然后创建一个新的一个。

+2

如果只有两个文件,排序的目的是甚么,甚至有一个容器? – dasblinkenlight 2014-12-04 15:57:11

+2

我说这个差别不足以担心。您正在优化需要很少时间的事情。而且它不像你会在循环中调用数十亿次。 – drescherjm 2014-12-04 16:01:17

+0

'使用向量并对其进行升序排序,从最后删除,添加新元素(最后),重新排序等等是没有意义的。在开始处插入比在末尾插入和排序要快得多。 – user2079303 2014-12-04 16:01:24

回答

0

其实我已经使用升压排序在最后的修改方式的文件:

bool Logger::compareAccessTime(const std::string& path1In, const std::string& path2In) 
{ 
    return (fs::last_write_time(fs::path(path1In)) < fs::last_write_time(fs::path(path2In))); 
} 

其中fs = boost::filesystem

而且因为我使用的字符串列表,我并没有改变整个代码,但初始化列表时添加的list::sort(compareAccessTime)。我只需要在应用程序的开始时,因为然后我在最后添加并从开始删除。

3

对于这种特殊的情况,容器将有〜2个元素,这一点不重要。枚举文件和删除文件的时间将比您选择的算法和数据结构慢几个数量级。只需将文件名放在std::vector中,使用std::sort(它将对日志文件名进行排序,以便最早出现),然后删除N-2个第一项。任务完成。

但对于一些普遍性的建议:

这几天一般建议似乎是std::vectorstd::list更好,甚至很多事情std::list看起来这将是很好的,主要原因是事实,即它是连续的存储这对缓存更友好。

有可能构建的基准会显示std::list更快,但是如果您选择std::vector来做所有事情,您不会错得太远!

如果您需要随时间维护一个容器并始终需要能够移除最小/最大的元素,std::priority_queue可能是个不错的主意。

如果您需要查找容器中的N个最小/最大物品,std::partial_sort是一种算法;它会比完整的std::sort快,因为它不会浪费精力排序你不关心的元素。

但是就像所有这样的一般性能问题,唯一正确的答案是“试试它,看看”我害怕!

编辑:我最初建议boost::circular_buffer,因为这就是问题的表现,但现在很清楚,它不是一个好建议,因为排序需要通过排序来创建,而不是通过插入顺序来创建。

+0

它可以排序吗?我需要在创建时对它进行排序 – sop 2014-12-04 16:27:46

+1

我已阅读您的新评论和更新的问题,它看起来像'boost :: circular_buffer'实际上不是您要找的 - 我会更新我的答案。如果你正在寻找一个总是排序的容器,'std :: priority_queue'可能更合适。但实际上,我个人通过将文件名放在'std :: vector'中,用'std :: sort'对其进行排序,然后迭代第一个N-2项并删除它们;任务完成。我向你保证,文件的枚举和删除将比你选择的数据结构慢许多个数量级。 – 2014-12-05 09:02:01

+1

另外...严重的是,不要为这个问题做这件事,但如果你遇到一种情况,你需要从一个容器中选择N个最小/最大的项目,并且你需要快速完成,那么算法可能会是'std :: partial_sort' - 它不会浪费时间对容器中不需要排序的部分进行排序。老实说,对于这个问题,它比它的价值更麻烦。 – 2014-12-05 09:03:43

0

没有真的在这里得到它,那家伙需要的名字比较2个文件,而不是数据结构教训

使用string ::比较比较的文件,是的,它会在年底比较这些数字你的日志文件太大,所以不要担心

这里是如何工作的

value=String.Compare(filenameA,filenameB) 



    If value<0 then print("filenameA is smaller than filenameB") 
    If value>0 then print("a is bigger than b") 
    If value=0 then print("a equals b") 

噢,对数据结构的选择,你不需要关心效率,或性能问题 我的意思你只是ind按名称exing 2个文件的简单和简陋的阵列会做的伎俩

这里就如何做到这一点

putNewFileMethod(FileType* arrayofFiles,FileType MynewFile)` 
{ 



String nameOfFile0=arrayOfFiles[0].method_that_retrieves_the_filename(); 
String nameOfFile1=arrayOfFiles[1].method_that_retrieves_the_filename();//you can search for a method of this kind in the docs of the api you are using,` 

int value=String.Compare(nameOfFile0,nameOfFile1); 

     If(value<0) 
     arrayOfFiles[0]=MynewFile; 
else arratOfFiles[1]=MynewFile; 


} 

附加注释的一个例子:

您可以使用2的圆形阵列不需要对文件进行排序,但是您提到了有关重新启动应用程序的一些信息,所以我想这不是您的最佳解决方案, (如果您想要圆形阵列/缓冲区示例,请告诉我)

层数据结构不来的buildin排序功能,至少大部分,所以你只要做你自己的一个

+1

如果你出于某种原因希望通过在日志文件标题中添加随机格式来让生活更加艰难,就像log_iLikeRandomNames.log试试这个日期检索方法,它通过路径工作,因此您不必提供File对象[link] http ://msdn.microsoft.com/en-us/library/system.io.file.getcreationtime(v = vs.110).aspx – 2014-12-04 22:09:36

+0

好评。其实我已经使用了Boost和'last_write_time()'函数,我会发布我的方法。关于你的回答,我并不完全赞同字符串比较,我添加了最后一个的例子是原因 – sop 2014-12-05 08:28:14