数据结构》严奶奶版本---图(1) 图的基础操作及应用 完整源码


图的基础操作及应用 完整源码


在这里插入图片描述

//图的存储结构
//邻接矩阵、邻接表

#include <iostream>
#include <windows.h>
#include <iomanip>

using namespace std;

#define MAXINT 65535
#define MAX_VERTEX_NUM 100
#define STACK_INIT_SIZE 100
#define STACK_ADD 10

typedef char InfoType;//附加信息
typedef int VRType;//顶点关系
typedef char VertexType;//顶点数据
typedef int QElemType;

typedef enum{

	DG,//有向图
	DN,//有向网
	UDG,//无向图
	UDN//无向网

}GraphKind;

//邻接矩阵存储结构定义
typedef struct arccell{
	
	VRType adj;// VRType 是顶点关系类型
				// 对无权图,用 1 或 0 表示相邻否;
				// 对带权图,则为权值类型。
	
	InfoType *info;// 该弧相关信息的指针

}ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

//图的结构定义
typedef struct mgraph{ 

     VertexType vexs[MAX_VERTEX_NUM];// 顶点信息 
     AdjMatrix arcs;  // 邻接矩阵	 
     int vexnum;// 顶点数
	 int arcnum;//弧数  	 
     GraphKind   kind; // 图的种类标志  
	 
}MGraph;

//邻接表存储结构定义:
typedef struct arcnode {  

  int adjvex;   // 该弧所指向的顶点的位置
  struct arcnode  *nextarc;  // 指向下一条弧的指针

} ArcNode;

typedef struct vnode { 

  VertexType  data;   // 顶点信息
  ArcNode  *firstarc;   // 指向第一条依附该顶点的弧

}VNode, AdjList[MAX_VERTEX_NUM];

typedef struct {  

     AdjList  vertices;
     int vexnum;
	 int arcnum; 
     int kind;          // 图的种类标志

}ALGraph;

//链队列结构类型定义
typedef struct qnode{

	QElemType data;
	struct qnode *prior;
	struct qnode *next;

}QNode,*Queue;

typedef struct linkqueue{

	Queue front;
	Queue rear;

}LinkQueue;

//顺序栈结构定义
typedef struct sqstack{

	int *base;
	int *top;
	int stacksize;

}SqStack;

//辅助数组
typedef struct closedge{

	VertexType adjvex;

	VRType lowcost;

}ClosEdge[MAX_VERTEX_NUM];

bool visited[100];
bool (* VisitFunc)(int v,ALGraph G);

bool create_graph(ALGraph &g);//建立有向图的邻接表
bool create_graph(MGraph &g);//采用邻接矩阵表示法,创建有向网
bool create_UDN(MGraph &g);//采用邻接矩阵表示法,创建无向网
bool create_UDG(ALGraph &g);//采用邻接表表示法,创建无向图 
int locate_vertex(ALGraph g,VertexType v);//查找
int locate_vertex(MGraph h,VertexType v);//查找
void output(ALGraph g);//输出图
void output(MGraph g);//输出图
int first_adjvex(ALGraph g,int v);//返回第一个相邻节点序号
int next_adjvex(ALGraph g,int v,int w);//返回v相对w的下一个节点的序号

void DFS(ALGraph g,int v);
void DFSTraverse(ALGraph g,bool(*Visit)(int v,ALGraph G));//深度优先遍历
void BFSTraverse(ALGraph g, bool(*Visit)(int v,ALGraph G));//广度优先遍历
void DFSSearch(ALGraph g,int v, int s, char *PATH);
bool TopologicalSort(ALGraph g);//拓扑排序
void MiniSpanTree_P(MGraph G, VertexType u);//最小生成树
int LocateVex(MGraph G,char v);//定位节点
int LocateVex(ALGraph G,char v);
void FindInDegree(ALGraph G,int indegree[]);//入度数值

//队列操作
void init_queue(LinkQueue &q);//初始化
void en_queue(LinkQueue &q,QElemType e);//入队
void de_queue(LinkQueue &q,QElemType &e);//出队
bool empty_queue(LinkQueue q);//判空
void print_queue(LinkQueue q);//输出

//顺序栈操作
bool init_stack(SqStack &s);//栈初始化
bool push(SqStack &s,int d);//入栈
bool pop(SqStack &s,int &d);//出栈
bool judge_empty(SqStack s);//判空
bool get_top(SqStack s,int &d);//得到栈顶元素
bool print_stack(SqStack s);//输出栈

void show();//显示菜单
void switch_channel(int channel);//菜单功能实现
bool visit(int v,ALGraph G);//输出节点

