Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 计算两个向量的指数';有效的公共元素_C++_Vector_Unordered Set - Fatal编程技术网

C++ 计算两个向量的指数';有效的公共元素

C++ 计算两个向量的指数';有效的公共元素,c++,vector,unordered-set,C++,Vector,Unordered Set,我有两个向量(每个向量只有唯一的元素),它们共享一组整数。我想尽可能有效地计算一个向量的元素的指数,这些元素也存在于另一个向量中。你能比我拙劣低效的实现做得更好吗 编辑: 向量没有排序,我们需要未排序向量的索引。此外,在解决问题时,禁止修改初始向量(random_vec_1和random_vec_2) #包括 #包括 #包括 #包括 #包括 #包括 使用名称空间std::chrono; int main(){ //设置1:用随机整数构造两个向量。 constexpr size\u t num=1

我有两个向量(每个向量只有唯一的元素),它们共享一组整数。我想尽可能有效地计算一个向量的元素的指数,这些元素也存在于另一个向量中。你能比我拙劣低效的实现做得更好吗

编辑: 向量没有排序,我们需要未排序向量的索引。此外,在解决问题时,禁止修改初始向量(
random_vec_1
random_vec_2

#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std::chrono;
int main(){
//设置1:用随机整数构造两个向量。
constexpr size\u t num=1000;
std::随机_装置rd;
标准:mt19937 gen(rd());
std::均匀分布分布dis(0,num);
std::向量随机向量1;
std::向量随机向量2;
随机向量1.保留(num);
随机向量2.保留(num);
对于(大小i=0u;istd::cout
向量
现在太快了,我不会使用
集合

  • 将第一个向量复制到,例如
    新向量_1
  • 排序
    new_vector_1
  • 使用
    binary\u search
    new\u vector\u 1
    中查找值
  • 代码:

    std::vector<int> new_vec_1(random_vec_1);
    std::sort(std::begin(new_vec_1), std::end(new_vec_1));
    std::vector<size_t> match_index_2;
    match_index_2.reserve(random_vec_2.size());
    
    for (size_t i = 0; i < random_vec_2.size(); ++i) {
        if (std::binary_search(std::begin(new_vec_1), 
                               std::end(new_vec_1),
                               random_vec_2[i])) {
            match_index_2.push_back(i);
        }
    }
    

    实际上,我希望对向量进行排序大大优于创建
    std::set
    ,因为STL集是一棵树,而
    int
    向量可以使用计数排序在线性时间内进行排序,如果您的计数不超过1,则将得到一个集合。创建集合是O(n log n)对于成本日志n的n个插入,排序为O(n),如上所述

    在排序的向量上,您可以运行
    std::set_difference
    ,它也应该与两个输入中的较大值在时间上线性运行

    因此,你应该能够在线性时间内做到这一点

    如果不能修改向量,可以使用hashmap(std::unordered_-map)将值映射到原始向量中的索引。请注意,由于您没有提到数字是唯一的,因此您会发现两个集合中都包含值x_1,…,x_n,然后您将使用该映射使用hashmap将其投影回原始向量中的索引。

    新答案 新的要求是,在计算解时不能修改原始向量。由于索引混淆,排序交集解不再有效

    以下是我的建议:使用
    无序映射将第一个向量值映射到相应的索引,然后运行第二个向量值

    // Not necessary, might increase performance
    match_index_2.reserve(std::min(random_vec_1.size(), random_vec_2.size()));
    
    std::unordered_map<int, int> index_map;
    // random_vec_2 is the one from which we want the indices.
    index_map.reserve(random_vec_2.size());
    for (std::size_t i = 0; i < random_vec_2.size(); ++i) {
        index_map.emplace(random_vec_2[i], i);
    }
    
    for (auto& it : random_vec_1) {
        auto found_it = index_map.find(it);
        if (found_it != index_map.end()) {
            match_index_2.push_back(found_it->second);
        }
    }
    
    改编自

    以下是另一个版本,改编自:


    您可以将索引创建到值集中,并对这些值进行操作:

    #include <algorithm>
    #include <vector>
    
    inline std::vector<std::size_t>  make_unique_sorted_index(const std::vector<int>& v) {
        std::vector<std::size_t> result(v.size());
        std::iota(result.begin(), result.end(), 0);
        std::sort(result.begin(), result.end(),
            [&v] (std::size_t a, std::size_t b) {
                return v[a] < v[b];
        });
        auto obsolete = std::unique(result.begin(), result.end(),
            [&v] (std::size_t a, std::size_t b) {
                return v[a] == v[b];
        });
        result.erase(obsolete, result.end());
        return result;
    }
    
    // Constructs an unordered range of indices [i0, i1, i2, ...iN) into the first set
    // for elements that are found uniquely in both sets.
    // Note: The sequence [set1[i0], set1[i1], set1[i2], ... set1[iN]) will be sorted.
    std::vector<std::size_t>  unordered_set_intersection(
        const std::vector<int>& set1,
        const std::vector<int>& set2)
    {
        std::vector<std::size_t> result;
        result.reserve(std::min(set1.size(), set2.size()));
        std::vector<std::size_t> index1 = make_unique_sorted_index(set1);
        std::vector<std::size_t> index2 = make_unique_sorted_index(set2);
    
        auto i1 = index1.begin();
        auto i2 = index2.begin();
        while(i1 != index1.end() && i2 != index2.end()) {
            if(set1[*i1] < set2[*i2]) ++i1;
            else if(set2[*i2] < set1[*i1]) ++i2;
            else {
                result.push_back(*i1);
                ++i1;
                ++i2;
            }
        }
        result.shrink_to_fit();
        return result;
    }
    
    如果索引是唯一的或不是唯一的,则该算法产生稳定的结果:

    • 元素的排序(结果索引指向)与std::sort一样稳定
    • 如果索引不是唯一的,则相同元素的数量(结果索引指向)分别是第一组或第二组中相同元素的最小数量

    也可以看一下:你可以考虑在@ diutl u上的例子,这些链接没有帮助。<代码>:STD::包含告诉你第二个范围是否包含在第一个范围内,这是无关的。<代码> STD::独特的< /代码>从一个范围中移除连续的重复,这是更不相关的。向量不是为我的真实而排序的。问题。设置交叉点(不包括)is:一般来说,我处理的向量没有排序。我只需要构造一个玩具示例,并使用
    std::set
    。@MrX你在编辑中说你需要未排序向量的索引。但是你当前的解决方案对向量进行排序。那么,排序可以吗?还是你希望原始向量不被碰?我拿了个大问题这里没有,但我怀疑另一种算法是否优于排序,并且使用
    set\u intersection
    @MrX Nelxiost的方法很好,您的要求与您当前的解决方案相冲突。Nelxiost:
    set\u intersection
    为您提供两个排序范围的通用值,而不是一个向量的索引,这也与要求。我的解决方案(而不是设置)也适用于未排序的向量。我只是为问题设置添加了一个随机洗牌,以使其更清晰。我的错误。我编辑了,以便您获得索引而不是值。我删除了带有
    set\u intersection
    的部分,因为您无法将其用于问题(可能通过创建特殊的输出迭代器除外)。@MrX您没有回答。是否要求原始向量保持未排序?计数排序仅适用于小值范围。MrX使用的范围非常小(0…1000),但可能值得注意的是,用户可能无法自由做出这样的假设。向量的一般排序上限也是O(n log n)。使用哈希映射作为计数器,可以将其应用于相当大的范围(2^xxx)同样,只要它们足够稀疏。当然,内存成本与符号(数字)的大小成线性关系,但通常情况下,这是可行的。例如,对于所有整数,在16GB内存中最多可以计算2^32次。由于OP需要一个集合,他实际上只需要一位来表示存在/不存在,即m
    match_index_2.reserve(std::min(random_vec_1.size(), random_vec_2.size()));
    
    constexpr std::size_t unmapped = -1; // -1 or another unused index
    // Since std::size_t is an unsigned type, -1 will actually be the maximum value it can hold.
    
    std::vector<std::size_t> index_map(num, unmapped);
    for (std::size_t i = 0; i < random_vec_2.size(); ++i) {
        index_map[random_vec_2[i]] = i;
    }
    
    for (auto& it : random_vec_1) {
        auto index = index_map[it];
        if (index != unmapped) {
            match_index_2.push_back(index);
        }
    }
    
    auto first1 = random_vec_1.begin();
    auto last1 = random_vec_1.end();
    auto first2 = random_vec_2.begin();
    auto last2 = random_vec_2.end();
    auto index_offset = first1; // Put first2 if you want the indices of the second vector instead
    
    while (first1 != last1 && first2 != last2)
        if (*first1 < *first2)
            ++first1;
        else if (*first2 < *first1)
            ++first2;
        else {
            match_index_2.push_back(std::distance(index_offset, first1));
            ++first1;
            ++first2;
        }
    }
    
    auto first1 = random_vec_1.begin();
    auto last1 = random_vec_1.end();
    auto first2 = random_vec_2.begin();
    auto last2 = random_vec_2.end();
    auto index_offset = first1; // Put first2 if you want the indices of the second vector instead
    
    while (first1 != last1 && first2 != last2) {
        if (*first1 < *first2) {
            ++first1;
        } else  {
            if (!(*first2 < *first1)) {
                match_index_2.push_back(std::distance(index_offset, first1++));
            }
            ++first2;
        }
    }
    
    // Setup 2: Make elements unique.
    auto first1 = random_vec_1.begin();
    auto last1 = random_vec_1.end();
    std::sort(first1, last1);
    last1 = std::unique(first1, last1);
    random_vec_1.erase(last1, random_vec_1.end());
    
    auto first2 = random_vec_2.begin();
    auto last2 = random_vec_2.end();
    std::sort(first2, last2);
    last2 = std::unique(first2, last2);
    random_vec_2.erase(last2, random_vec_2.end());
    
    #include <algorithm>
    #include <vector>
    
    inline std::vector<std::size_t>  make_unique_sorted_index(const std::vector<int>& v) {
        std::vector<std::size_t> result(v.size());
        std::iota(result.begin(), result.end(), 0);
        std::sort(result.begin(), result.end(),
            [&v] (std::size_t a, std::size_t b) {
                return v[a] < v[b];
        });
        auto obsolete = std::unique(result.begin(), result.end(),
            [&v] (std::size_t a, std::size_t b) {
                return v[a] == v[b];
        });
        result.erase(obsolete, result.end());
        return result;
    }
    
    // Constructs an unordered range of indices [i0, i1, i2, ...iN) into the first set
    // for elements that are found uniquely in both sets.
    // Note: The sequence [set1[i0], set1[i1], set1[i2], ... set1[iN]) will be sorted.
    std::vector<std::size_t>  unordered_set_intersection(
        const std::vector<int>& set1,
        const std::vector<int>& set2)
    {
        std::vector<std::size_t> result;
        result.reserve(std::min(set1.size(), set2.size()));
        std::vector<std::size_t> index1 = make_unique_sorted_index(set1);
        std::vector<std::size_t> index2 = make_unique_sorted_index(set2);
    
        auto i1 = index1.begin();
        auto i2 = index2.begin();
        while(i1 != index1.end() && i2 != index2.end()) {
            if(set1[*i1] < set2[*i2]) ++i1;
            else if(set2[*i2] < set1[*i1]) ++i2;
            else {
                result.push_back(*i1);
                ++i1;
                ++i2;
            }
        }
        result.shrink_to_fit();
        return result;
    }
    
    inline std::vector<std::size_t>  make_sorted_index(const std::vector<int>& v) {
        std::vector<std::size_t> result(v.size());
        std::iota(result.begin(), result.end(), 0);
        std::sort(result.begin(), result.end(),
            [&v] (std::size_t a, std::size_t b) {
                return v[a] < v[b];
        });
        return result;
    }