图的定义:
这里面的术语很多:
具体的定义请参考这篇文章:
https://segmentfault.com/a/1190000013223267
图的存储结构
邻接矩阵
图的邻接矩阵存储结构代码:
typedef char VertexType; //结点类型
typedef int EdgeType; //边上的权值类型
#define MAXVEX 100 //最大顶点数
#define INFINITY 65535 //用65535来代替无穷大
typedef struct
{
VertexType vexs[MAXVEX]; //顶点表
EdgeType arc[MAXVEX][MAXVEX]; //邻接矩阵,可看作表
int numVertexes,numEdges; //图中当前的顶点数和边数
}MGraph;
无向网图的邻接矩阵表示代码
void CreateMGraph(MGraph *G)
{
int row,col,value;
std::cout<<"请输入顶点数和边数"<<std::endl;
std::cin>>G->numVertexes>>G->numEdges;
std::cout<<"读入顶点信息,建立顶点表"<<std::endl;
for(int i=0;i<G->numVertexes;i++) //读入顶点信息,建立顶点表
{
std::cin>>G->vexs[i];
}
//邻接矩阵初始化
for(int i=0;i<G->numVertexes;i++)
{
for(int j=0;j<G->numVertexes;j++)
{
G->arc[i][j]=INFINITY;
}
}
for(int k=0;k<G->numEdges;k++)
{
std::cout<<"输入边(Vi,Vj)上的下标i,下标j和权w:"<<std::endl;
std::cin>>row>>col>>value;
G->arc[row][col]=value;
G->arc[col][row]=G->arc[row][col]; //因为是无向图,所以矩阵对称
}
}
从代码可以看出,对于n个顶点和e条边的无向网图创建,时间复杂度为O(n+n2+e),其中对邻接矩阵的初始化耗费了O(n2)的时间。
邻接表
邻接矩阵是一种不错的图存储结构,但是我们也发现,对于边数相对顶点较少的图,这种结构是存在对存储空间的极大浪费。
我们把数组与链表相结合的存储方法称为邻接表(Adjacency List)
邻接表结构代码
typedef char VertexType; //结点类型
typedef int EdgeType; //边上的权值类型
typedef struct EdgeNode //边表节点
{
int adjvex; //邻接点域,存储该顶点对应的下标
EdgeType weight; //用于存储权值,对于非网图可以不需要
struct EdgeNode *next; //链域,指向下一个邻接点
}EdgeNode;
typedef struct VertexNode //顶点表结点
{
VertexType data; //顶点域,存储顶点信息
EdgeNode *firstedge; //边表头指针
}VertexNode,AdjList[MAXVEX];
typedef struct
{
AdjList adjList;
int numVertexes,numEdges; //图中当前的顶点数和边数
}GraphAdjList;
邻接表的创建代码
void CreateALGraph(GraphAdjList *G)
{
int row,col;
EdgeNode *e;
std::cout<<"输入顶点数和边数"<<std::endl;
std::cin>>G->numVertexes>>G->numEdges;
//读入顶点信息,建立顶点表
for(int i=0;i<G->numVertexes;i++)
{
std::cin>>G->adjList[i].data; //输入顶点信息
G->adjList[i].firstedge=nullptr; //将边表置为空表
}
//建立边表
for(int i=0;i<G->numEdges;i++)
{
std::cout<<"输入边(Vi,Vj)上的顶点序号:"<<std::endl;
std::cin>>row>>col;
e=(EdgeNode *)malloc(sizeof (EdgeNode));
e->adjvex=col;
e->next=G->adjList[row].firstedge;
G->adjList[row].firstedge=e;
e=(EdgeNode *)malloc(sizeof (EdgeNode));
e->adjvex=row;
e->next=G->adjList[col].firstedge;
G->adjList[col].firstedge=e;
}
}
十字链表
邻接多重表
具体参考这篇文章
https://segmentfault.com/a/1190000015188957
图的遍历
深度优先遍历
邻接矩阵形式的深度优先遍历
typedef int Boolean;
Boolean visited[MAXSIZE]; //访问标志的数组
/*邻接矩阵的深度优先递归算法*/
void DFS(MGraph G,int i)
{
int j;
visited[i]=True;
std::cout<<G.vexs[i]<<std::endl;
for(j=0;j<G.numVertexes;j++)
{
if(G.arc[i][j]==1&&!visited[j])
{
DFS(G,j);
}
}
}
/*邻接矩阵的深度遍历操作*/
void DFSTraverse(MGraph G)
{
int i;
for(i=0;i<G.numVertexes;i++)
{
visited[i]=False; //初始化所有顶点状态都是未访问过的顶点
}
for(i=0;i<G.numVertexes;i++)
{
if(!visited[i]) //对未访问的顶点调用DFS,若是连通图,只会执行一次
DFS(G,i);
}
}
邻接表的深度优先遍历
/*邻接表的深度优先递归算法*/
void DFS(GraphAdjList GL,int i)
{
EdgeNode *p;
visited[i]=True;
std::cout<<GL.adjList[i].data<<std::endl; //打印顶点,也可以是其他操作
p=GL.adjList[i].firstedge;
while (p)
{
if(!visited[p->adjvex])
{
DFS(GL,p->adjvex); //对未访问的邻接顶点递归调用
}
p=p->next;
}
}
/*邻接表的深度遍历操作*/
void DFSTraverse(GraphAdjList GL)
{
int i;
for(i=0;i<GL.numVertexes;i++)
{
visited[i]=False; //初始化所有顶点状态都是未访问的状态
}
for(i=0;i<GL.numVertexes;i++)
{
if(!visited[i]) //对未访问的顶点调用DFS,若是连通图,只会执行一次
DFS(GL,i);
}
}
邻接矩阵的时间复杂度O(N2)
邻接表的时间复杂度O(N+e)