/*
点类
*/
#ifndef NODE_H__
#define NODE_H__
#include "arc.h"
#include <memory>
#include <string>
struct node
{
std::string node_name;
std::shared_ptr<arc> arc;
node()
{
node_name.clear();
arc.reset();
}
node(const std::string name)
{
node_name=name;
arc.reset();
}
};
#endif
/**
边类
**/
#ifndef ARC_H__
#define ARC_H__
#include <memory>
#include <string>
struct arc
{
std::shared_ptr<arc> next;
std::string node_name;
arc(const std::string& name)
{
next.reset();
node_name=name;
}
arc()
{
node_name.clear();
next.reset();
}
};
#endif
/**
一个邻接表表示的有向图
**/
#ifndef GRAPH_H__
#define GRAPH_H__
#include <vector>
#include <string>
#include <algorithm>
#include <memory>
#include <map>
#include <iostream>
#include "node.h"
#include "arc.h"
class graph
{
private:
typedef std::vector<std::shared_ptr<node> >::iterator iterator;
std::shared_ptr<arc> null_arc;
public:
graph()
{
null_arc.reset();
}
bool add_node(const std::string& name)
{
auto index=vec.begin();
for(;index!=vec.end();++index)
{
if((*index)->node_name==name)
break;
}
if(index!=vec.end())
return false;
vec.push_back(std::shared_ptr<node>(new node(name)));
return true;
}
void remove_node(const std::string& name)
{
//删除节点和删除边
auto index=vec.begin();
while(index!=vec.end())
{
if((*index)->node_name==name) //删除以这个点起始的点
{
index=vec.erase(index);
}
else //删除所有以这个边为终点的边
{
if((*index)->arc==null_arc)
;
else if((*index)->arc->node_name==name)
{
(*index)->arc=(*index)->arc->next;
}
else
{
auto p=(*index)->arc;
while(p->next!=null_arc)
{
if(p->next->node_name==name)
{
p->next=p->next->next;
break;
}
p=p->next;
}
}
++index;
}
}
}
//删除(from_name,to_name)边
bool remove_arc(const std::string from_name,
const std::string to_name)
{
auto index_f=get_index_from_name(from_name); //查找from_name的节点
if(index_f==vec.end()) //如果没有,就返回
{
std::cout<<"This arc is not exist!"<<std::endl;
return false;
}
if((*index_f)->arc==null_arc) //如果from_name节点不包含边,则返回
{
std::cout<<"This arc is not exist!"<<std::endl;
return false;
}
if((*index_f)->arc->node_name==to_name) //特殊情况,处理
{
(*index_f)->arc=(*index_f)->arc->next;
}
else //否则,循环查找,如果找到就删除
{
auto p=(*index_f)->arc;
while(p->next!=null_arc)
{
if(p->next->node_name==to_name)
{
p->next=p->next->next;
break;
}
p=p->next;
}
}
return true;
}
//在from_name和to_name之间添加一条边
//前提必须是已经存在from_name和to_name两个点
bool add_arc(const std::string from_name,
const std::string to_name)
{
auto index_f=get_index_from_name(from_name);
auto index_t=get_index_from_name(to_name);
if(index_f==vec.end()|| index_t==vec.end())
{
std::cout<<"Please input node first!"<<std::endl;
return false;
}
//查重
if((*index_f)->arc!=null_arc)
{
std::shared_ptr<arc> tem=(*index_f)->arc;
while(tem!=null_arc)
{
if(tem->node_name==to_name)
{
std::cout<<"This arc has exist!"<<std::endl;
return false;
}
if(tem->next==null_arc)
break;
tem=tem->next;
}
tem->next.reset(new arc(to_name));
}
else
{
(*index_f)->arc.reset(new arc(to_name));
}
return true;
}
//输出图
void print_graph()
{
auto index=vec.begin();
while(index!=vec.end())
{
std::cout<<"Node:"<<(*index)->node_name;
std::cout<<" arcs:";
auto p=(*index)->arc;
while(p!=null_arc)
{
std::cout<<"("<<(*index)->node_name<<","<<p->node_name<<") ";
p=p->next;
}
std::cout<<std::endl;
++index;
}
}
//查找割点
//采用targan算法
std::vector<std::string> get_cut_points(const std::string& node_name)
{
std::vector<std::string> cut_points;
size_t count=0;
std::map<std::string,int>seq,low;
dnf(node_name,seq,low,count,cut_points);
if(count<vec.size()-1)
{
cut_points.push_back(node_name);
for(auto index=vec.begin();index!=vec.end();++index)
{
count=0;
if(seq.find((*index)->node_name)!=seq.end())
dnf((*index)->node_name,seq,low,count,cut_points);
}
}
return cut_points;
}
private:
//深度遍历
//从node_name节点开始
//seq为节点的访问顺序
//low为low(v)=min(seq(v),low(u))
//其中,v为当前节点,u为v深度遍历的子节点
//count为访问次序
//vec用来存储割点
void dnf(const std::string& node_name,std::map<std::string,int>& seq,
std::map<std::string,int>& low,size_t& count,std::vector<std::string>& cut_points)
{
auto index=get_index_from_name(node_name);
if(index!=vec.end())
{
int min=-1;
auto p=(*index)->arc;
seq.insert(make_pair(node_name,count));
min=count++;
while(p!=null_arc)
{
if(seq.find(p->node_name)==seq.end()) //如果没有访问过
{
dnf(p->node_name,seq,low,count,cut_points);
if(low[p->node_name]<min)
min=low[p->node_name];
if(low[p->node_name]>=seq[node_name])
cut_points.push_back(node_name);
}
else if(seq[p->node_name]<min)
min=seq[p->node_name];
p=p->next;
}
low[node_name]=min;
}
}
//根据节点名字查找该节点在vector中的索引
iterator get_index_from_name(const std::string& from_name)
{
auto index=vec.begin();
while(index!=vec.end())
{
if((*index)->node_name==from_name)
break;
++index;
}
return index;
}
private:
//换成map效率更高
//std::map<std::string,std::shared_ptr<arc> > vec;
std::vector<std::shared_ptr<node> >vec;
//typedef std::vector<std::shared_ptr<node> >::iterator iterator;
};
#endif
/**
利用targan算法求无向图的割点
**/
#include "graph.h"
int main(int argc,char* argv[])
{
graph g;
g.add_node("1");
g.add_node("2");
g.add_node("3");
g.add_node("4");
g.add_node("5");
g.add_node("6");
///
g.add_arc("1","2");
g.add_arc("1","6");
g.add_arc("2","5");
g.add_arc("6","5");
g.add_arc("5","1");
g.add_arc("2","3");
g.add_arc("3","4");
g.add_arc("5","4");
std::vector<std::string> vec=g.get_cut_points("1");
std::for_each(vec.begin(),vec.end(),[](const std::string& str)
{
std::cout<<str<<std::endl;
}
);
system("PAUSE");
return 0;
}