![](/img/trans.png)
[英]C++/STL which algorithm should I use to check if a container has duplicates?
[英]Which STL container(s)/algorithm(s) could I use to solve this?
我有一個MFC項目,給出初始的根路徑,該項目遍歷每個文件,文件夾和子文件夾,然后在列表控件中向用戶顯示每個文件。 由於這很容易成為冗長的操作,因此我有時會控制操作系統(通過處理單個消息泵隊列),從而允許顯示到目前為止發現的每個元素。 現在來了棘手的部分...
我想讓元素按它們的最后一個已知修改時間戳進行排序,(我認為)這需要某種插入排序技術。 由於某些元素可能包含重復的時間戳,但文件路徑不同,並且我們將按時間戳(以MM:DD:YY hh:mm
格式存儲為std::string
進行排序,因此簡單的std::vector
不會似乎可以勝任這項工作。 另外,我不希望用戶在開始對元素進行排序之前不讓整個操作等待完成,因為等待的時間是未知的,並且就像我上面所說的那樣,很容易變得足夠長以至於使任何人都沒有耐心。
最后,我需要某種方法來保持插入到列表控件中的元素平均映射到容器上的排序操作,以便用戶可以實時查看根路徑的最新修改內容(和子內容)。
為了實現此目的,將使用什么合適的容器和算法?
這基本上是我現在正在做的:
void CFileSearchDlg::UpdateDirectoryList(std::string strRootPath)
{
CFilesystem fs; // Helper class which uses C++11 <filesystem> to iterate through file path entries
DWORD time = GetTickCount(); // Determines if we should yield control to the OS after a certain period of time
m_listView.DeleteAllItems(); // Clears all current elements from the list view control
/*
// CFilesystem::Search() takes in a root path and a lambda expression, and executes the expression for each
// element found within the root path, passing a basic_directory_entry<path> as a parameter to the lambda
// expression, and will continue to parse until no entries are left (or until we return false)...
*/
fs.Search(strRootPath, [&](CFilesystem::path_entry pe)
{
// This is primarily a Unicode project, so we need to convert the search results to an std::wstring
std::string path = pe.path().string();
std::wstring wpath;
wpath.assign(path.begin(), path.end());
// Get a Win32 handle to the file/folder, or display an error & exit
auto hFile = CreateFileA(path.c_str(), GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
MessageBoxA(NULL, "Failed to open file", path.c_str(), MB_OK | MB_ICONERROR);
return false; // Stop parsing
}
// Get the date & time attributes of the file/folder, or display an error & exit
TCHAR fileTime[MAX_PATH];
ZeroMemory(&fileTime, sizeof(TCHAR)* MAX_PATH);
auto ret = GetLastWriteTime(hFile, fileTime, MAX_PATH);
CloseHandle(hFile);
if (!ret) {
MessageBoxA(NULL, "Failed to get date & time attributes", path.c_str(), MB_OK | MB_ICONERROR);
return false; // Stop parsing
}
std::wstring strTime(fileTime);
/**************************************************
// THIS IS WHERE THE MAGIC IS SUPPOSED TO HAPPEN //
/*************************************************/
InsertPathItem(m_listView, wpath, strTime); // ... But how?
// Check if we should yield control to the operating system
auto tick = GetTickCount();
if (tick - time > 100) {
YieldControl();
time = tick;
}
// Continue to parse directory contents
return true;
}
);
}
編輯 :完整的答案似乎是galinette(關於適當的STL容器)和foraidt(關於將視圖與數據同步)的組合。
只需使用std::multimap
,其鍵類型為整數時間戳(最快的方式)或您建議的時間字符串(如果默認字符串排序保持時間戳順序(此速度較慢))
std::multimap<time_t, std::wstring>
要么
std::multimap<std::string, std::wstring>
插入:
myFileMap.insert(std::pair<time_t, std::wstring>(time,wPath));
一個std::set
使其元素根據其Comparator進行排序。
編輯:您需要提供一個嚴格小於確定性的比較器(忘記了數學術語)。 如果可能有多個相同的時間戳記,則需要消除另一個屬性的歧義(例如,一個id)。
要將MFC 控件的排序與內部數據結構同步 ,您可以嘗試使用虛擬列表:密鑰使用LVS_OWNERDATA
樣式。 然后,列表將不會單獨存儲項目數據,而是會回調您的代碼以獲取顯示項目所需的信息。 在這里,您可以跳入自定義排序的容器並檢索信息。
代碼項目上的“使用虛擬列表”一文似乎很全面。
接下來, 對自身進行排序 。 您可以嘗試一個自定義類型,其中包含要顯示的文本以及以數字格式排序的條件,例如:
struct item {
std::string label;
time_t mtime;
};
出於性能原因,在將控制權交還給OS之前,將多個項目插入向量中,然后對其進行一次排序可能會很有用。 但是,您必須測試它是否比直接插入已排序的容器是否更好地工作。
無論如何,要輕松地在容器類型之間切換,您可以指定可以用作排序謂詞的排序函子(使用C ++ 11 lambda可以做得更好):
struct item_less {
bool operator()(const item & a, const item & b) {
return a.mtime < b.mtime;
}
};
像這樣使用它:
std::set<item, item_less> a; // Automatic sorting
std::vector<item> b;
std::sort(a.begin(), a.end(), item_less()); // Manual sorting
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.