c++ - 在向量末尾找到一个周期的最大频率的最快方法?
问题描述
假设我有向量{ 1, 1, 2, 1, 1, 2 }
,我想找出向量末尾一个周期的最大频率。在这种情况下,频率(卷曲)为 2,因为112
重复了两次。而且由于任何重复至少两次的周期最多是向量长度的一半,所以我只需要扫描一半向量。
我正在寻找比较同一向量的各个部分的最快方法。根据最近的建议,我使用了std::equal()
,但我不知道这是否是最好的功能,或者我是否以最快的方式使用它。
这是我目前的功能:
vector<int> sequence = someVec;
int curl = 1;
for (int length = 1; length <= sequence.size()/2); ++length) {
int freq = 1;
while ((freq + 1) * length <= sequence.size() and std::equal(sequence.end() - (freq + 1) * length, sequence.end() - freq * length, sequence.end() - length)) {
++freq;
if (freq > curl) {
curl = freq;
}
}
}
while 循环看起来确实很可怕。基本上,它会尝试在向量序列的末尾找到匹配的周期,如果找到重复的周期,它会检查它延长了多长时间。任何关于更好实施或其他更快编写方法的建议都非常受欢迎!
根据要求提供一些示例:
假设向量序列是{ 1, 1, 2, 1, 1, 2 }
它开始检查2
向量末尾有多少个s,即1。接下来,它检查末尾有多少1, 2
个s,即1。接下来,它检查1, 1, 2
并发现这是重复的2次。因此,卷曲为 2。
假设向量序列是{ 2, 2, 2, 2 }
从它开始2
并找到其中的 4 个。接下来,它检查2, 2
并找到其中的 2 个。因此,卷曲为 4。
Since I have to find these curls for sequences up to about a length of 100 million, I really want to squeeze the most out of it. (I do use some mathematical approximation, but this part of the program still takes up about most of the time so I skipped that part).
解决方案
Now (as you no longer make copies of sub-vectors), almost all the time is spent in comparing values.
I see two independent ways to speed this up: vectorize the compare operation (if your compiler doesn't do it) and parallelize processing of different length
.
我实现了多线程。使用了 1,000,000 int
s 的向量,“最坏情况”全为零(因此每次比较都会运行子向量的全长)。单线程版本花了将近 3 分钟,12 线程(在我的 6 核上) - 不到 30 秒。矢量化应该至少可以节省 50%(根据我过去的实验)。请参阅此实施:https ://community.intel.com/t5/Intel-ISA-Extensions/Q-on-memory-comparison-optimization/td-p/1041997
这是我的代码(为简单起见,我使用了全局变量):
#include <iostream>
#include <vector>
#include <mutex>
#include <thread>
#include <atomic>
#include <chrono>
// worst case scenario - all zeroes
std::vector<int> s(1'000'000);
std::mutex m_curl;
unsigned int curl = 1;
std::atomic<int> length;
unsigned int get_curl(int length)
{
unsigned int local_curl = 1;
unsigned int freq = 1;
while ((freq + 1) * length <= s.size() and std::equal(s.end() - (freq + 1) * length, s.end() - freq * length, s.end() - length)) {
++freq;
if (freq > local_curl) {
local_curl = freq;
}
}
return local_curl;
}
void worker()
{
unsigned int thread_curl = 1;
while (true)
{
int current_length = length.fetch_sub(1);
if (current_length <= 0)
break;
int local_curl = get_curl(current_length);
if (local_curl > thread_curl) {
thread_curl = local_curl;
}
}
// sync access to the curl
{
std::lock_guard<std::mutex> l(m_curl);
if (thread_curl > curl) {
curl = thread_curl;
}
}
}
int main() {
auto t1 = std::chrono::high_resolution_clock::now();
length = s.size() / 2;
// create reasonable number of threads
static const int n = std::thread::hardware_concurrency();
std::vector<std::thread> threads;
for (int i = 0; i < n; ++i)
threads.emplace_back(std::thread(worker));
// wait for all of them to finish
for (int i = 0; i < n; ++i)
threads[i].join();
auto t2 = std::chrono::high_resolution_clock::now();
std::cout << std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count() << std::endl;
return curl;
}
推荐阅读
- python - Pyspark 根据列是否在另一个 Spark Dataframe 中创建新列
- google-oauth - 在获取 google OAuth 2.0 访问令牌方面需要帮助
- node.js - 在创建新的 Angular 项目时修复上游依赖冲突
- rebus - Rebus 第一级重试。有没有办法从以前的交付尝试中获得异常?
- reactjs - React-Select 无法自定义
- mysql - 无法使用 Spring、Hibernate 和 tomcat 9 运行 maven 项目
- html - PagedJS 覆盖 CSS
- azure - Azure 事件中心 - 即使轮换了客户端凭据,如何创建客户端
- javascript - × TypeError:无法解构'Object(...)(...)'的属性'currentUser',因为它是未定义的
- sql-server - 数据源包含处理操作不支持的 ImpersonationMode