ALGraph ga1,ga2;//邻接表
MGraph gm1,gm2;//邻接矩阵
char *path = new char[100];
bool found = false;
int w=0,k=0,j=0;

int main()
{
	int channel;

	do{
		show();
		cout<<"请输入操作:";
		cin>>channel;
		switch_channel(channel);
		cout<<endl;
	
	}while(1);
	return 0;
}

void show()
{
	cout<<"图的存储结构的建立\n";
	cout<<"1--有向图的邻接表"<<endl;
	cout<<"2--有向图的邻接矩阵"<<endl;
	cout<<"3--无向图的邻接表"<<endl;
	cout<<"4--无向图的邻接矩阵"<<endl;
	cout<<"5--深度优先遍历、广度优先遍历"<<endl;
	cout<<"6--无向图简单路径"<<endl;
	cout<<"7--无向图最小生成树"<<endl;
	cout<<"8--有向图拓扑排序"<<endl;
}

void switch_channel(int channel)
{
	switch(channel)
	{
	case 1: create_graph(ga1);output(ga1);break;
	case 2: create_graph(gm1);output(gm1);break;
	case 3: create_UDG(ga2);output(ga2);break;
	case 4: create_UDN(gm2);output(gm2);break;
	case 5:{   
				cout<<"有向图:";
				cout<<"深度优先遍历:";
				DFSTraverse(ga1,visit);
				cout<<"广度优先遍历";
				BFSTraverse(ga1,visit);
				cout<<endl;

				cout<<"无向图:";
				cout<<"深度优先遍历:";
				DFSTraverse(ga2,visit);
				cout<<"广度优先遍历";
				BFSTraverse(ga2,visit);
				cout<<endl;
		   }break;
	case 6: {
				int v,m;
				cout<<"请输入要查询的路径起始端点编号:";
				cin>>v;
				cout<<"请输入要查询的路径尾端点编号:";
				cin>>m;
				DFSSearch(ga2,1,3,path);
				cout<<endl;

			}break;
	case 7: output(gm2);MiniSpanTree_P(gm2,gm2.vexs[0]);cout<<endl;break;
	case 8: output(ga1); TopologicalSort(ga1); cout<<endl;break;
	default:exit(1);break;
	
	}
}
//建立有向图的邻接表
bool create_graph(ALGraph &g)
{
	char ch;
	char v1,v2;
	ArcNode *p;
	int i,j,k;

	cout<<"请输入有向图的顶点个数:";
	cin>>g.vexnum;
	cout<<"请输入有向图的弧个数:";
	cin>>g.arcnum;
	
	cout<<"请输入图中的顶点"<<endl;
	for(i =0 ;i < g.vexnum; i++)// 输入顶点信息
	{
		cin>>ch;
		g.vertices[i].data = ch;
		g.vertices[i].firstarc = NULL;//初始化表头结点的指针域为 NULL

	}

	for(k = 0;k < g.arcnum; k++)
	{
		cout<<"请输入图中第"<<k+1<<"条弧的起点和终点"<<endl;
		cin>>v1>>v2;//输入弧所依附的顶点
	
		i = locate_vertex(g,v1);//确定 v1 和 v2 在 G 中的位置
		j = locate_vertex(g,v2);

		p = new ArcNode;
		if(!p)
			return false;

		p->adjvex = j;
		p->nextarc = g.vertices[i].firstarc;//该弧插入邻接表中,采用头插法
		g.vertices[i].firstarc = p;
		
	}

	return true;
}
//采用邻接矩阵表示法,创建有向网
bool create_graph(MGraph &g)
{
	int i,j,k,w;
	char v1,v2;

	cout<<"请输入有向图的顶点个数:";
	cin>>g.vexnum;
	cout<<"请输入有向图的弧个数:";
	cin>>g.arcnum;
	
	cout<<"请输入顶点:";
	for(i = 0;i < g.vexnum; i++)
		cin>>g.vexs[i];
	
	for(i = 0;i < g.vexnum; i++)
		for(j = 0;j < g.vexnum; j++)
			g.arcs[i][j].adj = MAXINT;//初始化邻接矩阵,边的权值均置为无穷
	
	for(k = 0;k < g.arcnum; k++)
	{
		cout<<"输入一条边依附的顶点及权值: ";
		cin>>v1>>v2>>w;
		i = locate_vertex(g,v1);//确定 v1 和 v2 在 G 中的位置
		j = locate_vertex(g,v2);

		g.arcs[i][j].adj = w;
	}

	return true;
}
//采用邻接矩阵表示法,创建无向网
bool create_UDN(MGraph &g)
{
	int i,j,k,w;
	char v1,v2;

	cout<<"请输入无向图的顶点个数:";
	cin>>g.vexnum;
	cout<<"请输入无向图的弧个数:";
	cin>>g.arcnum;
	
	cout<<"请输入顶点:";
	for(i = 0;i < g.vexnum; i++)
		cin>>g.vexs[i];
	
	for(i = 0;i < g.vexnum; i++)
		for(j = 0;j < g.vexnum; j++)
			g.arcs[i][j].adj = MAXINT;//初始化邻接矩阵,边的权值均置为无穷
	
	for(k = 0;k < g.arcnum; k++)
	{
		cout<<"输入一条边依附的顶点及权值: ";
		cin>>v1>>v2>>w;
		i = locate_vertex(g,v1);//确定 v1 和 v2 在 G 中的位置
		j = locate_vertex(g,v2);

		g.arcs[i][j].adj = w;// 边<v1, v2>对应的矩阵元素值
		g.arcs[j][i].adj = w;//置<v1, v2>的对称边<v2, v1>的矩阵元素值
	}

	return true;
}
//采用邻接表表示法,创建无向图 
bool create_UDG(ALGraph &g)
{
	int i,j,k,w;
	char v1,v2;
	ArcNode *p;
	ArcNode *p2;

	cout<<"请输入无向图的顶点个数:";
	cin>>g.vexnum;
	cout<<"请输入无向图的弧个数:";
	cin>>g.arcnum;
	
	cout<<"输入各个顶点:\n";
	for(i = 0;i < g.vexnum; i++)// 输入顶点信息
	{
		cin>>g.vertices[i].data;
		g.vertices[i].firstarc = NULL;//初始化表头结点的指针域为 NULL
	}
	
	cout<<"输入边上的两个顶点:\n";
	for(k = 0;k < g.arcnum; k++)
	{
		cin>>v1>>v2;//输入弧所依附的顶点

		i = locate_vertex(g,v1);
		j = locate_vertex(g,v2);

		p = new ArcNode;//生成一个新的边结点*p
	    if(!p)
			return false;
		p->adjvex = j;//邻接点序号为 j
		p->nextarc = g.vertices[i].firstarc;//该弧插入邻接表中,采用头插法
		g.vertices[i].firstarc = p;//将新结点*p 插入顶点 vi 的边表头部

		p2 = new ArcNode;//生成另一个对称的新的边结点*p2
	    if(!p2)
			return false;
		p2->adjvex = i;//邻接点序号为 i
		p2->nextarc = g.vertices[j].firstarc;
		g.vertices[j].firstarc = p2;//将新结点*p2 插入顶点 vj 的边表头部

	}

	return true;
}
//查找邻接表
int locate_vertex(ALGraph g,VertexType v)
{
	int i;

	for(i = 0;i < g.vexnum; i++)
		if(g.vertices[i].data == v)
			return i;
	return -1;
}
//查找邻接矩阵
int locate_vertex(MGraph g,VertexType v)
{
	int i;

	for(i = 0;i < g.vexnum; i++)
		if(g.vexs[i] == v)
			return i;
	return -1;
}
//输出图邻接表
void output(ALGraph g)
{
	ArcNode *p;
	int i;
	cout<<"当前图结构:\n";
	for(i = 0;i < g.vexnum; i++)
	{
		cout<<g.vertices[i].data;
		p = g.vertices[i].firstarc;
		
		while(p)
		{
			cout<<"-->"<<g.vertices[p->adjvex].data;
			p = p->nextarc;
		}
		cout<<endl;
	}
}
//输出图邻接矩阵
void output(MGraph g)
{
	int i,j;
	for(i=0;i<g.vexnum;i++)
	{
		for(j=0;j<g.vexnum;j++)
			{
				if(g.arcs[i][j].adj == MAXINT)
					cout<<setw(7)<<"NULL"<<" ";
				else
					cout<<setw(7)<<g.arcs[i][j].adj<<" ";
			}
		cout<<endl;
	}
}


