【考研】图的基本操作和算法

邻接矩阵


存储结构

#define MaxVertexNum 100//顶点数目的最大值

typedef char VertexType ;//顶点的数据类型 不同情况不一样

typedef int EdgeType ;//整数表示权值或者连通性

typedef struct 
{
	VertexType Vex[MaxVertexNum];//顶点表
	EdgeType Edge[MaxVertexNum][MaxVertexNum] ;//邻接矩阵(二维数组),边表
	int vexnum , arcnum ;//图的当前顶点数和弧数
}MGraph;


基本操作


顶点插入

//插入顶点
void InsertVertex(MGraph *g,char x)
{
	//printf("开始插入");
	if(g->vexnum<100){	
		g->Vex[g->vexnum]=x;
		g->vexnum++;
	}
	else{
		printf("顶点存储已满,无法插入");
	}
}

删除操作

在删除操作时需要注意,与该顶点有关的边要全部删除,例如要删除b相关的边,则需要先删除与b相关的行再删除与其相关的列

//删除顶点(也会删除该顶点关联的边)
void DeleteVertex(MGraph *g,char x){
	MGraph gr=*g;
	int i=getVex(gr,x);	//获取顶点对应的顶点表中的标号
	if(i==-1){
		printf("\n不存在这样的点,无法删除!\n");
		return;
	}else{
		for(int s=0;s<g->vexnum;s++){
			if(g->Edge[i][s]!=0){
				g->arcnum--;
				//printf("\nEdge[%d][%d],边数:%d",i,s,g->arcnum);
			}
			if(g->Edge[s][i]!=0){
				g->arcnum--;
				//printf("\nEdge[%d][%d],边数:%d",s,i,g->arcnum);
			}
		}//先进行相关联边的遍历,然后对总边数进行修改
		for(int j=i;j<g->vexnum;j++){
			g->Vex[j]=g->Vex[j+1];//对顶点表的修改
			for(int m=0;m<g->vexnum;m++){
				g->Edge[j][m]=g->Edge[j+1][m];		
			}
		}//删除一行操作
		for(int n=i;n<g->vexnum;n++){
			for(int m=0;m<g->vexnum-1;m++){
				g->Edge[m][n]=g->Edge[m][n+1];					
			}
		}//删除一列操作
		g->vexnum--;//顶点数进行修改
		printf("\n点%c删除完成\n",x);
	}
}

边的插入、删除和判断两点之间是否有边操作

Adjacent函数这里只用于有向图的判断,如果使用无向图的判断,那么需要多加一个或判断g.Edge[j][i]!=0

//增加边
void AddEdge(MGraph *g,char x,char y){
	MGraph gr=*g;
	int i=getVex(gr,x);	//获取顶点对应的顶点表中的标号
	int j=getVex(gr,y);//获取顶点对应的顶点表中的标号
	if(i==-1||j==-1){
		printf("\n不存在这样的顶点可以插入边!\n");
		return;
	}else{
		if(g->Edge[i][j]==0){
			g->Edge[i][j]=1;
			g->arcnum++;
		}
		else{
			printf("这两点已存在边,插入边失败!");
		}
	}
}
//判断x和y中是否有边
bool Adjacent(MGraph g,char x,char y){
	int i=getVex(g,x);
	int j=getVex(g,y);
	if(i==-1||j==-1){
		printf("\n不存在这样的顶点!\n");
		return false;
	}else if(g.Edge[i][j]!=0){
			return true;
	}
	return false;
}
//删除边<x,y>(如果存在)
void RemoveEdge(MGraph *g,char x,char y){
	MGraph gr=*g;
	if(Adjacent(gr,x,y)){//Adjacent判断x和y中是否存在边,存在即返回true
		int i=getVex(gr,x);
		int j=getVex(gr,y);
		g->Edge[i][j]=0;
		g->arcnum--;
	}else{
		printf("\n所要删除的边不存在");
	}
}

边的设置权值和获取权值操作

//获得<x,y>对应的权值
int Get_edge_value(MGraph g,char x,char y){
	if(Adjacent(g,x,y)){
		int i=getVex(g,x);
		int j=getVex(g,y);
		return g.Edge[i][j];
	}else{
		printf("两点之间没有边\n");
		return -1;
	}
	return -1;
}

