/*图的存储及遍历*/
#include<iostream>
using namespace std;
//-----------------------------------
//邻接矩阵的存储及深度和广度遍历
//-----------------------------------
/*邻接矩阵的类型定义*/
#define MAX 10000000
#define MAX_VERTEX_NUM 20
typedef enum{ DG,DN,UDG,UDN }GraphKind;//有向图,有向网,无向图,无向网
typedef struct
{
char vexs[MAX_VERTEX_NUM];//用一维数组存储顶点信息
int edges[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//用二维数组充当矩阵,来存储顶点边的信息
int vexnum,edgenum;//顶点树和边数
GraphKind kind;//图的种类
}MGraph;
/*构造无向图的邻接矩阵*/
void CreateUDG_AM(MGraph &G,int n,int e)
{
G.vexnum=n;
G.edgenum=e;
int i,j,k;
for(i=0;i<n;i++)
cin>>G.vexs[i];//输入顶点信息
for(i=0;i<n;i++)
for(j=0;j<n;j++)
G.edges[i][j]=0;//将矩阵初始化为0
for(k=0;k<e;k++)
{
cin>>i>>j;//这里只用输入对称的边就行,也就是输入下矩阵或是上矩阵
G.edges[i][j]=G.edges[j][i]=1;//输入边的信息
}
}
/****************************无向图的深度优先遍历************************/
int visited[MAX_VERTEX_NUM];
void DF_AM(MGraph &G,int i)
{
int j;
cout<<G.vexs[i]<<" ";
visited[i]=1;
for(j=0;j<G.vexnum;j++)
{
if((G.edges[i][j])==1&&(visited[j])==0)
DF_AM(G,j);
}
}
void DF_Traverse_AM(MGraph &G)
{
int i;
for(i=0;i<G.vexnum;i++)
{
visited[i]=0;
}
for(i=0;i<G.vexnum;i++)
{
if(!visited[i])
DF_AM(G,i);
}
}
/*********************无向图的广度优先遍历*****************************/
//循环队列的类型定义
const int Queue_Size=100;
typedef struct circlQueue
{
int *elem;
int rear;
int front;
int queueSize;
}circlQueue;
//初始化
void initQueue_C(circlQueue &Q)
{
Q.elem=new int[Queue_Size];
Q.front=Q.rear=0;//首尾指针相等说明队列为空。
Q.queueSize=Queue_Size;
}
//入队列
void enterQueue_C(circlQueue &Q,int x)
{
if(((Q.rear+1)%Q.queueSize)==Q.front)//判断栈满的情况
cout<<"Queue OverFlow!";
Q.elem[Q.rear]=x;
Q.rear=(Q.rear+1)%Queue_Size;//尾指针应以此种方式加1,才会实现循环队列。
}
//出队列
char outputQueue_C(circlQueue &Q)
{
int e;
if(Q.rear==Q.front)
cout<<"Queue Empty";
e=Q.elem[Q.front];
Q.front=(Q.front+1)%Q.queueSize;;//头指针应以此种方式加1,才会实现循环队列。
return e;
}
//广度遍历
void BF_Traverse_AM(MGraph &G)
{
int i,j,v;
for(i=0;i<G.vexnum;i++)
visited[i]=0;
circlQueue Q;
initQueue_C(Q);//队列实现了“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问
for(i=0;i<G.vexnum;i++)
{
if(!visited[i])
{
cout<<G.vexs[i]<<" ";
visited[i]=1;
enterQueue_C(Q,i);
while(Q.front!=Q.rear)
{//这个循环是将队列里面的顶点取出来,然后进行下面的for循环
v=outputQueue_C(Q);
for(j=0;j<G.vexnum;j++)
{//这个循环是将顶点的全部邻接点依次访问并且入队列
if(G.edges[v][j]&&(!visited[j]))
{
cout<<G.vexs[j]<<" ";
visited[j]=1;
enterQueue_C(Q,j);
}
}
}
}
}
}
//-----------------------------------------------
//邻接表的存储及深度和广度遍历
//-----------------------------------------------
typedef struct EdgeNode
{//边表结点的定义
int adjvex;//存放邻接点在顶点表中的位置
struct EdgeNode * nextedge;//指向下一个边表结点
int weight;
}EdgeNode;
typedef struct VexNode
{//顶点表结点的定义
char vex;//存放顶点信息
EdgeNode * firstedge;//指向第一个边表结点
}VexNode;
typedef struct
{//顶点表的定义
VexNode vexs[MAX_VERTEX_NUM];
int vexnum,edgenum;
GraphKind kind;
}LGraph;
/*构造有向图的邻接表*/
void CreateDG_AL(LGraph &G,int n,int e)
{
int i,j,k;
G.vexnum=n;
G.edgenum=e;
G.kind=DG;
for(i=0;i<n;i++)
{
cin>>G.vexs[i].vex;
G.vexs[i].firstedge=NULL;//初始化为空
}
for(k=0;k<e;k++)
{
EdgeNode *p;
cin>>i>>j;
p=new EdgeNode;
p->adjvex=j;
p->nextedge=G.vexs[i].firstedge;
G.vexs[i].firstedge=p;//采用头插法
}
}
/*********************有向图的深度优先遍历**************************/
void DF_AL(LGraph &G,int v)
{
int j;
EdgeNode *p;
cout<<G.vexs[v].vex<<" ";
visited[v]=1;
for(p=G.vexs[v].firstedge;p;p=p->nextedge)
{
j=p->adjvex;
if(!visited[j])
DF_AL(G,j);
}
}
void DF_Traverse_AL(LGraph &G)
{
int i;
for(i=0;i<G.vexnum;i++)
{
visited[i]=0;
}
for(i=0;i<G.vexnum;i++)
{
if(!visited[i])
DF_AL(G,i);
}
} /* 何问起 hovertree.com */
/*********************有向图的广度优先遍历**************************/
void BF_Traverse_AL(LGraph &G)
{
int i,j,v;
EdgeNode *p;
for(i=0;i<G.vexnum;i++)
visited[i]=0;
circlQueue Q;
initQueue_C(Q);//队列实现了“先被访问的顶点的邻接点”先于“后被访问的顶点的邻接点”被访问
for(i=0;i<G.vexnum;i++)
{
if(!visited[i])
{
cout<<G.vexs[i].vex<<" ";
visited[i]=1;
enterQueue_C(Q,i);
while(Q.front!=Q.rear)
{//这个循环是将队列里面的顶点取出来,然后进行下面的for循环
v=outputQueue_C(Q);
for(p=G.vexs[v].firstedge;p;p=p->nextedge)
{//这个循环是将顶点的全部邻接点依次访问并且入队列
j=p->adjvex;
if(!visited[j])
{
cout<<G.vexs[j].vex<<" ";
visited[j]=1;
enterQueue_C(Q,j);
}
}
}
}
}
}
void main()
{
/*MGraph G;
CreateUDG_AM(G,6,6);
DF_Traverse_AM(G);
cout<<endl;
BF_Traverse_AM(G);*/
LGraph G;
CreateDG_AL(G,5,7);
DF_Traverse_AL(G);
cout<<endl;
BF_Traverse_AL(G);
}
/* Prim算法生成最小生成树 */ void MiniSpanTree_Prim(MGraph G) { cout<<"Prim算法生成最小生成树,结果为:"<<endl; int min,i,j,k; int adjvex[MAXVEX]; int lowcost[MAXVEX]; lowcost[0]=0; adjvex[0]=0; for(i=1;i<G.numVertexes;i++) { lowcost[i]=G.arc[0][i]; adjvex[i]=0; } for(i=1;i<G.numVertexes;i++) { min=INFINITY; j=1;k=0; while(j<G.numVertexes) { if(lowcost[j]!=0 && lowcost[j]<min) { min=lowcost[j]; k=j; } j++; } cout<<"("<<adjvex[k]<<","<<k<<")"<<endl; lowcost[k]=0; for(j=1;j<G.numVertexes;j++) { if(lowcost[j]!=0 && G.arc[k][j]<lowcost[j]) { lowcost[j]=G.arc[k][j]; adjvex[j]=k; } } } cout<<endl; } /* Kruskal 算法生成最小生成树 */ class Edge{ /*对边集数组Edge结构的定义*/ public: int begin; int end; int weight; }; void Swap(Edge *edges,int i,int j) /* 交换权值 以及头和尾 */ { int temp; temp=edges[i].begin; edges[i].begin=edges[j].begin; edges[j].begin=temp; temp=edges[i].end; edges[i].end=edges[j].end; edges[j].end=temp; temp=edges[i].weight; edges[i].weight=edges[j].weight; edges[j].weight=temp; } void sort(Edge edges[],MGraph *G) /* 对权值进行排序 */ { int i,j; for ( i=0;i<G->numEdges;i++) { for ( j=i+1;j<G->numEdges;j++) { if (edges[i].weight>edges[j].weight) { Swap(edges,i,j); } } } cout<<"权排序之后的为:"<<endl; for (i=0;i<G->numEdges;i++) { cout<<"("<<edges[i].begin<<","<<edges[i].end<<")"<<endl; } } int Find(int *parent,int f) /*查找连线顶点的尾部下标*/ { while (parent[f]>0) f=parent[f]; return f; } void MiniSpanTree_Kruskal(MGraph G) { int i,j,n,m; Edge edges[MAXEDGE]; int parent[MAXVEX]; /*将邻接数组G转化为边集数组edges并按权由小到大排序*******BEGIN*********/ int k=0; for ( i=0;i<G.numVertexes-1;i++) { for (j=i+1;j<G.numVertexes;j++) { if (G.arc[i][j]<INFINITY) { edges[k].begin=i; edges[k].end =j; edges[k].weight=G.arc[i][j]; k++; } } } sort(edges, &G); /***************END***********************/ for (i=0;i<G.numVertexes;i++) parent[i]=0; /* 初始化数组值为0 */ cout<<"Kruskal 算法生成最小生成树,结果为:"<<endl; for (i=0;i<G.numEdges;i++) /* 循环每一条边 */ { n=Find(parent,edges[i].begin); m=Find(parent,edges[i].end); if (n!=m) /* 假如n与m不等,说明此边没有与现有的生成树形成环路 */ { parent[n]=m; /* 将此边的结尾顶点放入下标为起点的parent中。 */ /* 表示此顶点已经在生成树集合中 */ cout<<"("<<edges[i].begin<<","<<edges[i].end<<") "<<edges[i].weight<<endl; } } }
对于如下所示的图:
运行程序,结果如下: