图
图是一种重要的数据结构,可以用来描述很多实际问题,因此得到了广泛的应用。最典型的应用领域有电路分析、寻找最短路径、项目规划、鉴别化合物、统计力学、遗传学、控制论等学科中。图的主要特点:它的每一个顶点可以与多个其他顶点相关联,各顶点之间的关系时任意的。
1、图的一些基本概念
路径:在图G=(V,E)中,若从顶点vi出发沿着一些边经过若干顶点vp1, vp2,vp3,vp4...vpm 到达顶点vj 则称顶点序列(vi, vp1, vp2,vp3,vp4...vpm, vj)为从顶点i到顶点j的一条路径。
路径长度:不带权的图,路径长度是指此路径上边的条数。带权图,路径长度是指路径上各个边上的权值之和。
简单路径:若路径上各个顶点没有重复的,则称该路径为简单路径。若第一个顶点和最后一个顶点重合,则称这样的路径为回路。
连通图和连通分量:在无向图中,从顶点一到顶点二有路径,则称这两个顶点是连通的,若图中的任一对顶点都是连通的,则称此图是连通的。非连通图的最大连通子图称为该图的连通分量。
强连通图和强连通分量:在有向图中,若任意两个顶点之间都有两个路径,则称此图是强连通的,非强连通图的极大连通子图是强连通分量。
生成树:一个无向连通图的生成树是它的极小连通子图。
2、图的C++实现
图的邻接表表示法:
声明一个数组表示各个顶点,以每个顶点为头结点,链接和这个结点相连的边。下图是一个示例图片:
抽象数据类型表示:
/* 有向图边结构体 */ struct GraphEdge { int cost; //边的权值 int edgedata; //边的顶点值 GraphEdge *nextedge; //下一个边 GraphEdge(int cost,int edgedata) { this->cost=cost; this->edgedata=edgedata; this->nextedge=NULL; } }; /* 图顶点:结构体表示,包含顶点的值和边链表指针域, 顶点表使用数组来表示。 */ struct Vertex { int data; //顶点的值 GraphEdge *edgehead; //边链表的头指针 }; //图类 class LinkedGraph { public: //构造函数析构函数 LinkedGraph() { //初始化参数值 v=new Vertex[9]; //创建顶点表数组 //加入检测语句 if(v==NULL)cout<<"未分配成功"<<endl; for(int i=0;i<9;i++) v[i].edgehead=NULL; //这里需要用点运算符进行操作 } ~LinkedGraph() { } //建立图、输出图 void InitGraphOutput(LinkedGraph *lg); //深度优先搜索和广度优先搜索 void DFSGraph(LinkedGraph *lg); //深度优先遍历 void BFSGraph(LinkedGraph *lg); //广度优先遍历 private: //声明结点的个数,并分配空间:不能只声明不定义和分配存储空间 Vertex *v; };
建立邻接表表示的图(带权无向图)算法:
1、输入顶点,顶点数组表示。
2、输入边,将每个顶点之间有关系的边链接起来。
3、相当于插入顶点,插入边。
代码:
void LinkedGraph::InitGraphOutput(LinkedGraph *lg) { int data; //顶点值 int dest,cost; int i=0; while(i<9) //建立图的顶点数组和这个顶点链接的边 { //输入顶点 cout<<"请输入顶点值:"<<endl; cin>>data; lg->v[i].data=data; //要用点运算符来操作结构体的成员 GraphEdge *q,*p=lg->v[i].edgehead; //声明两个指针,一个用于指向当前顶点的边链表头指针,一个用来辅助 cin>>dest>>cost; //输入这个顶点链接的边,以权值为0结束 int edgenum=0; //用来记录边数,用于不同的链接方式,局部变量的位置 while(cost!=0) { edgenum++; if(edgenum<=1) { //分配一个存储空间给q,如果是第一条边 q=new GraphEdge(cost,dest); if(q==NULL)cout<<"未分配成功"<<endl; //链接 lg->v[i].edgehead=q; //记住这一句 p=q; q=q->nextedge; } else { //bug:只能链入两条边 cout<<"第二条边链接成功"<<endl; //还有其他边 q=new GraphEdge(cost,dest); p->nextedge=q; p=p->nextedge; q=q->nextedge; } cout<<"请继续输入这个顶点对应的边的值和权值:"<<endl; cin>>dest>>cost; } i++; //插入顶点的操作 } cout<<"-------------输出这个图:-------------"<<endl; //输出这个图 for(int i=0;i<9;i++) { cout<<lg->v[i].data<<endl; GraphEdge *p=lg->v[i].edgehead; if(p==NULL)cout<<"这个指针出现问题"<<endl<<endl; while(p!=NULL) { cout<<lg->v[i].data<<"-->"<<p->edgedata<<" 权值为:"<<p->cost<<endl; p=p->nextedge; } } }
图的关联算法
1、克鲁斯卡尔
2、floyd
4、普里姆
5、Bellman-Ford
6、迪杰斯特拉
7、SPFA
8、拓扑排序
9、最短路径问题