//设置<x,y>之间的权值
bool Set_edge_value(MGraph *g,char x,char y,int v){
	MGraph gr=*g;
	if(Adjacent(gr,x,y)){
		int i=getVex(gr,x);
		int j=getVex(gr,y);
		g->Edge[i][j]=v;
		return true;
	}else{
		printf("\n两点之间没有边,无法设置权值!\n");
		return false;
	}
	return false;
}

获取第一个邻接点和下一个邻接点操作

//求顶点的第一个邻接点
int FirstNeighbor(MGraph g,char x){
	int i=getVex(g,x);
	if(i!=-1){
		for(int j=0;j<g.vexnum;j++){
			if(g.Edge[i][j]!=0||g.Edge[j][i]!=0){
				return j;
			}
		}
	}
	return -1;
}

//求顶点x在y之后的邻接点
int NextNeighbor(MGraph g,char x,char y){
	if(!Adjacent(g,x,y)){
		printf("%c和%c不是邻接点  ",x,y);
		return -1;
	}else{
		int i=getVex(g,x);
		int j=getVex(g,y);
		if(i!=-1&&j!=-1){
			for(j=j+1;j<g.vexnum;j++){
				if(g.Edge[i][j]!=0||g.Edge[j][i]!=0){
					return j;
				}
			}
		}
	}
	return -1;
}

邻接法


存储结构

#define MaxVertexNum 100	//图中顶点数目的最大值

typedef struct ArcNode{	//边表结点
	int djvex;	//该弧指向的顶点位置
	struct ArcNode *next;	//指向下一条弧的指针
	//InfoType info		//边的边权值
}ArcNode;

typedef struct VNode {	//顶点表结点
	VertexType data;	//顶点信息
	ArcNode *first;		//指向第一条依附该顶点的弧的指针
}VNode , AdjList[MaxVertexNum];

typedef struct {
	AdjList vertice;	//邻接表
	int vexnum , arcnum;	//图的顶点和弧数
}ALGraph;		//ALGraph是以邻接表存储的图类型

基本操作:


建立有向图

//建立有向图
void CreateDGGraph(ALGraph &G)
{
    int m, n;      //边<Vm,Vn>的下标
    ArcNode *vm, *vn;//构成边<Vm,Vn>的两个顶点
    cout << "请输入顶点数和边数:";
    cin >> G.vexnum >> G.arcnum;
    cout << "请输入顶点的信息:" << endl;

    //获取顶点信息
    for(int i=0; i<G.vexnum; i++)
    {
        cin >> G.vertices[i].data;
        G.vertices[i].firstarc=NULL;
    }

    //建立邻接表,采用头插法
    for(int i=0; i<G.arcnum; i++)
    {
        cout << "请输入<Vi,Vj>的下标:";
        cin >> m >> n;
        vm(ArcNode*)malloc(sizeof(ArcNode));
        vm->adjvex=n;

        vm->nextarc=NULL;
        if(G.vertices[m].firstarc==NULL)
        {
            vn=G.vertices[m].firstarc=vm;
        }
        else{
            vn=vn->nextarc=vm;
        }
    }
}

建立无向图

//建立无向图
void CreateUDGGraph(ALGraph &G)
{
    int m, n;                  //边<Vm,Vn>的下标
    ArcNode *pe;

    cout << "请输入顶点数和边数:";
    cin >> G.vexnum >> G.arcnum;
    cout << "请输入顶点的信息:" << endl;

    //获取顶点信息
    for(int i=0; i<G.vexnum; i++)
    {
        cin >> G.vertices[i].data;
        G.vertices[i].firstarc=NULL;
    }

    //建立邻接表,采用头插法
    for(int i=0; i<G.arcnum; i++)
    {
        cout << "请输入<Vi,Vj>的下标:";
        cin >> m >> n;
        pe=(ArcNode*)malloc(sizeof(ArcNode));
        pe->adjvex=n;

        pe->nextarc=G.vertices[m].firstarc;
        G.vertices[m].firstarc=pe;

        pe=(ArcNode*)malloc(sizeof(ArcNode));
        pe->adjvex=m;
        pe->nextarc=G.vertices[n].firstarc;
        G.vertices[n].firstarc=pe;
    }
}

输出邻接表

void PrintALGraph(ALGraph &G)
{
    ArcNode *p;
	for (int i=0;i<G.vexnum;i++)
	{
		cout << "顶点" << i << "(" << G.vertices[i].data << ") "": ";
		for (p=G.vertices[i].firstarc; p!=NULL;p=p->nextarc)
			cout << p->adjvex << "(" << G.vertices[p->adjvex].data << ") ";
		if (p==NULL)
			cout << endl;
	}
}