//返回第一个相邻节点序号
int first_adjvex(ALGraph g,int v)
{
	if(!g.vertices[v].firstarc)
		return -1;

	return g.vertices[v].firstarc->adjvex;
}
//返回v相对w的下一个节点的序号
int next_adjvex(ALGraph g,int v,int w)
{
	ArcNode *p;
	int flag=0;

	p = g.vertices[v].firstarc;

	while(p)
	{
		if(p->adjvex == w)
		{
			flag = 1;
			break;
		}

		p = p->nextarc;
	}

	if(flag)
	{
		if(p->nextarc)
			return p->nextarc->adjvex;
	}

	return -1;
}

//深度优先遍历
void DFS(ALGraph g,int v)
{// 从第 v 个顶点出发,深度优先搜索遍历连通图 G
	visited[v] = TRUE;
	VisitFunc(v,g);
	int w;

   for(w=first_adjvex(g,v);w>=0;w=next_adjvex(g,v,w))
        if (!visited[w])  // 对 v 的尚未访问的邻接顶点 w递归调用 DFS 
			DFS(g, w);  
 
}
//深度优先遍历。
void DFSTraverse(ALGraph g,bool(*Visit)(int v,ALGraph G))
{
   
	VisitFunc = Visit; //使用全局变量 VisitFunc,使 DFS 不必设函数指针参数
	int v;

	for (v=0; v<g.vexnum; ++v) 
		visited[v] = FALSE;// 访问标志数组初始化 

	for (v=0; v<g.vexnum; ++v) 
	 if (!visited[v]) 
		 DFS(g, v);// 对尚未访问的顶点调用 DFS

              
}
//广度优先遍历
void BFSTraverse(ALGraph g, bool(*Visit)(int v,ALGraph G))
{
	LinkQueue Q;
	int v,u,w;
	VertexType e;

	 for (v=0; v<g.vexnum; ++v)
		visited[v] = FALSE;//初始化访问标志
	 
	 init_queue(Q);// 初始化的辅助队列 Q

	 for ( v=0;  v<g.vexnum;  ++v )
     if ( !visited[v]) // v 尚未访问
	 {          
        visited[v] = true;  
		Visit(v,g); // 访问 v   
		en_queue(Q, v); // v 入队列            
		while (!empty_queue(Q)) 
		{
 			  de_queue(Q, u); // 队头元素出队并置为 u
			  
   			 for(w=first_adjvex(g, u); w>=0; w=next_adjvex(g,u,w))
   			 if ( ! visited[w])
			 {
       		  visited[w]=TRUE;  
			  Visit(w,g);
       		  en_queue(Q, w); // 访问的顶点 w 入队列 
			 } 
		} 
	} 

}

