图的基本操作
(1)键盘输入数据,建立一个有向图的邻接表。
(2)输出该邻接表。
(3)在有向图的邻接表的基础上计算各顶点的度,并输出。
(4)以有向图的邻接表为基础实现输出它的拓扑排序序列。
(5)采用邻接表存储实现无向图的深度优先遍历。
(6)采用邻接表存储实现无向图的广度优先遍历。
/*
本算法如果为邻接矩阵存储,无向图默认只求最小生成树,有向图默认只求任意两点最短路径
*/
#define FALSE 0
#define ERROR 0
#define OVERFLOW -2
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 20
采用链式存储实现栈的初始化、入栈、出栈操作
/
//下面为循环队列
#define MAXQSIZE 100 /*队列的最大长度*/
typedef struct {
int *base; // 队列的元素空间头指针指示器
int front;
int rear; /*尾指针指示器*/
}SqQueue;
int InitQueue(SqQueue &Q) {//初始化操作
Q.base = (int * )malloc(MAXQSIZE*sizeof(int));
if (!Q. base) exit (OVERFLOW);
Q.front=Q.rear =0;
return 1;
}
int EnQueue(SqQueue &Q,int e) {//入队操作
//int e;
if ((Q. rear+ 1) % MAXQSIZE == Q. front)
{
// printf("队列已满,不能进队\n");
return -1;//满标志
}
Q.base[Q.rear] = e;//进队
Q.rear = (Q. rear + 1) % MAXQSIZE;//队尾指针后移
return 1;
}
int DeQueue (SqQueue &Q) {//出队操作
int e;
if (Q. front == Q. rear) {
printf("队列已经为空\n");
return -1;
}
e = Q. base[Q. front];//队头出队
//printf("%d 出队\n",e);
Q.front = (Q.front + 1) % MAXQSIZE;//队头下标后移
return e;
}
int QueueEmpty (SqQueue &Q)
{
if (Q. front == Q. rear)
return 0;
else
return 1;
}
#include<stdio.h>
#include<stdlib.h>
#include"aa.h"
#include<iostream>
using namespace std;
#define MAX 50
#define INFINITY 1000000000
int k,Graph;//定点数
int dgree[MAX];
int visited[MAX];
int max(int a,int b)
{
return a>b?a:b;
}
typedef struct ArcNode//hu
{
int from,to,du;//该弧的尾和头顶点的位置
struct ArcNode *nextarc;//指向下一条弧的指针
int weigh;//权值
}ArcNode,*Linklist;
typedef struct VNode
{
int in,out,data;//定点信息;
ArcNode *firstarc;
}VNode;
struct VNode AdjList[MAX];
typedef struct{//邻接矩阵
int arcs[MAX][MAX];
int vexnum,arcnum;//边数和顶点数
int kind;//有向图,无向图
}MGraph;
MGraph M;
int cmp(const void *a,const void *b)
{
return *(int *)a-*(int *)b;
}
Linklist create()
{
Linklist p;
p=(Linklist)malloc(sizeof(ArcNode));
p->nextarc=NULL;
p->from=-1;
p->to=-1;
p->weigh=-1;
p->du=0;
return p;
}
void CreateGraph()//创建邻接表
{
int a,b,w,i;
Linklist p,q,s,t;
cout<<"请输入顶点的个数K:"; //顶点的个数
cin>>k;
cout<<"请输入始点(输入-1结束):";
for(i=0;i<k;i++)//度的初始化
{
AdjList[i].data=AdjList[i].in=AdjList[i].out=0;
AdjList[i].firstarc=create();
}
while(scanf("%d",&a))//from
{
if(a==-1)
break;
if(Graph==0)//有向图
{
//AdjList[a].firstarc=create();//初始化
p=AdjList[a].firstarc;
cout<<"请输入尾点和权值(当尾点为-1时,输入结束):";
while(scanf("%d",&b))
{
if(b==-1)
break;
scanf("%d",&w);
AdjList[a].out++;
AdjList[b].in++;
q=create();
q->from=a;
q->to=b;
q->weigh=w;
p->nextarc=q;
p=p->nextarc;
cout<<"请输入尾点和权值(当尾点为-1时,输入结束):";
}
cout<<"请输入始点(输入-1结束):";
}
else
{
cout<<"请输入尾点和权值(当尾点为-1时,输入结束):";
p=AdjList[a].firstarc;
while(scanf("%d",&b))
{
if(b==-1)
break;
scanf("%d",&w);
s=AdjList[b].firstarc;
AdjList[a].data++;
AdjList[b].data++;
q=create();
q->from=a;
q->to=b;
q->weigh=w;
while(p->nextarc) p=p->nextarc;
p->nextarc=q;
t=create();
t->from=b;
t->to=a;
t->weigh=w;
while(s->nextarc) s=s->nextarc;
s->nextarc=t;
cout<<"请输入尾点和权值(当尾点为-1时,输入结束):";
}
cout<<"请输入始点(输入-1结束):";
}
}
}
void print()//输出图
{
int i;
Linklist p;
for(i=0;i<k;i++)
{
p=AdjList[i].firstarc;
if(!p)
continue;
p=p->nextarc;
while(p)
{
printf("<%d,%d>%d ",p->from,p->to,p->weigh);
p=p->nextarc;
}
printf("\n");
}
//cout<<"k"<<k<<" ";
}
void TuoPuSort()//拓扑排序
{
int i,top=0;
Linklist p;
cout<<"拓扑序列为:";
if(Graph==0)//有向图
{
for(i=0;i<k;i++)
{
if(AdjList[i].in==0)
dgree[top++]=i;
}
top--;
while(top>=0)
{
if(top<0)
break;
cout<<"V"<<dgree[top]<<" ";
p=AdjList[dgree[top]].firstarc;
top--;//出战
if(!p) continue;
p=p->nextarc;
while(p)
{
AdjList[p->to].in--;
if(AdjList[p->to].in==0)
{
top++;
dgree[top]=p->to;
}
p=p->nextarc;
}
}
}
cout<<endl;
}
void GraphDu()//求图的度
{
int i;
for(i=0;i<k;i++)
{
if(Graph==0)
AdjList[i].data=AdjList[i].in+AdjList[i].out;
cout<<"V"<<i<<"的度为"<<AdjList[i].data<<endl;
}
}
void DFS(int v)
{
Linklist p;
visited[v]=1;
cout<<"V"<<v<<" ";
p=AdjList[v].firstarc;
p=p->nextarc;
while(p)
{
if(!visited[p->to])
DFS(p->to);
p=p->nextarc;
}
}
void DFSTraverse()//深度搜索
{
cout<<"无向图的深度遍历:";
int v;
for(v=0;v<k;v++)
visited[v]=0;
for(v=0;v<k;v++)
if(!visited[v])
DFS(v);
cout<<endl;
}
void BFSTraverse()//广度
{
cout<<"无向图的广度遍历:";
SqQueue Q;//定义队列
InitQueue(Q);//初始化
int v,e;
Linklist p;
for(v=0;v<k;v++)
visited[v]=0;
for(v=0;v<k;v++)
{
if(!visited[v])
{
cout<<"V"<<v<<" ";
EnQueue(Q,v);
while(!QueueEmpty(Q))
{
e=DeQueue (Q);
p=AdjList[e].firstarc;
p=p->nextarc;
while(p)
{
if(!visited[p->to])
{
visited[p->to]=1;
cout<<"V"<<v<<" ";
EnQueue(Q,p->to);
}
p=p->nextarc;
}
}
}
}
cout<<endl;
}
void DaYin1()//邻接表
{
cout<<"------------------------"<<endl;
cout<<"|输入0:创建图 |"<<endl;
cout<<"|输入1:输出图 |"<<endl;
cout<<"|输入2:输出图的度 |"<<endl;
cout<<"|输入3:对图进行拓扑排序|"<<endl;
cout<<"|输入-1:退出 |"<<endl;
cout<<"|请选择: |"<<endl;
cout<<"------------------------"<<endl;
return ;
}
void DaYin2()//邻接表
{
cout<<"------------------------"<<endl;
cout<<"|输入0:创建图 |"<<endl;
cout<<"|输入1:输出图 |"<<endl;
cout<<"|输入2:输出图的度 |"<<endl;
cout<<"|输入3:对图进行深度遍历|"<<endl;
cout<<"|输入4:对图进行广度遍历|"<<endl;
cout<<"|输入-1:退出 |"<<endl;
cout<<"|请选择: |"<<endl;
cout<<"------------------------"<<endl;
return;
}
///邻接矩阵
void JZGraph()//邻接矩阵的建立
{
cout<<"邻接矩阵:有向图请输入0,无向图请输入1,请选择:";
scanf("%d",&M.kind);
cout<<"请输入顶点的的个数:";
scanf("%d",&M.arcnum); // 顶点数
cout<<"请输入边的的个数:";
scanf("%d",&M.vexnum); // 边数
}
void MinRode(int v,int n)//dijsta
{
int s[MAX];//判断是否已存入该点到S集合中
int dist[MAX],pre[MAX],newdist;
int i,j;
for(i=0;i<M.arcnum;i++)
{
dist[i]=M.arcs[v][i];
s[i]=0;
pre[i]=v;
}
s[v]=1;
for(i=1;i<M.arcnum;i++)
{
int temp=INFINITY;
int u=v;
for(j=0;j<M.arcnum;j++)
if(!s[j]&&dist[j]<temp)
{
u=j;
temp=dist[j];
}
s[u]=1;
for(j=0;j<M.arcnum;j++)
if(!s[j]&& M.arcs[u][j]<INFINITY)
{
newdist=temp+M.arcs[u][j];
if(newdist<dist[j])
{
dist[j]=newdist;
pre[j]=u;
}
}
}
if(dist[n]>=INFINITY)
cout<<"V"<<v<<"与V"<<n<<"之间没有通路"<<endl;
else
{
cout<<"V"<<v<<"与V"<<n<<"之间最短路径为:"<<endl;
i=n;
while(i!=v)
{
cout<<"V"<<i<<"<--";
i=pre[i];
}
cout<<"V"<<v<<"\n"<<"最短路径长度为:"<<dist[n]<<endl;
}
}
void MinTree()//最小生成树
{
cout<<"最小生成树的权值为:";
int s[MAX];//判断是否已存入该点到S集合中
int dist[MAX],newdist,sum=0,pp;
int i,j;
for(i=0;i<M.arcnum;i++)
{
dist[i]=M.arcs[0][i];
s[i]=0;
}
s[0]=1;
for(i=1;i<M.arcnum;i++)
{
int temp=INFINITY;
int u=0;
for(j=0;j<M.arcnum;j++)
if(!s[j]&&dist[j]<temp)
{
u=j;
temp=dist[j];
}
s[u]=1;
if(temp<INFINITY)
{
sum+=temp;
if(!u)
cout<<"("<<"0"<<","<<u<<")"<<temp<<" ";
else
{ for(pp=0;pp<M.arcnum;pp++)
if(s[pp]&&M.arcs[pp][u]==temp)
cout<<"("<<pp<<","<<u<<")"<<temp<<" ";
}
}
else
{
cout<<"最小生成树,失败!!!";
break;
}
for(j=0;j<M.arcnum;j++)
if(!s[j]&& M.arcs[u][j]<INFINITY)
{
newdist=M.arcs[u][j];
if(newdist<dist[j])
{
dist[j]=newdist;
}
}
}
if(sum<INFINITY)
cout<<"\n"<<"最小生成树的权值和为:"<<sum<<endl;
}
void CreateJZGraph()
{
int i,j,a,b,w;
int visit[MAX][MAX];
for(i=0;i<M.arcnum;i++)
for(j=0;j<M.arcnum;j++)
{
M.arcs[i][j]=INFINITY;
visit[i][j]=0;
}
if(M.kind==0)//有向图
{
cout<<"请输入顶点和权值:"<<endl;
for(i=0;i<M.vexnum;i++)
{
scanf("%d%d%d",&a,&b,&w);
M.arcs[a][b]=w;
}
int m,n;
cout<<"计算任意两点的距离,请输入始末点,以起点为-1为结束标志:"<<endl;
while(scanf("%d",&m))
{
if(m<0) break;
cin>>n;
MinRode(m,n);
cout<<"计算任意两点的距离,请输入始末点,以起点为-1为结束标志:"<<endl;
}
}
else//无向图
{
//cout<<"最小生成树为:";
cout<<"请输入顶点和权值:"<<endl;
for(i=0;i<M.vexnum;i++)//读入数据
{
scanf("%d%d%d",&a,&b,&w);
M.arcs[a][b]=w;
M.arcs[b][a]=w;
}
MinTree();
}
}
//
int main()
{
int count;
cout<<"存储方式:用邻接表存储请输入0,用邻接矩阵存储请输入1,请选择:";
scanf("%d",&count);
switch(count)
{
case 0:
{
cout<<"用邻接表存储:有向图请输入0,无向图请输入1,请选择:";
scanf("%d",&Graph);
int g1;
if(Graph==0)//有向图
{
DaYin1();
while(scanf("%d",&g1))
{
if(g1==-1)break;
switch(g1)
{
case 0:CreateGraph();break;
case 1:print();break;
case 2:GraphDu();break;
case 3:TuoPuSort();break;
//cout<<"图的深度遍历:";
}
DaYin1();
}
}
else//无向图
{
DaYin2();
while(scanf("%d",&g1))
{
if(g1==-1)break;
switch(g1)
{
case 0:CreateGraph();break;
case 1:print();break;
case 2:GraphDu();break;
case 3:DFSTraverse();break;
case 4:BFSTraverse();break;
}
DaYin2();
}
}
}break;
case 1: //邻接矩阵
{
JZGraph();
CreateJZGraph();//最小生成树he最短路径
}
}
return 0;
}
/*
0 1 6
0 2 1
0 3 5
1 2 5
2 3 5
1 4 3
2 4 6
2 5 4
3 5 2
4 5 6
*/
/*
0 1 1
1 2 2
0 3 3
0 4 5
3 2 2
2 4 3
4 0 4
*/
(7)采用邻接矩阵存储实现无向图的最小生成树的PRIM算法。
(8)采用邻接矩阵存储一个有向图,输出单源点到其它顶点的最短路径。
(9)在主函数中设计一个简单的菜单,分别调试上述算法。