/*圖的鄰接矩陣和鄰接表的轉換,圖的遍歷,最小生成樹等*/
#include "stdio.h"
#include "malloc.h"
#define INF 32767 //表示正無窮
#define MAXV 100 //最大頂點個數
int visited[MAXV]; //全局數組
//定義鄰接矩陣類型
typedef int InfoType;
typedef struct {
int NO; //頂點編號
InfoType info; //頂點的其他信息
}VertexType; //頂點類型
typedef struct {
int edges[MAXV][MAXV]; //鄰接矩陣
int n,e; //頂點數、邊數
VertexType Vexs[MAXV]; //存放頂點信息
}MGraph; //圖的鄰接矩陣類型
//定義鄰接表類型
typedef struct ANode { //邊的節點結構類型
int adjvex; //該邊的終點位置
struct ANode *nextarc; //指向下一條邊的指針
InfoType info; //該邊的相關信息,這里用於存放權值
}ArcNode;
typedef int Vertex;
typedef struct VNode { //鄰接表頭節點的類型
Vertex data; //頂點信息
ArcNode *firstarc; //指向第一條邊
}VNode;
typedef VNode Adjlist[MAXV];//Adjlist是鄰接表類型
typedef struct {
Adjlist adjlist; //鄰接表
int n,e; //圖中頂點數n和邊數e
}ALGraph; //圖的鄰接表類型
//不帶權值的圖
void MarToList(MGraph g,ALGraph *&G) //將鄰接矩陣g轉化為鄰接表G
{
int i,j;
ArcNode *p;
G=(ALGraph *)malloc(sizeof(ALGraph));
for(i=0;i<g.n ;i++) //給鄰接表中所有頭節點的指針域賦初值
G->adjlist [i].firstarc =NULL;
for(i=0;i<g.n ;i++)
for(j=g.n -1;j>=0;j--)
if(g.edges [i][j]!=0) //鄰接矩陣當前元素不為0
{
p=(ArcNode *)malloc(sizeof(ArcNode));//創建一個節點*p
p->adjvex =j;
p->nextarc =G->adjlist [i].firstarc ;//將*p鏈到鏈表后
G->adjlist [i].firstarc =p;
}
G->n =g.n ;
G->e =g.e ;
}
void LisrToMat(ALGraph *G,MGraph &g) //將鄰接表G轉換成鄰接矩陣g
{
int i,j;
ArcNode *p;
for(i=0;i<G->n ;i++) //g.edges[i][j]賦初值0
for(j=0;j<G->n ;j++)
g.edges [i][j]=0;
for(i=0;i<G->n ;i++)
{
p=G->adjlist[i].firstarc ;
while(p!=NULL)
{
g.edges [i][p->adjvex ]=1;
p=p->nextarc ;
}
}
g.n =G->n ;
g.e =G->e ;
}
void DispMat(MGraph g) //輸出鄰接矩陣g
{
int i,j;
for(i=0;i<g.n ;i++)
{
for(j=0;j<g.n ;j++)
printf("%3d",g.edges [i][j]);
printf("\n");
}
}
void DispAdj(ALGraph *G)
{
int i;
ArcNode *p;
for(i=0;i<G->n ;i++)
{
p=G->adjlist [i].firstarc ;
printf("%3d:",i);
while(p!=NULL)
{
printf("%3d",p->adjvex ) ;
p=p->nextarc;
}
printf("\n");
}
}
//帶權值的圖
void MatToList1(MGraph g,ALGraph *&G)
{
int i,j;
ArcNode *p;
G=(ALGraph *)malloc(sizeof(ALGraph));
for(i=0;i<g.n ;i++)
G->adjlist[i].firstarc =NULL;
for(i=0;i<g.n ;i++)
for(j=g.n -1;j>=0;j--)
if(g.edges [i][j]!=0&&g.edges [i][j]!=INF)
{
p=(ArcNode *)malloc(sizeof(ArcNode));//創建一個節點*p
p->adjvex =j;
p->info =g.edges [i][j];
p->nextarc =G->adjlist [i].firstarc ;//將*p鏈到鏈表后
G->adjlist [i].firstarc =p;
}
G->n =g.n ;
G->e =g.e ;
}
void ListToMat1(ALGraph *G,MGraph &g)
{
int i,j;
ArcNode *p;
for(i=0;i<G->n ;i++) //g.edges[i][j]賦初值0
for(j=0;j<G->n ;j++)
if(i==j)
g.edges [i][j]=0;
else g.edges [i][j]=INF;
for(i=0;i<G->n ;i++)
{
p=G->adjlist[i].firstarc ;
while(p!=NULL)
{
g.edges [i][p->adjvex ]=p->info ;
p=p->nextarc ;
}
}
g.n =G->n ;
g.e =G->e ;
}
void DispMat1(MGraph g) //輸出鄰接矩陣g
{
int i,j;
for(i=0;i<g.n ;i++)
{
for(j=0;j<g.n ;j++)
if(g.edges [i][j]==INF)
printf(" %3s","∞");
else
printf(" %3d",g.edges [i][j]);
printf("\n");
}
}
void DispAdj1(ALGraph *G)
{
int i;
ArcNode *p;
for(i=0;i<G->n ;i++)
{
p=G->adjlist [i].firstarc ;
printf("%3d:",i);
while(p!=NULL)
{
printf("%3d(%d)",p->adjvex,p->info ) ;
p=p->nextarc;
}
printf("\n");
}
}
//非遞歸深度優先遍歷
void DFS(ALGraph *G,int v)
{
ArcNode *p;
ArcNode *St[MAXV];
int top =-1,w,i;
for(i=0;i<G->n ;i++)
visited[i]=0; //頂點訪問標志賦值為0
printf("%3d",v); //訪問頂點
visited[v]=1; //標記訪問過的頂點
top++;
St[top]=G->adjlist [v].firstarc ;
while(top>-1)
{
p=St[top];
top--;
while(p!=NULL)
{
w=p->adjvex ;
if(visited[w]==0)
{
printf("%3d",w);
visited[w]=1;
top++; //將頂點w的第一個頂點進棧
St[top]=G->adjlist [w].firstarc ;
break;
}
p=p->nextarc ;
}
}
printf("\n");
}
//深度優先遍歷
void DFS1(ALGraph *G,int v)
{
ArcNode *p;
visited[v]=1;
printf("%3d",v);
p=G->adjlist [v].firstarc ; //p指向頂點v的第一條邊的邊頭節點
while(p!=NULL)
{
if(visited[p->adjvex] ==0) //p->adjvex頂點未訪問,遞歸訪問他
DFS1(G,p->adjvex );
p=p->nextarc ; //指向下一條邊的邊頭節點
}
}
//廣度優先遍歷
void BFS(ALGraph *G,int v)
{
ArcNode *p;
int queue[MAXV],front=0,rear=0; //定義循環隊列,並初始化
int visited[MAXV]; //定義存放頂點的訪問標志的數組
int w,i;
for(i=0;i<G->n ;i++)
visited[i]=0; //初始化標志數組
printf("%3d",v);
visited[v]=1;
rear=(rear+1)%MAXV; //也可以不用循環隊列的,一般都不會溢出
queue[rear]=v; //v進隊
while (front!=rear) //隊列不空
{
front=(front+1)%MAXV;
w=queue[front]; //出隊,並賦給w
p=G->adjlist [w].firstarc ; //找與頂點W鄰接的第一個頂點
while(p!=NULL)
{
if(visited[p->adjvex ]==0)//當前訪問的頂點沒有訪問過
{
printf("%3d",p->adjvex );
visited[p->adjvex ]=1;
rear=(rear+1)%MAXV;
queue[rear]=p->adjvex ;
}
p=p->nextarc ; //找下一個鄰接頂點
}
}
printf("\n\n");
}
//利用普里姆算法求最小生成樹
void Prim(MGraph g,int v)
{
int lowcost[MAXV],min,n=g.n ;
int closest[MAXV],i,j,k;
for(i=0;i<n;i++)
{
lowcost[i]= (g.edges[v][i]==0?INF:g.edges[v][i]);
closest[i]=0;
}
for(i=1;i<n;i++)
{
min=INF;
for(j=0;j<n;j++)
if(lowcost[j]!=0 && lowcost[j]<min)
{
min=lowcost[j];
k=j;
}
printf(" 邊(%d,%d)權為:%d\n",closest[k],k,min);
lowcost[k]=0;
for(j=0;j<n;j++)
if(g.edges [k][j]!=0 && g.edges [k][j]<lowcost[j])
{
lowcost[j]=g.edges [k][j];
closest[j]=k;
}
}
}
void main()
{
int i,j;
MGraph g,g1;
ALGraph *G;
int A[8][8]={
{0,4,3,0,0,0,0,0},
{4,0,5,5,9,0,0,0},
{3,5,0,5,0,0,0,5},
{0,5,5,0,7,6,5,4},
{0,9,0,7,0,3,0,0},
{0,0,0,6,3,0,2,0},
{0,0,0,5,0,2,0,6},
{0,0,5,4,0,0,6,0}};
g.n =8;g.e =14;
for(i=0;i<g.n ;i++)
for(j=0;j<g.n ;j++)
g.edges [i][j]=A[i][j];
G=(ALGraph *)malloc(sizeof(ALGraph));
printf("圖的鄰接矩陣為:\n");
DispMat(g) ;
printf("\n無向圖的鄰接矩陣轉換成鄰接表:\n");
MarToList(g,G);
DispAdj(G);
printf("\n帶權無向圖的鄰接矩陣轉換成鄰接表:\n");
MatToList1(g,G);
DispAdj1(G);
printf("\n無向圖的鄰接表換成鄰接矩陣:\n");
LisrToMat(G,g1);
DispMat(g1);
printf("\n帶權無向圖的鄰接表換成鄰接矩陣:\n");
ListToMat1( G, g1);
DispMat1(g1);
printf("\n從頂點0開始的深度優先遍歷(非遞歸):");
DFS(G,0);
for(i=0;i<G->n ;i++)
visited[i]=0;
printf("\n從頂點0開始的深度優先遍歷(遞歸):");
DFS1(G,0);
printf("\n\n從頂點0開始的廣度優先遍歷:");
BFS(G,0);
printf("普里姆算法求解結果:\n");
Prim( g,0);}