首页 / 知识
关于C#:帮助合并向量的算法
2023-04-16 23:02:00

Help with algorithm for merging vectors我需要一个非常快速的算法来完成以下任务。我已经实现了几种算法来完成它,但是它们对于我所需的性能来说太慢了。它应该足够快,以使算法可以在现代CPU上每秒至少运行100,000次。它将在C中实现。 我正在使用跨度/范围,这是一种在一条线上具有起点和终点坐标的结构。 我有两个跨度的向量(动态数组),我需要将它们合并。一个向量是src,另一向量是dst。向量按跨度开始坐标排序,并且跨度在一个向量内不重叠。 必须将src向量中的跨度与dst向量中的跨度合并,以使所得向量仍被排序且没有重叠。 IE。如果在合并过程中检测到重叠,则将两个跨度合并为一个。 (合并两个跨度仅是更改结构中的坐标的问题。) 现在,还有一个问题,在合并过程中,必须"扩大" src向量中的跨度。这意味着一个常量将被添加到src中每个跨度的开始坐标,另一个(较大)常量被添加到结束坐标。这意味着在src跨度扩大后,它们可能会重叠。 到目前为止,我得出的结论是它不能完全就地完成,需要某种临时存储。我认为它应该在线性时间内超过src和dst元素的总和是可行的。 该算法的多次运行之间可能共享任何临时存储。 我尝试过的两种主要方法(太慢了)是: 将src的所有元素附加到dst,然后在附加每个元素之前将其扩展。然后运行就地排序。最后,使用"读"和"写"指针对结果向量进行迭代,使读指针在写指针之前运行,并合并跨度。当所有元素都已合并(读取指针到达末尾)时,dst将被截断。 创建一个临时工作向量。如上所述,通过反复从src或dst中选取下一个元素并合并到工作向量中,进行幼稚的合并。完成后,将工作向量复制到dst,以替换它。 第一种方法的问题是排序是O((m n)* log(m n))而不是O(m n),并且有一些开销。这也意味着dst向量必须增长得比实际需要大得多。 第二个主要问题是大量复制并再次分配/取消分配内存。 如果需要,可以更改用于存储/管理跨度/矢量的数据结构。 更新:忘记说数据集有多大。在两个向量中,最常见的情况是在4到30个元素之间,并且dst为空或src和dst的跨度之间存在大量重叠。 我们知道,绝对最佳的运行时是O(m n),这是因为您至少必须扫描所有数据才能合并列表。鉴于此,您的第二种方法应为您提供这种类型的行为。 您是否介绍了第二种方法来找出瓶颈?实际上,根据您正在谈论的数据量,实际上不可能在指定的时间内完成您想要的操作。一种验证方法是做一些简单的事情,例如对循环中每个向量中跨度的所有开始和结束值求和,并对时间进行计时。基本上,这里您对向量中的每个元素都进行了最少的工作。这将为您提供可望获得的最佳性能的基准。 此外,您可以避免使用stl swap方法逐个复制vectors,并且可以将temp向量预分配为一定大小,以避免合并元素时触发数组扩展。铅> 您可能会考虑在系统中使用2个向量,并且每当需要进行合并时,都将合并到未使用的向量中,然后交换(这类似于图形中使用的双缓冲)。这样,您不必在每次合并时都重新分配向量。 但是,最好先进行概要分析,然后找出瓶颈。如果与实际的合并过程相比分配量很少,那么您需要弄清楚如何更快地进行分配。 直接访问向量原始数据可能会带来一些额外的提速,从而避免了每次访问数据时的边界检查。 您的目标系统是什么?是多核吗?如果是这样,您可以考虑对该算法进行多线程处理 我将始终对跨度矢量进行排序。这使得实现算法更容易-并且可以在线性时间内完成。 好,所以我根据以下内容对跨度进行排序:
您需要创建一个函数来执行此操作。 然后,我将使用std :: set_union合并向量(在继续之前,您可以合并多个向量)。 然后对于具有相同最小值的每个连续范围的跨度,保留第一个范围并删除其余部分(它们是第一个范围的子范围)。 然后,您需要合并跨度。现在应该可以在线性时间内实现了。 好的,这就是窍门。不要尝试就地执行此操作。使用一个或多个临时向量(并提前保留足够的空间)。然后最后调用std :: vector :: swap将结果放入您选择的输入向量中。 我希望这足以使您前进。 我专门针对此算法编写了一个新的容器类,以适应需要。这也使我有机会调整程序周围的其他代码,这些代码同时提高了一点速度。 这比使用STL向量的旧实现要快得多,但在其他方面基本上是相同的。但是,虽然速度更快,但仍然还不够快...不幸的是。 分析不再显示什么是真正的瓶颈。 MSVC探查器有时有时会把错误归咎于错误的调用(假设相同的运行分配了截然不同的运行时间),并且大多数调用已合并为一个大问题。 查看生成的代码的反汇编表明,生成的代码中存在大量跳跃,我认为这可能是现在速度缓慢的主要原因。
如果您最近的实现仍然不够快,您可能最终不得不考虑其他方法。 此功能的输出用于什么? 1是正确的-完全排序比合并两个排序的列表要慢。 因此,您正在查看调整2(或全新的内容)。 如果将数据结构更改为双向链表,则可以在恒定的工作空间中合并它们。 为列表节点使用固定大小的堆分配器,既可以减少每个节点的内存使用量,又可以提高节点在内存中相互靠近的机会,从而减少页面遗漏。 您也许可以在线上或在自己喜欢的算法书中找到代码,以优化链接列表合并。您将需要对此进行自定义,以便在列表合并的同时进行跨度合并。 为优化合并,首先请注意,对于来自同一侧的值的每次运行而没有来自另一侧的值的运行,您可以一次将整个运行插入dst列表,而不必依次插入每个节点。而且您可以在正常的列表操作中为每次插入节省一次写入操作,只需在结尾处保持"悬挂"即可,因为您知道稍后会对其进行修补。并且只要您不删除应用程序中的其他任何地方,该列表就可以单链接,这意味着每个节点一次写入。 对于10微秒的运行时间-取决于n和m ... 我认为严格的线性解决方案是不可能的,因为在最坏的情况下扩宽src向量跨度可能会导致它们全部重叠(取决于您要添加的常数的大小) 问题可能出在实现中,而不是算法中;我建议为您先前的解决方案分析代码,以了解时间花在哪里 原因: 对于运行在3.2GHz的真正"现代" CPU(例如Intel Core 2 Extreme QX9770),可以期望达到约59,455 MIPS。 对于100,000个向量,您将必须以594,550指令处理每个向量。那是很多指令。 ref:维基百科MIPS 此外,请注意,将常量添加到src向量跨度不会对其进行排序,因此您可以独立地标准化src向量跨度,然后将它们与dst矢量跨度合并;这样可以减少原始算法的工作量 在方法1中提到的排序可以减少为线性时间(从描述的对数线性化),因为两个输入列表已经进行了排序。只需执行合并排序的合并步骤。使用输入跨度矢量的适当表示形式(例如单链接列表),可以就地完成此操作。 http://en.wikipedia.org/wiki/Merge_sort 没有重复分配的第二种方法怎么样?换句话说,一次分配您的临时向量,而不再分配它呢?或者,如果输入向量足够小(但不是恒定大小),则只需使用alloca而不是malloc。 此外,在速度方面,您可能要确保代码使用CMOV进行排序,因为如果代码实际上是为mergesort的每个单次迭代而分支的:
分支预测将在50%的时间内失败,这将对性能造成巨大影响。有条件的移动可能会做得更好,因此请确保编译器正在执行此操作,否则,请尝试诱使它这样做。 |
最新内容
相关内容
linux运行图形界命令?
linux运行图形界命令?,系统,密码,地址,电脑,图形界面,地方,工具,界面,终端,图形,linux图形化界面命令第一种方式比较简单,只需要选择相应的带图linux怎样运行命令?
linux怎样运行命令?,系统,工作,信息,基础,地址,命令,目录,工具,密码,一致,Linux系统基础操作指令1、linux常用命令有pwd命令、cd命令、ls命令linux编译完运行命令?
linux编译完运行命令?,系统,代码,环境,工具,信息,命令,文件,程序,终端,编辑,在linux中编译C输入完程序后输入个:wq然后按什么键就然后就回到了linux命令程序运行?
linux命令程序运行?,状态,系统,服务,情况,命令,进程,软件,数据,发行,时间,Linux中如何启动进程?进程调度命令有哪些?实现调度启动进程的方法有linux测试性能命令?
linux测试性能命令?,系统,网络,信息,工具,状态,地址,指标,情况,分析,下行,五个Linux简单命令帮你解决系统性能问题VMSTAT命令擅长用来查询CPUlinux合并行命令行?
linux合并行命令行?,工作,系统,地址,信息,文件,代码,目录,命令,功能,内容,Linux怎么用命令合并多个文件为一个1、将两个文件filetxt和filetxtlinux运行多个命令?
linux运行多个命令?,环境,软件,系统,工作,服务,连续,命令,指令,分号,冲突,linux多个用户同时执行命令会冲突吗不会冲突。解释:用户登录linux的linux运行命令查看?
linux运行命令查看?,系统,信息,状态,命令,名称,情况,地址,软件,进程,第一,linux查看进程命令首先打开xshell软件,连接上linux服务器,使用指令pslinux中命令运行软件?
linux中命令运行软件?,软件,系统,名称,工具,电脑,位置,环境,中心,在线,初级,如何用命令行在Linux下安装软件?首先启动CentOS7,在VMware中点击上脚本linux上运行命令?
脚本linux上运行命令?,工具,代码,时间,密码,系统,环境,名字,位置,第三,下来,typescript脚本中怎样运行Linux命令?1、Script可用于记录当前用户linux运行命令的脚本?
linux运行命令的脚本?,系统,服务,工具,脚本,意外,技术,分析,文件,方法,命令,sh文件在linux下如何运行Linux下面运行 SH文件步骤如下:查看目录shlinux影藏运行命令?
linux影藏运行命令?,档案,电脑,标准,设备,代码,工具,系统,查询系统,暂停,命令,linux查询系统所有隐藏档案(不包括目录)的命令1、可以使用find