我有很多向量(大约10 ^ 4,甚至更多!)而且我将从流中获得更多的向量输入。所以,例如,我有
v1 = 1 0 4 1 1
v2 = 1 1 2 5 3 6 2
v3 = 0 1 1 5 0
我有10 ^ 4个这样的载体
现在,我输入了一个向量v4 = 0 1 1 5 0
,我想检查它是否已经出现过,你是怎么建议我这样做的?
我将列出我想到的技术,以及伴随它们的错误:
std::map
或std::set
作为相同的内容。但是,std::map std::set
不支持向量作为参数。v5 = 11 1 1 1
和v6 = 1 1 1 1 1
的情况将显示为相同。我想知道你能想出一些实现这个目标的方法吗?
编辑: 对于10 ^ 4,它是可以实现的。我的新任务要求我存储最多10 ^ 9。我个人认为STL没有那么大的空间,他们抛出SIGABRT错误。你知道在这种情况下可以使用的任何其他有效的散列方法吗?
答案 0 :(得分:1)
这是非常初学的方法,但我正在尝试使用我从折叠和stl
中学到的东西方法说明:
1.处理了一个矢量列表(无论如何都可以输入)
2.保持主矢量v,它将存储主折叠矢量
3.使用stl包括在折叠前检查序列是否存在
输入集
std::vector<int> x ={1,2,3};
std::vector<int> y ={7,8,9};
std::vector<int> z ={1,2,3};
std::vector<int> a ={1,2,3};
std::vector<int> v5 = {11,1,1,1}; //as mentioned in question
std::vector<int> v6 = {1,1,1,1}; //as mentioned in question
方法
#include <iostream>
#include <vector>
#include <algorithm>
#include <list>
template <typename T>
void Concat(std::vector<T>& v, const std::vector<T>& v2)
{
v.insert(v.end(), v2.begin(), v2.end());
}
template <typename T>
void Concat(std::vector<T>& v, const T& value)
{
v.push_back(value);
}
template<typename T, typename... Args>
void push_back_vec(std::vector<T>& v, Args&&... args)
{
(Concat(v, args), ...);
}
int main()
{
std::vector<int> v;
std::list<std::vector<int> > m ;
std::vector<int> x ={1,2,3};
std::vector<int> y ={7,8,9};
std::vector<int> z ={1,2,3};
std::vector<int> a ={1,2,3};
std::vector<int> v5 = {11,1,1,1};
std::vector<int> v6 = {1,1,1,1};
m.push_back(x);
m.push_back(y);
m.push_back(z);
m.push_back(a);
m.push_back(v5);
m.push_back(v6);
for (std::list<std::vector<int> >::iterator it1 = m.begin(); it1 != m.end(); ++it1)
{
if (std::includes(v.begin(), v.end(), (*it1).begin(), (*it1).end()))
{
std::cout<<"Already present"<<std::endl;
}
else
{
push_back_vec(v,(*it1));
}
}
for (int i : v) std::cout << i << ' ';
}
输出
Already present
Already present
1 2 3 7 8 9 11 1 1 1 1 1 1 1 Program ended with exit code: 0
我知道可以有很多改进,但在某些情况下它可能会失败。这只是其中一个尝试随意批评并帮助我改进
答案 1 :(得分:1)
如果您在向量上定义完整的排序,则可以通过两种方式进行合理有效的查找:
std::set
或std::map
中。这些是有序的容器类,具有相当有效的成员资格/查找方法。std::vector
中按排序顺序存储现有向量,并使用std::binary_search
排序向量的默认选择是词典顺序。这是由operator<
实施提供的std::vector
提供的;它实际上做的是这样的:
bool operator<(const std::vector<int> &a, const std::vector<int> &b) {
auto a_it = a.cbegin();
auto b_it = b.cbegin();
while(a_it < a.cend() && b_it < b.cend()) {
if(*a_it < *b_it) {
return true;
}
if(*b_it < *a_it) {
return false;
}
++a_it;
++b_it;
}
if(a_it == a.cend() && b_it < b.cend()) {
return true;
}
return false;
}
请注意,此代码可以提前退出:如果输入向量的第一个元素不同,则无需进一步检查。只有存在长公共前缀(或者向量实际上是相同的)时才需要检查所有元素。
如评论中所述,您还可以通过以下方式解决此问题:
std::unordered_map
) - 要求您为std::vector<int>
std::
实施,您需要追踪图书馆或推出自己的答案 2 :(得分:1)
执行此操作的简单方法是将向量存储在另一个向量中,并使用std :: lexigraphical_compare作为排序谓词,使用std :: sort()函数系列维护该向量的顺序。这将允许以O(log(n))摊销时间对列表进行二进制搜索,这是以昂贵的半昂贵的排序操作,这可以通过使用堆积或分区您的矢量列表来玩一些游戏来减少你加载它。
然而,比这更有效的是将矢量存储为trie(https://en.wikipedia.org/wiki/Trie),其中trie下的每个路径都存储来自矢量的唯一序列。根据数据的差异,这可以更节省空间,添加和搜索都是O(log(n))操作。
以一粒盐为我的建议,然而,10 ^ 4个元素实际上是一个很小的数字。我的经验是效率分类和效率的差异。当您处于数据集的10 ^ 6-10 ^ 7范围内时,搜索算法才真正开始在现代硬件上展示自己。低于该规模,经常会使用最简单,最易于缓存的算法。
另一种选择,如果您只是为了获得原始速度,并且您要扫描的向量列表是众所周知的并且是静态的,那就是使用有限状态机来接受/拒绝您的输入。像Ragel这样的工具可以解决这些问题。