//简单路径
void DFSSearch(ALGraph g, int v, int s, char *PATH)
{
	// 从第 v 个顶点出发递归地深度优先遍历图g,
	// 求得一条从 v 到 s 的简单路径,并记录在 PATH 中

	visited[v] = true;// 访问第 v 个顶点


	PATH[j]=g.vertices[v].data;j++;	 // 第 v 个顶点加入路径 

	for (w=first_adjvex(g,v);w>=0&&!found; w=next_adjvex(g,v,w))
	if (w==s) 
	  {
		found = true;  
		PATH[j]=g.vertices[w].data; 
		cout<<"简单路径为:";
		for (k=0;k<=j;k++) 
			cout<<PATH[k]<<" ";
	  }
	  else  if (!visited[w])
		  DFSSearch(g,w,s,PATH);


	if(!found)  j--; // 从路径上删除第 v 个顶点

}

//队列基础操作
void init_queue(LinkQueue& Q) 
{
  Q.front=Q.rear=(Queue)malloc(sizeof(QNode));
  Q.front->next = Q.rear->prior = NULL;
}
void en_queue( LinkQueue& Q, QElemType e ) 
{
	Queue p;
  p = (Queue) malloc (sizeof(QNode));
  p->data = e;  p->next = NULL;
  p->prior = Q.front;
  Q.rear->next = p;  Q.rear = p;
}
void de_queue( LinkQueue& Q, QElemType& e )
{
  Q.front = Q.front->next;  e = Q.front->data;
}
bool empty_queue(LinkQueue q)
{
	if(q.front == q.rear)
		return true;
	return false;
}
void print_queue(LinkQueue Q)
{
	Queue q;
	q = Q.front;
	while(q!=Q.rear)
	{
		cout<<q->data<<" ";
		q = q->next;
	}
}

