2014-12-04 110 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