图的邻接表实现以及targan算法

来源:互联网 发布:ecshop php版本 编辑:程序博客网 时间:2024/06/05 09:31
/*点类*/#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;}