//栈基础操作
//栈初始化
bool init_stack(SqStack &s)
{
	s.base = new int[STACK_INIT_SIZE];
	if(!s.base)
		return false;

	s.top = s.base;
	s.stacksize = STACK_INIT_SIZE;

	return true;
}
//入栈
bool push(SqStack &s,int d)
{
	if(s.top - s.base >= s.stacksize)
	{
		s.base = (int *)realloc(s.base,(s.stacksize + STACK_ADD)*sizeof(int));
		if(!s.base)
			return false;
		s.top = s.base + s.stacksize;
		s.stacksize += STACK_ADD;
	}
	
	*s.top++ = d;

	return true;

}
//出栈
bool pop(SqStack &s,int &d)
{
	if(judge_empty(s))
		return false;

	d = *(--s.top);

	return true;

}
//判空
bool judge_empty(SqStack s)
{	
	if(s.top == s.base)
		return true;

	return false;

}
//得到栈顶元素
bool get_top(SqStack s,int &d)
{
	if(judge_empty(s))
		return false;

	d = *(s.top - 1);

	return true;
}
//输出栈
bool print_stack(SqStack s)
{
	int *t;
	t = s.base;
	
	while(t != s.top)
	{
		cout<<*t<<" ";
		t++;
	}

	cout<<endl;

	return true;
}

//拓扑排序
bool TopologicalSort(ALGraph g)
{
	SqStack s;
	int i,count,k;
	int indegree[MAX_VERTEX_NUM];
	ArcNode *p;

	init_stack(s);

	for(i=0;i<g.vexnum;i++)
		indegree[i] = 0;

	FindInDegree(g,indegree);//对各顶点求入度
	
	for(i=0;i<g.vexnum;i++)
	{
		if(!indegree[i])//入度为零的顶点入栈
			push(s,i);
	}

	count = 0;//对输出顶点计数
	while(!judge_empty(s))
	{
		pop(s,i);
		cout<<setw(5)<<g.vertices[i].data;
		count++;

		for(p=g.vertices[i].firstarc;p;p=p->nextarc)
		{
			k=p->adjvex;//取出弧头顶点在图中的位置
			if(!(--indegree[k]))//弧头顶点的入度减一,新产生的入度为零的顶
				push(s,k);
		}
	}
	cout<<endl;

	if (count<g.vexnum) 
	{
		cout<<"有回路"<<endl;
		return true;
	}
	
	cout<<"无回路,拓扑序列如上"<<endl;
	return false;
}
//最小生成树
void MiniSpanTree_P(MGraph g, VertexType u)
{
	ClosEdge closedge;
	int i,j,k,t,min;
	i=j=k=t=min=0;

	k = LocateVex(g,u);
	for(j=0;j<g.vexnum;j++)// 辅助数组初始化
		if(j != k)
		{
			closedge[j].adjvex = u;
			closedge[j].lowcost = g.arcs[k][j].adj;
		}

		closedge[k].lowcost = 0;
		cout<<"最小生成树上的边有:"<<endl;

		for(i=1;i<g.vexnum;i++)//建立 n-1 条边,循环 n-1 次即可
		{
			for(j=0;j<g.vexnum;j++)
				if(closedge[j].lowcost != 0)
				{
					min=closedge[j].lowcost;
					k=j;
					break;
				}

			for(t=0;t<g.vexnum;t++)
				if(closedge[t].lowcost != 0 && closedge[t].lowcost<min)
				{// 求出加入生成树的下一个顶点(k)
					k=t;
					min=closedge[t].lowcost;
				}

			cout<<closedge[k].adjvex<<"-->"<<g.vexs[k]<<endl; // 输出生成树上一条边

			closedge[k].lowcost = 0;// 第 k 顶点并入 U 集

			for(j=0;j<g.vexnum;j++)//修改其它顶点的最小边
				if(g.arcs[k][j].adj < closedge[j].lowcost)
				{
					closedge[j].adjvex = g.vexs[k];
					closedge[j].lowcost = g.arcs[k][j].adj;
				}
		}


}

//邻接矩阵获取结点
int LocateVex(MGraph g,char v)
{//返回顶点 v 在图中的位置, 存在则返回 v 在顶点表中的下标;否则返回-1
	int i;
	for(i=0;i<g.vexnum;i++)
		if(g.vexs[i]==v) 
			return i;

	return -1;
}

//邻接表获取节点
int LocateVex(ALGraph g,char v)
{//返回顶点 v 在图中的位置, 存在则返回 v 在顶点表中的下标;否则返回-1
	int i;
	for(i=0;i<g.vexnum;i++)
		if(g.vertices[i].data==v) 
			return i;

	return -1;
}
//求取入度值
void FindInDegree(ALGraph G,int indegree[])
{
	int i;ArcNode *p;

	for (i=0;i<G.vexnum;i++)
	{
		p=G.vertices[i].firstarc;

		while (p)
		{
			indegree[p->adjvex]++;
			p=p->nextarc;
		}
	}

}

bool visit(int e,ALGraph G)
{
	cout<<G.vertices[e].data<<" ";
	
	return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值