- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个函数,可以将网格中点列表的所有邻居移出一定距离,这涉及很多重复项(我邻居的邻居再次 == 我)。
我一直在尝试几种不同的解决方案,但我不知道哪个更有效。下面是一些代码,演示了两个并行运行的解决方案,一个使用 std::vector sort-unique-erase,另一个使用 std::copy 到 std::unordered_set。
我还尝试了另一种解决方案,即将包含到目前为止的邻居的 vector 传递给邻居函数,该函数将使用 std::find 确保在添加邻居之前不存在邻居。
所以三个解决方案,但我无法完全理解哪个会更快。任何人的想法?
代码片段如下:
// Vector of all neighbours of all modified phi points, which may initially include duplicates.
std::vector<VecDi> aneighs;
// Hash function, mapping points to their norm distance.
auto hasher = [&] (const VecDi& a) {
return std::hash<UINT>()(a.squaredNorm() >> 2);
};
// Unordered set for storing neighbours without duplication.
std::unordered_set<VecDi, UINT (*) (const VecDi& a)> sneighs(phi.dims().squaredNorm() >> 2, hasher);
... compute big long list of points including many duplicates ...
// Insert neighbours into unordered_set to remove duplicates.
std::copy(aneighs.begin(), aneighs.end(), std::inserter(sneighs, sneighs.end()));
// De-dupe neighbours list.
// TODO: is this method faster or slower than unordered_set?
std::sort(aneighs.begin(), aneighs.end(), [&] (const VecDi& a, const VecDi&b) {
const UINT aidx = Grid<VecDi, D>::index(a, phi.dims(), phi.offset());
const UINT bidx = Grid<VecDi, D>::index(b, phi.dims(), phi.offset());
return aidx < bidx;
});
aneighs.erase(std::unique(aneighs.begin(), aneighs.end()), aneighs.end());
最佳答案
这里的很大一部分可能取决于输出集的大小(反过来,这将取决于您采样的邻居的距离)。
如果它很小,(不超过几十个项目左右)您使用 std::vector
手动滚动的集合实现和 std::find
可能会保持相当的竞争力。它的问题在于它是一个 O(N2) 算法——每次插入一个项目时,您必须搜索所有现有项目,因此每次插入都与集合中已有项目的数量成线性关系。因此,随着集合变大,其插入项目的时间大致呈二次方增长。
使用 std::set
您每次插入只需进行大约 log2(N) 次比较而不是 N 次比较。这将整体复杂度从 O(N2) 降低到 O(N log N)。主要的缺点是它(至少在正常情况下)实现为由单独分配的节点组成的树。这通常会降低其引用的局部性——即,您插入的每个项目都将由数据本身加上一些指针组成,遍历树意味着跟随指针。由于它们是单独分配的,因此(当前)在树中相邻的节点在内存中很可能不会相邻,因此您会看到相当数量的缓存未命中。底线:虽然它的速度随着项目数量的增加而增长相当缓慢,但所涉及的常数相当大——对于少量项目,它开始时会相当慢(通常比你的手卷版本慢一点) )。
使用 vector/sort/unique 结合了前面每个的一些优点。将项目存储在一个 vector 中(每个项目没有额外的指针)通常会导致更好的缓存使用——相邻索引处的项目也位于相邻的内存位置,所以当你插入一个新项目时,新项目的位置很可能会已经在缓存中。主要的缺点是,如果您正在处理一个非常大的集合,这可能会使用更多的内存。当您插入每个项目时,集合消除重复项(即,只有在与集合中已有的任何项目不同时才会插入项目),这将插入所有项目,然后最后删除所有重复项。鉴于当前的内存可用性和我猜你可能正在访问的邻居数量,我怀疑这在实践中是一个主要缺点,但在错误的情况下,它可能会导致一个严重的问题——几乎所有虚拟内存的使用几乎肯定会使其成为净亏损。
从复杂性的角度来看最后一个,它将变成 O(N log N),有点像集合。不同之处在于,对于该集合,它实际上更像是 O(N log M),其中 N 是邻居的总数,而 M 是唯一邻居的数量。对于 vector ,它实际上是 O(N log N),其中 N 是(再次)邻居的总数。因此,如果重复的数量非常大,则集合可能具有显着的算法优势。
也可以在纯线性序列中实现类似集合的结构。这保留了集合仅存储唯一项的优势,也保留了 vector 的引用位置优势。这个想法是保持当前集合的大部分排序,所以你可以在 log(N) 复杂度中搜索它。但是,当您插入一个新项目时,您只需将其放入单独的 vector (或现有 vector 的未排序部分)中。当你做一个新的插入时,你也会对那些未排序的项目进行线性搜索。
当未排序的部分变得太大(对于“太大”的某些定义)时,您对这些项目进行排序并将它们合并到主组中,然后再次开始相同的序列。如果根据“log N”(其中 N 是已排序组中的项目数)定义“太大”,则可以将整个数据结构的复杂度保留为 O(N log N)。当我使用它时,我发现未排序的部分在它开始引起问题之前可能比我预期的要大。
关于c++ - vector 排序/唯一/删除与复制到 unordered_set 的性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17640107/
我正在尝试对每个条目有多个值的关联数组进行排序。 例如 [0] => stdClass Object ( [type] => node [sid] => 158 [score] => 0.059600
我在 mysql 中有“日期”列以这种格式保存日期 2014 年 9 月 17 日(日-月-年) 我需要对它们进行升序排序,所以我使用了这个命令: SELECT * FROM table ORDER
我目前正在将 MySQL 存储过程重写为 MS SQL 存储过程,但遇到了问题。 在 MySQL 存储过程中,有一个游标,它根据最近的日期 (effdate) 选择一个值并将其放入变量 (thestt
我想要 gwt r.QuestionId- 排序。但是我得到未排序的 QuestionId 尽管我提到了 QuestionId ASC 的顺序。 SELECT r.QuestionId,
我有一个关于在 scandir 函数中排序的基本问题。到目前为止,我阅读了 POSIX readdir 的手册页,但没有找到有关订购保证的具体信息。 但是当我遍历大目录(无法更改,只读)时,我在多个系
基本上我必须从 SQL 数据库中构建项目列表,但是用户可以选择对 7 个过滤器的任意组合进行过滤,也可以选择要排序的列以及按方向排序。 正如您可以想象的那样,这会以大量不同的组合进行编码,并且数据集非
我有两张 table 。想象第一个是一个目录,包含很多文件(第二个表)。 第二个表(文件)包含修改日期。 现在,我想选择所有目录并按修改日期 ASC 对它们进行排序(因此,最新的修改最上面)。我不想显
我想先根据用户的状态然后根据用户名来排序我的 sql 请求。该状态由 user_type 列设置: 1=活跃,2=不活跃,3=创始人。 我会使用此请求来执行此操作,但它不起作用,因为我想在“活跃”成员
在 C++ 中,我必须实现一个“类似 Excel/Access”(引用)的查询生成器,以允许对数据集进行自定义排序。如果您在 Excel 中使用查询构建器或 SQL 中的“ORDER BY a, b,
我面临这样的挑战: 检索按字段 A 排序的文档 如果字段 B 存在/不为空 . 否则 按字段排序 C. 在 SQL 世界中,我会做两个查询并创建一个 UNION SELECT,但我不知道如何从 Mon
我想对源列表执行以下操作: map 列表 排序 折叠 排序 展开 列表 其中一些方法(例如map和toList)是可链接的,因为它们返回非空对象。但是,sort 方法返回 void,因为它对 List
我制作了一个用于分析 Windows 日志消息编号的脚本。 uniq -c 数字的输出很难预测,因为根据数字的大小会有不同的空白。此时,我手动删除了空白。 这是对消息进行排序和计数的命令: cat n
我有以下词典: mydict1 = {1: 11, 2: 4, 5: 1, 6: 1} mydict2 = {1: 1, 5: 1} 对于它们中的每一个,我想首先按值(降序)排序,然后按键(升序)排序
我刚刚开始使用泛型,目前在对多个字段进行排序时遇到问题。 案例: 我有一个 PeopleList 作为 TObjectList我希望能够通过一次选择一个排序字段,但尽可能保留以前的排序来制作类似 Ex
有没有办法在 sql 中组合 ORDER BY 和 IS NULL 以便我可以在列不为空时按列排序,但如果它为null,按另一列排序? 最佳答案 类似于: ORDER BY CASE WHEN
我有一个包含 2 列“id”和“name”的表。 id 是常规的自动增量索引,name 只是 varchar。 id name 1 john 2 mary 3 pop 4 mary 5 j
场景 网站页面有一个带有分页、过滤、排序功能的表格 View 。 表中的数据是从REST API服务器获取的,数据包含数百万条记录。 数据库 REST API 服务器 Web 服务器 浏览器 问
假设我有一本字典,其中的键(单词)和值(分数)如下: GOD 8 DONG 16 DOG 8 XI 21 我想创建一个字典键(单词)的 NSArray,首先按分数排序,然后按字
如何在 sphinx 上通过 sql 命令选择前 20 行按标题 WEIGHT 排序,接下来 20 行按标题 ASC 排序(总共 40 个结果),但不要给出重复的标题输出。 我尝试了这个 sql 命令
我有一个奇怪的问题,当从 SQLite 数据库中选择信息并根据日期排序时,返回的结果无效。 我的SQL语句是这样的: Select pk from usersDates order by dateti
我是一名优秀的程序员,十分优秀!