顶点v的第一个邻接点

//求图中顶点v的第一个邻接点,若有则返回顶点下标。若v没有邻接点或图中不存在v,则返回-1
int FirstNeighbor(ALGraph G, int v)
{
    ArcNode *next=G.vertices[v].firstarc;
    if(next)
    {
        return next->adjvex;
    }
    return -1;
}

顶点v的下一个邻接点

//返回除顶点v外的下一个顶点w
int NextNeighbor(ALGraph G, int v, int w)
{
    ArcNode *next=G.vertices[v].firstarc;
    while(next)
    {
        if(next->adjvex==w)break;
        next=next->nextarc;
    }
    if(next)
    {
        ArcNode *nextNode=next->nextarc;
        if(nextNode)
        {
            return nextNode->adjvex;
        }
    }
    return -1;
}

访问结点v

void visit(ALGraph G, int v)
{
    cout << G.vertices[v].data << " ";
}

主函数编写

int main()
{
    ALGraph G;
    //CreateALGraph(G);
    int tag;                   //有向无向图标志
    cout << "请输入1(有向图),2(无向图):";
    cin >> tag;
    if(tag==1)
    {
        G.kind=DG;
        CreateDGGraph(G);      //建立有向图
    }
    else
    {
        G.kind=UDG;
        CreateUDGGraph(G);     //建立无向图
    }

    cout << "===========================" << endl;
    PrintALGraph(G);

    cout <<endl;
    cout << "广度遍历:";
    BFSTraverse(G);

    cout << endl;
    cout << "深度遍历:";
    DFSTraverse(G);

    return 0;
}

遍历


广度优先搜索遍历(BFS)

类属于二叉树的层序遍历算法,借助队列+辅助标记数列

int visit[100];	//标记数组
void BFS(Graph G ,int v){
	visit(v);	//访问初始节点v
	visited[v] = 1;	//标记
	EnQueue(Q ,v);	//入队起点
	while( ! is Empty(Q)){
		DeQueue(Q , v);	//出队,v去接受出队的值
		for(w = FirstNeighbor (G , v) ; w >= 0 ; w = NextNeighbor(G , v ,w)){
		//检测v所有邻接点
			if( !visited[w]){	//未被标记的邻接入队 
				visit(w);	//访问顶点w
				visited[w] = 1;	//标记
				EnQueue(Q ,w); 	//入队
			} 
		} 
	} 
} 

void BFSTrarerse(Graph G){
	for( int i = 0 ; i <G.vexnum ; i++){//对访问数组初始化
		visit(i) = 0;
	}
	InitQueue(Q);	//初始化辅助队列Q
	for(int i = 0 ; i <G.vexnum ; i++){		//从0号顶点开始遍历
		if( !visited[i]){	//对每个连接分量调用一次BFS
        	BFS(G , i);
		}
	}
}

BFS应用:单源非带权图最短路径

void BFS_MIN_Distance(Graph G, int u){
	for(i=0;i<G.vexnum;++i) d[i] = ∞ ;//d[i]表示从u到i结点的最短路径
	visited[u] = TRUE ;
	d[u] = 0 ;
	EnQueue(Q,u) ;
	while(!IsEmpty(Q)){
		DeQueue(Q,u) ;
		ArcNode *p = G->adjList[u].firstedge;
		while(p){
			if(!visited[p->adjvex]){
				visited[p->adjvex] = TRUE ;
				d[p->adjvex] = d[u]+1 ;//路径长度加1
				EnQueue(Q,p->adjvex) ;
			}
			p=p->next; 
		}
	}
}

//王道伪代码
void BFS_MIN_Distance(Graph G, int u){
	for(i=0;i<G.vexnum;++i) d[i] = ∞ ;//d[i]表示从u到i结点的最短路径
	visited[u] = TRUE ;
	d[u] = 0 ;
	EnQueue(Q,u) ;
	while(!IsEmpty(Q)){
		DeQueue(Q,u) ;
		for(w = FirstNeighbor( Q , r ) ; w >= 0 ; w = NextNeighbor( Q , u , w ) ){
			if(!visited[w]){
				visited[w] = TRUE ;
				d[w] = d[u]+1 ;//路径长度加1
				EnQueue(Q,w) ;
			}
		}
	}
}

