图是一种重要的数据结构,可以用来描述很多实际问题,因此得到了广泛的应用。最典型的应用领域有电路分析、寻找最短路径、项目规划、鉴别化合物、统计力学、遗传学、控制论等学科中。图的主要特点:它的每一个顶点可以与多个其他顶点相关联,各顶点之间的关系时任意的。

1、图的一些基本概念

路径:在图G=(V,E)中,若从顶点vi出发沿着一些边经过若干顶点vp1, vp2,vp3,vp4...vpm 到达顶点v则称顶点序列(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

3、图的广度优先搜索和深度优先搜索

4、普里姆

5、Bellman-Ford

6、迪杰斯特拉

7、SPFA

8、拓扑排序

9、最短路径问题

posted @ 2013-04-20 12:47  李VS超  阅读(194)  评论(0编辑  收藏  举报