C++ 这个向量以前发生过吗

C++ 这个向量以前发生过吗,c++,vector,stl,implementation,C++,Vector,Stl,Implementation,我有很多向量(以10^4的顺序,甚至更多!),我将从流的输入中获得更多向量。比如说,我有 v1=10411 v2=1125362 v3=01150 我有10^4个这样的向量 现在,我输入一个向量,我想检查它以前是否出现过,你建议我怎么做 我将列出我想到的技术,以及伴随这些技术而来的错误: 使用std::map,或std::set。但是,std::map std::set不支持向量作为参数 要将向量中的每个整数转换为字符串类型,请按顺序追加它们并将字符串存储在映射中。错误:v5=11 1和v

我有很多向量(以10^4的顺序,甚至更多!),我将从流的输入中获得更多向量。比如说,我有

  • v1=10411
  • v2=1125362
  • v3=01150
我有10^4个这样的向量 现在,我输入一个向量,我想检查它以前是否出现过,你建议我怎么做

我将列出我想到的技术,以及伴随这些技术而来的错误:

  • 使用
    std::map
    ,或
    std::set
    。但是,
    std::map std::set
    不支持向量作为参数
  • 要将向量中的每个整数转换为字符串类型,请按顺序追加它们并将字符串存储在映射中。错误:
    v5=11 1
    v6=1 1
    的情况将显示为相同
  • 与上面类似,只是在每个整数后添加一个分隔符。错误:太单调而无法编码
我想知道你是否能想出一些方法来达到这个目的

编辑:
对于10^4,这是可以实现的。我的新任务要求我最多存储10^9。我个人认为STL没有那么大的空间,他们抛出了错误。你知道在这种情况下还有其他有效的散列方法吗?

这是一种非常简单的方法,但我正在尝试使用从折叠和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

我知道可以有很多改进,在某些情况下可能会失败。这只是尝试之一。请随意批评并帮助我改进

如果您定义向量的完整顺序,您可以通过两种方式进行合理有效的查找:

  • 将现有向量存储在
    std::set
    std::map
    中。这些是有序的容器类,具有相当有效的成员资格/查找方法
  • 将现有向量按排序顺序存储在
    std::vector
    中,并使用
    std::binary\u search

对向量排序的默认选择是字典顺序。这是由
操作符提供的。实现这一点的简单方法是将向量存储在另一个向量中,并使用std::sort()函数族,使用std::lexigraphical_compare作为排序谓词,保持向量的顺序。这将允许在O(log(n))摊销时间内对列表进行二进制搜索,代价是半昂贵的排序操作,这可能通过在加载向量列表时对其进行重分类或分区来减少

但是,比这更有效的方法是将向量存储为trie(),其中沿trie的每条路径都存储来自向量的唯一序列。根据数据中的差异,这可能更节省空间,并且加法和搜索都是O(log(n))操作

不过,请恕我直言,10^4元素实际上是一个很小的数字。我的经验是,排序和搜索算法的效率差异只有在数据集在10^6-10^7范围内时才会在现代硬件上显现出来。在这个规模之下,最简单、最友好的缓存算法往往胜出


另一种选择是,如果你只是追求原始速度,而你要扫描的向量列表是众所周知的静态的,那就是使用有限状态机来接受/拒绝你的输入。像Ragel这样的工具可以很快解决这些问题。

将向量转换为逗号分隔的字符串应该不会很繁琐。这似乎是解决这个问题的最简单的方法。我认为散列函数会帮助你考虑在TIE结构中存储向量。然后你可以很容易地检查它effeciently@hiteshn97是什么让您认为
std::set
不是有效的类型?这里
namespace std{templatebool operator注意到您使用了a.cbegin()而不是a.begin(),是否有特定原因?或者只是个人选择?可能是为了确保不更改向量的内容?可能是因为您通过引用传递。是否正确?为什么在这种情况下返回true?
if(*a_it<*b_it)return true;
考虑字母顺序:确定
是否“cat”
,您首先检查
'c'
。如果是这样,您就知道
“cat”
排在第一位--您不需要检查任何其他字符,您知道结果是
true
。此外,我还使用了
cbegin()
强调输入是恒定的。我对向量的折叠不太了解。我尝试用谷歌搜索,但没有找到任何有用的资源。你能给我一个链接吗?你的算法的时间复杂度是多少。O(n)太大了!第一个方法。我没有得到它。我能理解的是你;重新排序向量,但是你的算法能区分{1,2,3}和{3,2,1}吗?
#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
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;
}