C++ C++;:映射、查找周期、算法
假设以下数据结构:C++ C++;:映射、查找周期、算法,c++,algorithm,cycle,stdmap,C++,Algorithm,Cycle,Stdmap,假设以下数据结构: std::map <int, std::vector<int> > M, 如何从段{}中查找所有循环(类似的开始和结束顶点) C1: {1 8 12 7} {7 9 13 18 0 2} {2 11 1} C2: {4 3 5} {5 17 10 4} C3: {9 6 19 14} {14, 15, 9} 以及如何在低时间复杂度的情况下避免重复的片段序列(map可能包含数十万个序列)。任何循环都可以包含n个段{},其中n>=1 初始化阶段:
std::map <int, std::vector<int> > M,
如何从段{}中查找所有循环(类似的开始和结束顶点)
C1: {1 8 12 7} {7 9 13 18 0 2} {2 11 1}
C2: {4 3 5} {5 17 10 4}
C3: {9 6 19 14} {14, 15, 9}
以及如何在低时间复杂度的情况下避免重复的片段序列(map可能包含数十万个序列)。任何循环都可以包含n个段{},其中n>=1
初始化阶段:
std::map M;
M[1]=std::vector{1,8,12,7};
M[4]=std::vector{4,3,5};
M[7]=std::vector{7,9,13,18,0,2};
M[2]=std::vector{2,11,1};
M[5]=std::vector{5,17,10,4};
M[9]=std::vector{9,6,19,14};
M[14]=std::vector{14,15,9};
算法草案:
std::vector<std::vector <int> > R;
for (auto im = M.begin(); im != M.end();)
{
std::vector<int> r, ri = im->second;
for(;;)
{
r.insert(r.end(), ri.begin(), ri.end());
ri = M[r.back()];
im = M.erase(M.find(im->first));
if (r.back() == r.front()) break;
}
R.push_back(r);
}
std::向量R;
对于(自动im=M.begin();im!=M.end();)
{
向量r,ri=im->秒;
对于(;;)
{
r、 插入(r.end(),ri.begin(),ri.end());
ri=M[r.back()];
im=M.erase(M.find(im->first));
如果(r.back()==r.front())中断;
}
R.推回(R);
}
不幸的是,重复删除代表了一个昂贵的操作。。。我希望有一个更漂亮、更有效的解决方案:-)
谢谢你的帮助…我的第一次尝试:
for (auto it : M)
{
if (it.first < it.second.back() && it.second.front() == M[it.second.back()].back())
std::cout << "Cycle between " << it.first << " and " << it.second.back() << '\n';
}
for(自动it:M)
{
if(it.first 首先,您的内部循环需要是一个函数(如果路径不循环怎么办?)
然后,如果
- 结束节点在数值上小于开始节点(可能是一个循环,但不是规范节点,因此我们不会打印此移位版本)
- 在路径主表中找不到结束节点
这就引出了一个解决方案:
bool try_follow(int from, std::vector<int>& result)
{
int current = from;
while (true) {
auto path = M.find(current);
if (path == M.end()) return false;
current = path->second.back();
if (current < from) return false;
result.insert(result.end(), path->second.begin()+1, path->second.end());
if (current == from) return true;
}
}
int main(void)
{
for( auto& kvp : M )
{
std::vector<int> x;
if (try_follow(kvp.first, x)) {
std::cout << kvp.first;
for( int y : x )
std::cout << " - " << y;
std::cout << std::endl;
}
}
}
bool try\u follow(int from,std::vector&result)
{
int电流=从;
while(true){
自动路径=M.find(当前);
if(path==M.end())返回false;
当前=路径->第二个.back();
如果(电流<来自)返回false;
插入(result.end(),path->second.begin()+1,path->second.end());
if(current==from)返回true;
}
}
内部主(空)
{
用于(自动和kvp:M)
{
std::向量x;
如果(尝试跟随(kvp.first,x)){
std::循环是否必须包括整个路径,或者是否可以使用任何连接的子序列?请注意,避免重复循环就像给每个循环指定一个规范名称一样简单。要求打印循环以编号最低的节点开始是一个好选择。@Ben Voigt:只有{}内的整个路径本·沃格特:谢谢,这是一个多么好的解决方案!
for (auto it : M)
{
if (it.first < it.second.back() && it.second.front() == M[it.second.back()].back())
std::cout << "Cycle between " << it.first << " and " << it.second.back() << '\n';
}
bool try_follow(int from, std::vector<int>& result)
{
int current = from;
while (true) {
auto path = M.find(current);
if (path == M.end()) return false;
current = path->second.back();
if (current < from) return false;
result.insert(result.end(), path->second.begin()+1, path->second.end());
if (current == from) return true;
}
}
int main(void)
{
for( auto& kvp : M )
{
std::vector<int> x;
if (try_follow(kvp.first, x)) {
std::cout << kvp.first;
for( int y : x )
std::cout << " - " << y;
std::cout << std::endl;
}
}
}