我有一个大的向量(mainvect)的struct info对象(大约8百万元素),我想删除重复项,结构由pid和uid组成。
struct info
{
int pid;
string uid;
}
我有另一个向量( vect1 ),其中包含每个pid的信息及其在mainvect中的出现(其搜索特定索引的帮助并非所有主要vect)vect1的大小为420k元素
struct pidInfo
{
int pid;
int numofoccurence;
}
我想在 vect2 中将unqiue元素存储在mainvect中。
.
.
// sort mainvect based on pid
sort(mainvect.begin(), mainvect.end(), sortByPId());
int start = 0;
int end = 0;
vector <string> temp; // to store uids with a specific pid
for (int i = 0; i < vect1.size(); i++)
{
end = end + vect1[i].numofoccurence;
for (int j = start; j < end; j++)
{
temp.push_back(mainvect[j].uid);
}
start = start + vect1[i].numofoccurence;
// remove duplicate uid
sort(temp.begin(), temp.end());
temp.erase(unique(temp.begin(), temp.end()), temp.end());
// push remaining unique uids
for (int k = 0; k < temp.size(); k++)
{
info obb;
obb.pid = vect1[i].pid;
obb.uid = temp[k];
vect2.push_back(obb);
}
// empty the temp vector to use in next i iteration
temp.erase(temp.begin(), temp.end());
}
.
.
答案 0 :(得分:3)
你的内存不足。你可以做的事情很少:
x64
的项目创建新配置。std::vector
替换为std::dequeu
以获取大型向量。 std::vector
的问题在于,每次增长时都会分配一个新的内存块并复制所有数据。您正在使用的MSVC实现每次增长1.5倍。因此,如果向量占用1 GB的内存,下次调整大小时,它将尝试分配1.5 GB,在调整大小时正在进行2.5 GB的RAM。
std::deque
的实现通常会在较小的块中分配内存,因此调整大小的问题会更少。
你需要注意的另一件事是std::string
。 MSVC实现使用SSO (Small-String-Optimization)。 Every instance of
std :: string` afair在x86上占用32个字节。因此,你的800万元素向量中的每个元素都可能会或可能不会浪费这些记忆。
根据您希望在计划上花费的时间,您可能想了解memory-mapped files。
答案 1 :(得分:3)
我认为你确实有算法问题。在每次迭代中,您要排序并在temp
向量中仅保留唯一元素。但是使用这种方法,每次迭代都会在vect2
中添加越来越多的重复项。因此,您应该在vect2
中排序并仅保留唯一元素。实际上,利用std::set
代替temp
和vect2
可能会更好。
另一个建议是如果它具有某种修复长度格式(如GUID),则可以为uid使用更好的存储。
答案 2 :(得分:1)
如上所述,您的内存不足。如果你真的有这么多元素,那么研究一个像sqlite这样的小型数据库可能是一个明智的想法。
但是由于问题是关于C ++标准容器,所以你正在接近这个问题。你正在做许多不必要的排序和循环。不仅充满了bug,你的算法至少是O(n ^ 3)
为什么不使用已经排序的容器之一,例如std :: map?您可以像这样重复列出一个列表:
std::vector<info> input;
// copy into map
std::map<int, info> tmp;
for (info& i : mainvect) {
tmp[i.pid] = i;
}
// copy back out
std::vector<info> output(tmp.size());
std::transform(tmp.begin(), tmp.end(), output.begin(), [] (const std::pair<int, info>& p) {
return p.second;
});
代码不仅更清晰,而且运行在O(n + ln(n))。或者,跳过第二步,首先使用std :: map或std :: set作为数据。
此外,如果你处理大量的物品,你也不想使用std :: vector。关键问题是向量的内存需要是一块连续的内存。您可能想要使用双端队列或列表。