图的深度优先遍历(DFS)

#define MaxSize 100 
bool visited[MaxSize] ;

void DFS(Graph G, int v){
	ArcNode *p ;	//工作指针p
	visit(v);	//访问顶底v(一般是打印,printf)
	visited[v] = TRUE ;//修改访问标记
	p = G->djList[v].firstarc;//指针p开始指向该顶点的第一条边
	while(p!=NULL){//没遍历完顶点的所有邻接顶点
		if(!visited[p->djvex]){//如果该顶点没被访问
			DFS(G,p->djvex);//递归访问该顶点
		}
		p=p->nextarc ;//看还有没有其他未访问的顶点
	}
}
void DFSTraverse(Graph G){
	int i ;//单独定义是为了方便多个循环中使用
	for (i=0;i<G->vexnum ; i++){
		visited[i] = false ;//将标志数组初始化 (全局数组)
	}
	for (i=0;i<G->vexnum ; i++){
		if(!visited[i]) 
			DFS(G,i);//对所有
	}
}


算法


判断图是否联通

bool visited[MaxVertexNum];         //访问标记数组

//从顶点v出发,采用递归,深度遍历图G
void DFS(ALGraph G, int v)
{
    visit(G, v);                    //访问v
    visited[v]=true;                //设已访问标记
    for(int w=FirstNeighbor(G, v); w>=0; w=NextNeighbor(G, v, w))
    {                               //w为v的尚未访问的邻接顶点
        if(!visited[w])
        {
            DFS(G, w);
        }
    }
}

//判断一个图是否连通
bool Judge(ALGraph G)
{
    for(int v=0; v<G.vexnum; v++)
    {
        visited[v]=false;
    }
    DFS(G, 0);                      //从任意一点遍历,这里从下标为0的点开始
    for(int v=0; v<G.vexnum; v++)
    {
        if(!visited[v])
        {
            return false;
        }
    }
    return true;
}

邻接表转换成邻接矩阵

思想:设图的顶点分别储存在v[n]中。所以需要先初始化邻接矩阵,再遍历邻接表,依次修改邻接矩阵的第i行的元素值。
若链表边结点为j,则设置arcs[i][j] = 1。当遍历完邻接表时,转换过程也结束了

void Convert(ALGraph &G ,int arcs[M][N]){
//此算法将邻接表方式表示的图G转换为邻接矩阵arcs
	for( i=0 ; i<n ; i++){		//依次遍历各顶点表结点为头的边链表
		p = ( G->v[i]).firstarc;		//取出顶点i的第一条出边
		while( p != NULL){		//遍历边链表
			arcs[i][p->data] = 1;	
			p = p->nextarc;		//取下一条出边
		}
	}
}

检验无向图G时否是树

若是一棵树,返回true;不是则返回false
思想:因为G是一棵树必须有n-1条边的连通图,则用深度优先探索算法遍历可能访问到的顶点个数和边个数,若一次就能访问到n个顶点和n-1条边,则是一棵树

bool isTree(Graph &G){
	for(int i = 0 ; i < G.vexnum ; i++)
		visited[i] = false;
	int Vnum=0 , Enum = 0;	//记录顶点数和边数
	if(Vnum == G ,vexnum && Enum == 2*(G.vexnum-1)) 
		return true;	//符合树的条件 
	else
		return false;	//不符合树的要求 
}

void DFS(Graph &G , int v, int &Vnum , int &Enum , int visited[]){
//深度遍历图G,统计访问过的定点数和边数,通过Vnum和Enum返回
	visited[v] = true;	//作为标记,顶点计数 
	Vnum++; 
	int w = FirstNeighbor(G , v);	//取v的第一个邻接顶点
	while( w!= -1){		//当邻接顶点存在时 
		Enum++;		//则边存在,计数
		if( !visited[w])	//当邻接顶点未被访问
			DFS(G , w , Vnum , Enum , visited);
		w = NextNeighbor(G ,v, w); 
	} 
} 


深度优先遍历算法DFS的非递归方法

利用栈来实现,记忆下一步可能访问的顶点,用visited[ i ]数组来记录第 i 个顶点是否在栈内或曾经再栈内。图用邻接表形式。

