在下面的示例代码中,函数
Connection_S_optimized
可以在3秒内处理100000个Coor的数组,而原始代码需要55秒。
以下代码的主要思想是对端点进行排序并将其放入multimap中。节点1坐标和节点2坐标都放在同一个map中,注意它是哪个端点。
然后,通过对相同组的端点进行单次遍历,我们填充每个Coor的C1和C2数组。
请注意,优化版本与x1、y1为同一点的向量的原始版本的工作方式不同。
正如有人指出的那样,比较双精度浮点数是否相等可能会很危险,因此,您可以调整函数
is_same_coordinate
以进行近似比较。
这段代码似乎可以工作,但当然要自己承担风险。
#include <vector>
#include <map>
#include <algorithm>
#include <time.h>
#include <iostream>
struct Coor
{
double x1; double y1;
double x2; double y2;
std::vector<int> C1;
std::vector<int> C2;
};
bool is_same_coordinate(std::pair<double, double> e1, std::pair<double, double> e2)
{
return (e1.first == e2.first) && (e1.second == e2.second);
}
std::vector<Coor> Connection_S(std::vector<Coor> Noeuds)
{
size_t N = Noeuds.size();
for (size_t i = 0; i < N; ++i)
{
for (size_t j = 0; j < N; ++j)
{
if (i == j)
{
continue;
}
if ((Noeuds[i].x1 == Noeuds[j].x1 && Noeuds[i].y1 == Noeuds[j].y1) || (Noeuds[i].x1 == Noeuds[j].x2 && Noeuds[i].y1 == Noeuds[j].y2))
{
Noeuds[i].C1.push_back(j);
}
if ((Noeuds[i].x2 == Noeuds[j].x1 && Noeuds[i].y2 == Noeuds[j].y1) || (Noeuds[i].x2 == Noeuds[j].x2 && Noeuds[i].y2 == Noeuds[j].y2))
{
Noeuds[i].C2.push_back(j);
}
}
}
return Noeuds;
}
void Connection_S_optimized(std::vector<Coor>& Noeuds)
{
std::multimap<std::pair<double, double>, std::pair<bool, size_t>> node_index;
for (size_t i = 0; i < Noeuds.size(); i++)
{
Coor& c = Noeuds[i];
node_index.insert(std::make_pair(std::pair<double, double>(c.x1, c.y1), std::pair<bool, size_t>(true, i)));
node_index.insert(std::make_pair(std::pair<double, double>(c.x2, c.y2), std::pair<bool, size_t>(false, i)));
}
auto s_representative_it = node_index.begin();
for (auto s_it = node_index.begin();; s_it++)
{
if (s_it == node_index.end() || !is_same_coordinate(s_representative_it->first, s_it->first))
{
auto start = s_representative_it;
auto end = s_it;
auto current = s_representative_it;
while (current != end)
{
bool is_node_1 = current->second.first;
Coor& current_coor = Noeuds[current->second.second];
auto it = start;
while (it != end)
{
if (it != current)
{
if (is_node_1)
{
current_coor.C1.push_back(it->second.second);
}
else
{
current_coor.C2.push_back(it->second.second);
}
}
it++;
}
current++;
}
if (s_it == node_index.end())
{
break;
}
s_representative_it = s_it;
}
}
}
const size_t NUM_COORS = 100000;
void generate_sample_set(std::vector<Coor>& Noeuds)
{
Coor c;
size_t degenerated = 0;
for (size_t i = 0; i < NUM_COORS + degenerated; i++)
{
c.x1 = i % 23;
c.x2 = i % 13;
c.y1 = i % 5;
c.y2 = i % 17;
if (is_same_coordinate(std::make_pair(c.x1, c.y1), std::make_pair(c.x2, c.y2)))
{
degenerated++;
continue;
}
Noeuds.push_back(Coor(c));
}
}
int main(int argc, char** argv)
{
std::vector<Coor> Noeuds_input;
generate_sample_set(Noeuds_input);
std::vector<Coor> Noeuds_original = Noeuds_input;
std::vector<Coor> Noeuds_optimized = Noeuds_input;
double time_original = clock();
Noeuds_original = Connection_S(Noeuds_original);
time_original = (clock() - time_original) / CLOCKS_PER_SEC;
double time_optimized = clock();
Connection_S_optimized(Noeuds_optimized);
time_optimized = (clock() - time_optimized) / CLOCKS_PER_SEC;
for (size_t i = 0; i < std::min(Noeuds_input.size(), 100u); i++)
{
std::cout << i << ": " << Noeuds_original[i].C1.size() << "," << Noeuds_original[i].C2.size()
<< " vs " << Noeuds_optimized[i].C1.size() << "," << Noeuds_optimized[i].C2.size() << std::endl;
}
std::cout << "Processing time for " << NUM_COORS << " items (in seconds):" << std::endl;
std::cout << " original: " << time_original << std::endl;
std::cout << " optimized: " << time_optimized << std::endl;
return 0;
}
j<i
的条件,这也会去掉i==j
的情况。 - tadmanx1
和x2
上索引你的条目到一个std::map
中,然后只比较共享同一桶的条目。你的算法非常低效。值得注意的是,你的编译器可能会或可能不会内联删除重复的Noeuds[i]
类型调用的代码。每个这样的查找都可能很痛苦。相反,将每个作为变量捕获并引用它们,或检查你的编译器优化标志是否设置正确。 - tadmanfor (j=(i+1);j<N;++j)
。目前我只尝试了一个较小的向量,但是我得到的时间是5.78秒,而不是10.23秒。 - Dom C.