图实验(基于邻接表)–合工大数据结构实验6+7
graph_Node.h
#include"createGrpAdjLinkedList.h"
#include<queue>
#include<algorithm>
#define INTF 2147483646
void shownemu()
{
cout<<"-------------------------------------------菜单---------------------------------------\n";
cout<<" -------------实验六-------------\n";
cout<<"1-打印出图(网)的两种遍历序\n";
cout<<"2求给定图中的边(或弧)的数目\n";
cout<<"3对给定的图G及出发点v0,从V0出发深度优先遍历图G,并构造出相应的生成树或生成森林\n";
cout<<"4对给定的图G及出发点v0,从V0出发广度优先遍历图G,并构造出相应的生成树或生成森林\n";
cout<<"5实现Prim算法,求解给定图G的最小生成树\n";
cout<<"6实现Kruskal算法,求解给定图G的最小生成树\n";
cout<<" -------------实验七-------------\n";
cout<<"7实现Dijkstra算法,求解给定图G指定顶点到其余顶点之间的最短路径\n";
cout<<"8实现Floyd 算法,求解给定图G各顶点之间的最短路径\n";
cout<<"9求解给定图G的拓扑序列\n";
cout<<"10求解给定AOE网的关键路径\n";
cout<<" 说明:此文件以邻接表为存储结构\n";
cout<<"--------------------------------------------------------------------------------------\n";
}
void DFS(Graph2 graph, int v, bool visitedd[]) {
visitedd[v] = 1;
cout<<graph.VerList[v].data<<" ";
EdgeNode* edge = graph.VerList[v].firstEdge;
while (edge != NULL) {
if (visitedd[edge->adjVer] == 0) {
DFS(graph, edge->adjVer, visitedd);
}
edge = edge->next;
}
}
void DFSTraverse(Graph2 graph,int v) {
bool visitedd[MaxVerNum + 1] = { 0 };
DFS(graph,v,visitedd);
for (int v = 1; v <= graph.VerNum; v++) {
if (visitedd[v] == 0) {
DFS(graph, v, visitedd);
}
}
}
void BFS(Graph2 graph, int v, bool visitedd[]){
visitedd[v]=1;
queue<int> q;
q.push(v);
while(!q.empty())
{
int temp=q.front();
q.pop();
cout<<graph.VerList[temp].data<<" ";
EdgeNode *p=graph.VerList[temp].firstEdge;
while(p)
{
if(!visitedd[p->adjVer])
{
q.push(p->adjVer);
visitedd[p->adjVer]=1;
}
p=p->next;
}
}
}
void BFSTraverse(Graph2 graph ,int v){
bool visitedd[MaxVerNum + 1] = { 0 };
BFS(graph,v,visitedd);
for (int v = 1; v <= graph.VerNum; v++) {
if (visitedd[v] == 0) {
BFS(graph, v, visitedd);
}
}
}
int vernum(Graph2 g)
{
int n=g.VerNum;
int num=0;
EdgeNode *p=NULL;
for(int i=1;i<=n;i++)
{
p=g.VerList[i].firstEdge;
while(p!=NULL)
{
num++;
p=p->next;
}
}
if(g.gKind==0||g.gKind==1) num/=2;
return num;
}
void dfs_generate_tree(Graph2 g, bool visitedd[], int u, int parent[]) {
visitedd[u] = true;
EdgeNode* p = g.VerList[u].firstEdge;
while (p) {
if (!visitedd[p->adjVer]) {
parent[p->adjVer] = u;
dfs_generate_tree(g, visitedd, p->adjVer, parent);
}
p = p->next;
}
}
void dfsTraverse_3(Graph2 g, bool visitedd[], int u) {
int parent[MaxVerNum + 1];
for (int i = 1; i <= g.VerNum; i++) {
parent[i] = -1;
}
dfs_generate_tree(g, visitedd, u, parent);
for (int i = 1; i <= g.VerNum; i++) {
if (parent[i] != -1) {
printf("%c->%c ", g.VerList[parent[i]].data, g.VerList[i].data);
}
}
for(int i = 1; i <= g.VerNum; i++)
{
if(!visitedd[i])
{
DFS(g, i,visitedd);
}
}
}
void bfs_generate_tree(Graph2 g, bool visited[], int parent[], int v) {
int queue[MaxVerNum];
int front = 0;
int rear = 0;
queue[rear++] = v;
visited[v] = true;
while (front != rear) {
int u = queue[front++];
EdgeNode* p = g.VerList[u].firstEdge;
while (p) {
int w = p->adjVer;
if (!visited[w]) {
visited[w] = true;
parent[w] = u;
queue[rear++] = w;
}
p = p->next;
}
}
}
void bfsTraverse_4(Graph2 g, bool visitedd[],int v) {
int parent[MaxVerNum + 1];
for (int i = 1; i <= g.VerNum; i++) {
parent[i] = -1;
}
bfs_generate_tree(g, visitedd, parent, v);
printf("BFS生成树的边信息:\n");
for (int i = 1; i <= g.VerNum; i++) {
if (parent[i] != -1) {
printf("(%c, %c)\n", g.VerList[parent[i]].data, g.VerList[i].data);
}
}
}
void Prim(Graph2 g)
{
int lowCost[100];
int closest[100];
for(int i=1;i<=g.VerNum;i++)
{
lowCost[i]=INF;
closest[i]=1;
}
EdgeNode*p=g.VerList[1].firstEdge;
while(p)
{
lowCost[p->adjVer]=p->eInfo;
p=p->next;
}
for(int i=2;i<=g.VerNum;i++)
{
int minCost = INF;
int minVertex = -1;
for(int j=2;j<=g.VerNum;j++)
{
if(lowCost[j]!=0&&lowCost[j]<minCost)
{
minCost=lowCost[j];
minVertex=j;
}
}
if(minVertex==-1) {
break;
}
cout<<g.VerList[closest[minVertex]].data<<"->"<<g.VerList[minVertex].data<<":"<<minCost<<endl;
lowCost[minVertex] = 0;
EdgeNode* q = g.VerList[minVertex].firstEdge;
while (q) {
int adjVer = q->adjVer;
int weight = q->eInfo;
if (weight < lowCost[adjVer]) {
lowCost[adjVer] = weight;
closest[adjVer] = minVertex;
}
q = q->next;
}
}
}
typedef struct {
int start;
int end;
int weight;
} Edge;
bool compareEdges(const Edge& e1, const Edge& e2) {
return e1.weight < e2.weight;
}
int findRoot(vector<int>& p, int x) {
if (p[x] !=x)
p[x] = findRoot(p, p[x]);
return p[x];
}
void Kruskal(Graph2 g)
{
vector<Edge> edges;
for(int i=1;i<=g.VerNum;i++)
{
EdgeNode*p=g.VerList[i].firstEdge;
while(p)
{
int start=i;
int end=p->adjVer;
int weight=p->eInfo;
edges.push_back({start,end,weight});
p=p->next;
}
}
sort(edges.begin(),edges.end(),compareEdges);
vector<int> parent(g.VerNum+1);
for (int i=1;i<=g.VerNum;i++) {
parent[i]=i;
}
vector<Edge> mst;
int numEdges=0;
for (const auto&edge:edges) {
int rootStart=findRoot(parent,edge.start);
int rootEnd=findRoot(parent,edge.end);
if (rootStart!=rootEnd) {
mst.push_back(edge);
numEdges++;
parent[rootStart] = rootEnd;
if (numEdges==g.VerNum-1)
break;
}
}
cout << "用Kauskal算法最小生成树为:" << endl;
for (auto&edge:mst) {
cout<<g.VerList[edge.start].data<<"--"<<g.VerList[edge.end].data<<":"<<edge.weight<<endl;
}
}
bool topo(Graph2 g,vector<int>& topologicalOrder)
{
vector<int> ans;
int in[100];
for(int i=1;i<=g.VerNum;i++) in[i]=0;
for(int i=1;i<=g.VerNum;i++)
{
EdgeNode*p=g.VerList[i].firstEdge;
while(p)
{
in[p->adjVer]++;
p=p->next;
}
}
queue<int>q;
for(int i=1;i<=g.VerNum;i++)
{
if(in[i]==0) q.push(i);
}
while(!q.empty())
{
int current = q.front();
ans.push_back(current);
q.pop();
EdgeNode*temp=g.VerList[current].firstEdge;
while(temp)
{
in[temp->adjVer]--;
if(in[temp->adjVer]==0)
{
q.push(temp->adjVer);
}
temp=temp->next;
}
}
if(ans.size()!=g.VerNum) return false;
topologicalOrder=ans;
return true;
}
void CriticalPath(Graph2& graph)
{
vector<int> topologicalOrder;
vector<int> ve(graph.VerNum + 1, 0);
vector<int> vl(graph.VerNum + 1, INF);
if (!topo(graph, topologicalOrder))
{
cout << "存在环,无法求解关键路径" << endl;
return;
}
for (int i = 0; i < topologicalOrder.size(); i++)
{
int v = topologicalOrder[i];
EdgeNode* p = graph.VerList[v].firstEdge;
while (p)
{
int w = p->adjVer;
ve[w] = max(ve[w], ve[v] + p->eInfo);
p = p->next;
}
}
vl[graph.VerNum] = ve[graph.VerNum];
for (int i = topologicalOrder.size() - 1; i >= 0; i--)
{
int v = topologicalOrder[i];
EdgeNode* p = graph.VerList[v].firstEdge;
while (p)
{
int w = p->adjVer;
vl[v] = min(vl[v], vl[w] - p->eInfo);
p = p->next;
}
}
cout << "关键路径:" << endl;
for (int i = 1; i <= graph.VerNum; i++)
{
EdgeNode* p = graph.VerList[i].firstEdge;
while (p)
{
int j = p->adjVer;
int e = ve[i];
int l = vl[j] - p->eInfo;
if (e == l)
cout << graph.VerList[i].data << " -> " << graph.VerList[j].data << endl;
p = p->next;
}
}
}
int path[100][100];
vector<vector<int>> Floyd(Graph2 g)
{
int n=g.VerNum;
vector<vector<int>> dist(100,vector<int>(100,0));
for(int i=1;i<=g.VerNum;i++)
{
for(int j=1;j<=g.VerNum;j++)
{
dist[i][j]=INF;
path[i][j]=-1;
}
}
for(int i=1;i<=g.VerNum;i++)
{
EdgeNode*p=g.VerList[i].firstEdge;
while(p)
{
dist[i][p->adjVer]=p->eInfo;
path[i][p->adjVer]=i;
p=p->next;
}
}
for(int m=1;m<=n;m++)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(dist[i][j]>dist[i][m]+dist[m][j]&&i!=j)
{
dist[i][j]=dist[i][m]+dist[m][j];
path[i][j]=path[m][j];
}
}
}
}
return dist;
}
vector<int> Dijkstra(Graph2 g,int v0,bool visitedd[])
{
int miin,pos;
visitedd[v0]=true;
int n=g.VerNum;
vector<int> dist(100,INF);
for(int i=1;i<=g.VerNum;i++) dist[i]=INF;
EdgeNode*p=g.VerList[v0].firstEdge;
while(p)
{
dist[p->adjVer]=p->eInfo;
p=p->next;
}
for(int i=1;i<=n;i++)
{
miin=INF;
for(int j=1;j<=n;j++)
{
if(!visitedd[j]&&dist[j]<miin)
{
miin=dist[j];
pos=j;
}
}
visitedd[pos]=true;
EdgeNode*temp=g.VerList[pos].firstEdge;
while(temp)
{
if(!visitedd[temp->adjVer]&&dist[temp->adjVer]>dist[pos]+temp->eInfo)
{
dist[temp->adjVer]=dist[pos]+temp->eInfo;
}
temp=temp->next;
}
}
return dist;
}
experiment6_Node.cpp
#include"graph_Node.h"
typedef long long ll;
typedef long double ld;
const int mod=1e5+7;
using namespace std;
int main() {
shownemu();
int choice;
cout<<"请输入你的选择";
cin>>choice;
while(choice)
{
char filename[100];
Graph2 g;
cout<<"请输入文件名称:";
cin>>filename;
bool jls=CreateGraphFromFile(filename,g);
if(jls) printGraph(g);
switch(choice)
{
case 1:
{
cout<<"dfs遍历结果:";
DFSTraverse(g,1);
cout<<"\nBFS遍历结果:";
BFSTraverse(g,1);
system("pause");
break;
}
case 2:
{
int n=vernum(g);
cout<<"边或弧的个数为"<<n<<endl;
system("pause");
break;
}
case 3:
{
bool visitedd[100];
for(int i=1;i<=g.VerNum;i++) visitedd[i] = false;
cout<<"请输入出发点v0";
int v0; cin>>v0;
cout<<"从v0开始的dfs遍历为:";
DFSTraverse(g,v0);
cout<<endl;
cout<<"\ndfs生成树为:";
dfsTraverse_3(g,visitedd,v0);
system("pause");
break;
}
case 4:
{
bool visitedd[100];
for(int i=1;i<=g.VerNum;i++) visitedd[i] = false;
cout<<"请输入出发点v0";
int v0; cin>>v0;
cout<<"从v0开始的bfs遍历为:";
BFSTraverse(g,v0);
cout<<endl;
cout<<"\nbfs生成树为:";
bfsTraverse_4(g,visitedd,v0);
system("pause");
break;
system("pause");
break;
}
case 5:
{
Prim(g);
system("pause");
break;
}
case 6:
{
Kruskal(g);
system("pause");
break;
}
case 7:
{
cout<<"Dijkstra算法求最短路径\n";
int begin;
cout<<"请输入起点位置下标:";cin>>begin;
bool visitedd[100]={false};
for(int i=1;i<=g.VerNum;i++) visitedd[i]=false;
auto dist=Dijkstra(g,begin,visitedd);
cout<<"从"<<begin<<"到各点最短距离如下(INF表示无通路或其自身)\n";
for(int i=1;i<=g.VerNum;i++)
{
if(dist[i]==INF)
cout<<begin<<"->"<<i<<" INF\n";
else
cout<<begin<<"->"<<i<<" "<<dist[i]<<"\n";
}
system("pause");
break;
}
case 8:
{
cout<<"Floyd求解最短路径\n";
auto dist=Floyd(g);
int n=g.VerNum;
int count=0;
cout<<"各顶点之间最短路径如下:\n";
for(int i=1;i<n;i++){
for(int j=i+1;j<=n;j++)
{
if(dist[i][j]!=65535)
cout<<i<<"->"<<j<<"="<<dist[i][j]<<" ";
}
cout<<endl;
}
system("pause");
break;
}
case 9:
{
vector<int> ans;
bool b=topo(g,ans);
if(!b)
{
cout<<"存在环 不存在拓朴序列.\n";
system("pause");
break;
}
for(auto i:ans)
{
cout<<g.VerList[i].data<<" ";
}
system("pause");
break;
}
case 10:
{
CriticalPath(g);
system("pause");
break;
}
}
system("cls");
shownemu();
cout<<"请输入您的选择:";
cin>>choice;
}
return 0;
}
createGrpAdjLinkedList.h
#include<iostream>
#include<string.h>
using namespace std;
#define INF 65535
#define MaxVerNum 100
typedef char elementType;
typedef int eInfoType;
typedef int cellType;
typedef enum{UDG, UDN, DG, DN} GraphKind;
typedef struct eNode
{
int adjVer;
int eInfo;
struct eNode* next;
}EdgeNode;
typedef struct vNode
{
char data;
EdgeNode* firstEdge;
}VerNode;
typedef struct GraphAdjLinkList
{
VerNode VerList[MaxVerNum+1];
int VerNum;
int ArcNum;
GraphKind gKind;
}Graph2;
bool visited[MaxVerNum+1];
void visit(Graph2 &G, int verID)
{
cout<<G.VerList[verID].data<<"\t";
visited[verID]=true;
}
int LocateVertex(Graph2 &G, elementType v)
{
for(int i=1;i<=G.VerNum;i++)
{
if( G.VerList[i].data==v )
return i;
}
return -1;
}
int firstAdj(Graph2 &G, int v)
{
EdgeNode *p;
p=G.VerList[v].firstEdge;
if(p)
return p->adjVer;
else
return 0;
}
int nextAdj(Graph2 &G, int v, int w)
{
EdgeNode *p;
p=G.VerList[v].firstEdge;
while(p->next)
{
if(p->adjVer==w)
return p->next->adjVer;
p=p->next;
}
return 0;
}
void printGraph(Graph2 &G)
{
int i=0,j=0;
switch(G.gKind)
{
case UDG:
cout<<"图类型:无向图"<<endl;
break;
case UDN:
cout<<"图类型:无向网"<<endl;
break;
case DG:
cout<<"图类型:有向图"<<endl;
break;
case DN:
cout<<"图类型:有向网"<<endl;
break;
default:
cout<<"图类型错误。"<<endl;
break;
}
cout<<"顶点数:"<<G.VerNum<<endl;
cout<<"边 数:"<<G.ArcNum<<endl;
cout<<"编号\t顶点\t边链表"<<endl;
EdgeNode* p;
for(i=1;i<=G.VerNum;i++)
{
cout<<i<<"\t"<<G.VerList[i].data<<"\t";
p=G.VerList[i].firstEdge;
while(p!=NULL)
{
cout<<p->adjVer<<"\t";
p=p->next;
}
cout<<endl;
}
cout<<endl;
}
void strLTrim(char* str);
int CreateGrpFromFile1(char fileName[], Graph2 &G)
{
FILE* pFile;
char str[1000];
char strTemp[10];
char* ss;
int i=0,j=0;
int edgeNum=0;
GraphKind graphType;
pFile=fopen(fileName,"r");
if(!pFile)
{
printf("错误:文件%s打开失败。\n",fileName);
return false;
}
ss=fgets(str,1000,pFile);
strncpy(strTemp,str,2);
while((ss!=NULL) && (strstr(strTemp,"//")!=NULL) )
{
ss=fgets(str,1000,pFile);
strncpy(strTemp,str,2);
}
if(strstr(str,"Graph")==NULL)
{
printf("错误:打开的文件格式错误!\n");
fclose(pFile);
return false;
}
if(fgets(str,1000,pFile)==NULL)
{
printf("错误:读取图的类型标记失败!\n");
fclose(pFile);
return false;
}
if(strstr(str,"UDG"))
graphType=UDG;
else if(strstr(str,"UDN"))
graphType=UDN;
else if(strstr(str,"DG"))
graphType=DG;
else if(strstr(str,"DN"))
graphType=DN;
else
{
printf("错误:读取图的类型标记失败!\n");
fclose(pFile);
return false;
}
if(fgets(str,1000,pFile)==NULL)
{
printf("错误:读取图的顶点元素失败!\n");
fclose(pFile);
return false;
}
char* token=strtok(str," ");
int nNum=1;
while(token!=NULL)
{
G.VerList[nNum].data=*token;
G.VerList[nNum].firstEdge=NULL;
token = strtok( NULL, " ");
nNum++;
}
int nRow=1;
int nCol=1;
EdgeNode* eR;
EdgeNode* p;
while(fgets(str,1000,pFile)!=NULL)
{
eR=NULL;
p=NULL;
nCol=1;
char* token=strtok(str," ");
while(token!=NULL)
{
if(atoi(token)>=1 && atoi(token)<INF)
{
p=new EdgeNode;
p->adjVer=nCol;
p->eInfo=atoi(token);
p->next=NULL;
if(G.VerList[nRow].firstEdge==NULL)
{
G.VerList[nRow].firstEdge=p;
eR=p;
}
else
{
eR->next=p;
eR=p;
}
edgeNum++;
}
token = strtok( NULL, " ");
nCol++;
}
nRow++;
}
G.VerNum=nNum;
if(graphType==UDG || graphType==UDN)
G.ArcNum=edgeNum / 2;
else
G.ArcNum=edgeNum;
G.gKind=graphType;
fclose(pFile);
return true;
}
int CreateGraphFromFile(char fileName[], Graph2 &G)
{
FILE* pFile;
char str[1000];
char strTemp[10];
int i=0,j=0;
int edgeNum=0;
eInfoType eWeight;
GraphKind graphType;
pFile=fopen(fileName,"r");
if(!pFile)
{
printf("错误:文件%s打开失败。\n",fileName);
return false;
}
while(fgets(str,1000,pFile)!=NULL)
{
strLTrim(str);
if (str[0]=='\n')
continue;
strncpy(strTemp,str,2);
if(strstr(strTemp,"//")!=NULL)
continue;
else
break;
}
if(strstr(str,"Graph")==NULL)
{
printf("错误:打开的文件格式错误!\n");
fclose(pFile);
return false;
}
while(fgets(str,1000,pFile)!=NULL)
{
strLTrim(str);
if (str[0]=='\n')
continue;
strncpy(strTemp,str,2);
if(strstr(strTemp,"//")!=NULL)
continue;
else
break;
}
if(strstr(str,"UDG"))
graphType=UDG;
else if(strstr(str,"UDN"))
graphType=UDN;
else if(strstr(str,"DG"))
graphType=DG;
else if(strstr(str,"DN"))
graphType=DN;
else
{
printf("错误:读取图的类型标记失败!\n");
fclose(pFile);
return false;
}
while(fgets(str,1000,pFile)!=NULL)
{
strLTrim(str);
if (str[0]=='\n')
continue;
strncpy(strTemp,str,2);
if(strstr(strTemp,"//")!=NULL)
continue;
else
break;
}
char* token=strtok(str," ");
int nNum=0;
while(token!=NULL)
{
G.VerList[nNum+1].data=*token;
G.VerList[nNum+1].firstEdge=NULL;
token = strtok( NULL, " ");
nNum++;
}
int nRow=1;
int nCol=1;
EdgeNode* eR;
EdgeNode* p;
elementType Nf,Ns;
while(fgets(str,1000,pFile)!=NULL)
{
strLTrim(str);
if (str[0]=='\n')
continue;
strncpy(strTemp,str,2);
if(strstr(strTemp,"//")!=NULL)
continue;
char* token=strtok(str," ");
if(token==NULL)
{
printf("错误:读取图的边数据失败!\n");
fclose(pFile);
return false;
}
Nf=*token;
token = strtok( NULL, " ");
if(token==NULL)
{
printf("错误:读取图的边数据失败!\n");
fclose(pFile);
return false;
}
Ns=*token;
for(nRow=1;nRow<=nNum;nRow++)
{
if(G.VerList[nRow].data==Nf)
break;
}
for(nCol=1;nCol<=nNum;nCol++)
{
if(G.VerList[nCol].data==Ns)
break;
}
if(graphType==UDN || graphType==DN)
{
token = strtok( NULL, " ");
if(token==NULL)
{
printf("错误:读取图的边数据失败!\n");
fclose(pFile);
return false;
}
eWeight=atoi(token);
}
eR=G.VerList[nRow].firstEdge;
while(eR!=NULL && eR->next!=NULL)
{
eR=eR->next;
}
p=new EdgeNode;
p->adjVer=nCol;
if(graphType==UDN || graphType==DN)
p->eInfo=eWeight;
else
p->eInfo=1;
p->next=NULL;
if(G.VerList[nRow].firstEdge==NULL)
{
G.VerList[nRow].firstEdge=p;
eR=p;
}
else
{
eR->next=p;
eR=p;
}
edgeNum++;
}
G.VerNum=nNum;
if(graphType==UDG || graphType==UDN)
G.ArcNum=edgeNum / 2;
else
G.ArcNum=edgeNum;
G.gKind=graphType;
fclose(pFile);
return true;
}
void strLTrim(char* str)
{
int i,j;
int n=0;
n=strlen(str)+1;
for(i=0;i<n;i++)
{
if(str[i]!=' ')
break;
}
for(j=0;j<n;j++)
{
str[j]=str[i];
i++;
}
}
void DestroyGraph(Graph2 &G)
{
EdgeNode *p,*u;
int vID;
for(vID=1; vID<=G.VerNum; vID++)
{
p=G.VerList[vID].firstEdge;
G.VerList[vID].firstEdge=NULL;
while(p)
{
u=p->next;
delete(p);
p=u;
}
}
p=NULL;
u=NULL;
G.VerNum=-1;
}
运行