void DFS_Non_RC(AdGraph &G , int v){
//从顶点v开始一个个进行深度优先搜索,一次遍历一个连通分量的所有顶点
	int w;		//顶点序号
	InitStack( S );		//初始化栈S
	for( i = 0 ; i < G.vexnum ; i++)
		visited[i] = false;
	Push( S , v);
	visited[ v ] = true;
	while ( !IsTmpty(S)){
		k = Pop(S);		//从栈推出一个顶点
		visit(k);	//先访问,再将其子节点入栈
		for( w = FirstNeighbor(G , k) ; w < G.vexnum ; w= NextNeighbor(G , k ,w)){
			if( !visited[w]){	//若没有进栈则进栈,再标记
				Push( S , w);
				visited[w] = true;	
			}
		}
	}
}

检测是否存在结点 I 到结点 J 的路径

广度优先遍历BFS:

int visited[MaxSize] = {0};	//访问标记数组
int BFS(ALGraph &G , int i .int j){
	InitQueue(Q);
	EnQueue(Q , i);
	while( !isTmpty(Q)){
		DeQueue(Q , U);		//队头顶点出队
		visited[u] = 1;		//置访问标记
		if( u== j)
			return 1;
		for( int p = FirstNeighbor(G , i) ; p ; p = NextNeighbor( G , u , p)){
			if(p == j)
				return 1;
			if( !visited[p]){
				EnQueue( Q , p);
				visited[p] = 1;
			}
		}
	}
}

深度优先遍历DFS:

int visited[ MaxSize ] = {0};
void DFS(ALGraph &G , int i ,int j , bool &can_reach){
//遍历全部结点,检测是否有路径,用can_reach来标识
	if( i == j){
		can_reach = true;
		return;		
	}
	visited[i] = 1;		//放置访问标记
	for( int p = FirstNeighbor( G , i) ; p >0 ; p = NextNeighbor(G ,i, p )){
		if( !IsEmpty( p ) && !can_reach )
			DFS( G , p , j , can_reach);
	}
}

输出顶点 i 到 顶点 j 的所有简单路径

思路:用递归的深度优先遍历算法,从结点u出发递归深度遍历图中的结点,若访问到结点v,则输出该搜索路径上的结点。
设置一个path数组来存放路径节点,d为路径长度(开始为-1),用邻接表来表示图G

void FinePath(ALGraph &G , int i , int j , int path[] , int d){
//设置path数组来存放路径上的结点,d表示路径长度
	int a , b;
	ArcNode *p;
	d++;
	path[d] = i;	//让第一个i添加到路径上
	visited[i] = 1;		//标记
	if( i == j)
		printf(path[]);		//输出路径上的结点
	p = G->adjlist[i].firstarc;		//p指向i的第一个相邻点
	while( p!= NULL){
		a = p->adjvex;		//若a没有被访问,则访问他
		if( visited[a] == 0)
			FinPath(G , a ,j .path ,d);
		p = p->nextarc;		//指向下一个相邻点
	}
	visited[i] = 0;		//回复环境,使得该顶点可重复使用
}

利用DFS法实现有向无环图拓扑排序

设有向无环图G中的任意结点u,v,则u和v存在三种关系
1.u是v的祖先:访问u的时候,必须先递归一次v,也就是对v结束的时间要先于u;可以设置一个时间坐标time以记录
2.u是v的子孙,则如1一样,u要比v快
3,u和v无关系,则关系任意

bool visited[ MaxSize ];
void DFSTraverse( Graph &G ){
	for(i = 0 ; i < G.vexnum ; i++)
		visited[i] = false;
	time = 0;
	for( i = 0 ; i < G.vexnum ; i++){
		if( !visited[i] )
			DFS(G , i)
 	} 
}

void DFS(Graph &G , int i ){
	visited[i] = true;
	visit(i);
	for( w = FirstNeighbor ; w < G.vexnum ; w = NextNeihbor){
		if( !vsited[w] )	//以w为u的尚未访问的邻接结点 
			DFS(G , w);
	}
	time = time+1;
	finishTime[v] = time;
}


最小生成树


素数算法Prime

思路:
1.初始化,将第一个顶点连接的边都列入weight中
2.找到目前与i相邻最小的边
3.//找到与i相连的其他边中的最小顶点,若比原本的min_arc小则上位

void MST_Prim(Graph G){
	int min_weight[G.vexnum];	//存放顶点到其他顶点的权值
	int adjvex[G.vexnum];	//记录结点数是被谁引用的
	for( int i = 0 ; i <G.vexnum ; i++){	//初始化,将第一个顶点连接的边都列入weight中 
		min_weight[i] = G.edge[0][1];	//第一个顶点到每一条边的距离 
		adjvex[i]=0;
	} 
	int min_vex;	//最小顶点下标 
	int min_arc;	//最小边
	for(int i = 1 ; i<G.vexnum ; i++){	//找到目前与i相邻最小的边 
		min_arc = MAX;	//令最小变最大,放便找最小值 
		for( int j = 1 ; j < G.vexnum ; j++ ){
			if( min_weight[j] != 0 && min_weight[j] < min_arc ){
				min_arc = min_weight[j];	//专门找最小的边 
				min_vex = j;	//记录最小边的下标 
			}
		}
		min_weight[min_vex] = 0;	//使其准备入结果树 
		for( int j = 0 ; j < G.vexnum ; j++ ){	//找到与i相连的其他边中的最小顶点,若比原本的min_arc小则上位
			if( min_weight[j] != 0 && min_weight[j] < min_arc ){
				min_weight[j] = G.edge[min_arc][j];
				adjvex[j]=min_arc;
			}
		}
	} 	
}

克鲁斯卡尔算法Kruskal

typedef struct{
	int u;	//边的起始顶点
	int v;	//边的终止顶点
	int w;	//边的权值 
}Edge;


void Kruskal( MGraph G){
	int i , j , u1 , v1 , s1 , s2 , k;
	int vest[MAX];
	Edge E[MAX];	//存放所有边 
	k = 0;			//E数组下标从0开始计数 
	for(i = 0 ; i < G->vexnum ; i++){	//从G产生的边集E 
		for( j = 0 ; j < G->vexnum ; j++){
			if( G.edges[i][j] != 0 && G.edges[i][j] != INF){
				E[k].u = i;
				E[k].v = j;
				E[k].w = G.edges[i][j];
				k++;
			}
		}
	} 
	InitSort( E , G.e);	//用直接插入排序对E数组进行权值递增排序
	for( i = 0 ; i < G.n ; i++){	//初始化辅助数组 
		vest[i] = i;
		k = 1;		//k表示当前构造生成树的第几条边,初值为1 
		j = 0;		//E中边的下标,初值为0 
		while( k < G.n ){	//生成的边数小于n时循环 
			u1 = E[j].u;	//取一条边的头尾节点 
			v1 = E[j].v;
			s1 = vest[u1];	//分别得到两个顶点所属的集合编号 
			s2 = vest[v1];
			if( s1 != s2 ){		//两顶点属于不同的集合 
				printf("(%d,%d):%d\n" , u1,v1,E[j].w);
				k++;	//生成边数+1
				for( i = 0 ; i < G.n ; i++ ){
					if(vest[i] == s2 )
						vest[i] = s1;
				} 
			} 
			j++;	//扫描下一条边 
		} 
	} 
 

最短路径问题


迪杰斯特拉算法(Dijkstra)

#define INF 32767 //INF表示无穷 
//迪杰斯特拉算法(Dijkstra)
void Dijkstra( MGraph G , int v){
	int dist[MaxVerterNum],path[MaxVerterNum];	//path[]表示从顶点v到顶点u的最短路径 
	int s[MaxVerterNum];
	int mindis , i , j ,u;
	for( i = 0 ; i < G.vexnum ; i++ ){
		dist[i] = G.Edge[v][i];	//距离初始化 
		s[i] = 0;	//s[]置空 
		if(G.Edge[v][i] == NULL)	//路径初始化 
			path[i] = v;	//从顶点v到i有边时,置顶点i之前的顶点为v
		else
			path[i] = -1;	// 从顶点v到i有边时,置顶点i之前的顶点为-1
	} 
	s[v] = 1;	//原点编号v放入s中 
	path[v] = 0;
	for(i = 0 ; i < G.vexnum ; i++){	//循环直到所有顶点的最短路径求粗 
		mindis = NULL;	//mindis置最小长度初值 
		for(j = 0 ; j < G.vexnum ; j++){	//选取不在s中且具有最小距离的顶点u 
			if(s[j] == 0 && dist[j] < mindis){
				u = j;
				mindis = dist[j];
			}
			s[u] = 1;	//顶点u加入s中
			for( j = 0 ; j < G.vexnum ; j++){	//修改不在s中的顶点的举例 
				if(s[j] == 0){
					if(G.Edge[u][j] < INF && dist[u]+G.Edge[u][j] < dist[j]){
						dist[j] = dist[u]+G.Edge[u][j];
						path[j] = u;
					}
				}
			} 
		}
	}
	Dispath(dist , path , s , G.vexnum , v);	//输出最短路径 
} 

弗洛伊德算法(Floyd)

void Floyd(AdjMatrix *G)
{
    int A[MaxVertices][MaxVertices],path[MaxVertices][MaxVertices];
    int i,j,k;
    //初始化
    for (i=0;i<G->vexnum;i++)
    {
        for (j=0;j<G->vexnum;j++)
        {
            A[i][j]=G->Edge[i][j];
            path[i][j]=-1;
        }
    }
//三重循环,floyd算法核心
    for (k=0;k<G->vexnum;k++)
    {
        for (i=0;i<G->vexnum;i++)
        {
            for (j=0;j<G->vexnum;j++)
            {
                if (A[i][j]>A[i][k]+A[k][j])
                {
                    A[i][j]=A[i][k]+A[k][j];
                    path[i][j]=k;
                }
            }
        }
    }
    Dispath(A,path,G->vexnum);//输出函数
}

拓扑排序

//拓扑排序 
typedef struct{
	int data;	//顶点信息
	int count;	//存放顶点入度
	ArcNode*first;	//指向第一条弧	
}VNode;

void TopSort (VNode adj[] , int n){
	int i , j;
	int S[MaxVerterNum];	
	int top = -1;	//栈S的指针为top 
	ArcNode *p;
	for( i = 0 ; i <n ; i++){
		if(adj[i].count == 0){	//入度为0的顶点入栈 
			top++;
			S[top]=i;
		}
	}
	while(top >-1){	//栈不为空则循环 
		i = S[top];		//出栈 
		top--;
		printf("%d" , i);
		p = adj[i].first;
		while( p!= NULL ){
			j = p->adjvex;
			adj[j].count--;
			if(adj[j].count == 0){
				top++;
				S[top] = j;
			}
			p = p->next;	//找下一个相邻顶点 
		}
	}
}

邻接表转化为逆邻接表

在这里插入图片描述

void Reverse(ALGraph A,ALGraph &B)
{
    int i,k;
    ArcNode *p1,*p2;
    B.vn=A.vn;
    B.en=A.en;
    for(i=1; i<=A.vn; i++)
    {
        scanf("%c",&B.adjlist[i].data);
        B.adjlist[i].firstarc=NULL;
    }
 
    for(i=1; i<=A.vn; i++)
    {
        p1=A.adjlist[i].firstarc;
        while(p1)
        {
            k=p1->adjvex;
            p2=(ArcNode *)malloc(sizeof(ArcNode));
            p2->adjvex=i;
            p2->nextarc=B.adjlist[k].firstarc;
            B.adjlist[k].firstarc=p2;
            p1=p1->nextarc;
        }
    }
}

无向图邻接矩阵转换为邻接表

//以下定义邻接矩阵类型  
typedef struct                  
{
	int vexs[MAXV];      		 
    int arcs[MAXV][MAXV];       
    int vexnum,arcnum;          
} MGraph;                       
//以下定义邻接表类型
typedef struct ANode            
{
    int adjvex;                 
    struct ANode *nextarc;        
} ArcNode;
typedef struct Vnode           
{
    int data;                
    ArcNode *firstarc;         
} VNode;
typedef struct
{
    VNode vertices[MAXV];            
    int vexnum,arcnum;               
} ALGraph;      
                
void MatToList(MGraph g,ALGraph *&G){
//将邻接矩阵g转换成邻接表G
    int i,j;
    ArcNode *p,*s;
    G=(ALGraph *)malloc(sizeof(ALGraph));
    for (i=0; i<g.vexnum; i++)             
        G->vertices[i].firstarc=NULL;
    for (i=0; i<g.vexnum; i++)    
        for (j=0; j<g.vexnum; j++)
            if (g.arcs[i][j]!=0){
	 			p=(ArcNode *)malloc(sizeof(ArcNode)); 
	            p->adjvex=j; p->nextarc=NULL;
				if(!G->vertices[i].firstarc)
					G->vertices[i].firstarc=p;
				else{
					s=G->vertices[i].firstarc;
					while(s->nextarc) s=s->nextarc;
					s->nextarc=p;
				}
            }
    G->vexnum=g.vexnum;
    G->arcnum=g.arcnum;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值