⛓️ 基于邻接表的图的算法
邻接表定义
#define MAX_VERTERX_NUM 100
typedef char VertexType;
typedef struct ArcNode {
int adjvex;
struct ArcNode *nextarc;
} ArcNode;
typedef struct VNode{
VertexType data;
ArcNode *firstarc;
} VNode, AdjList[MAX_VERTERX_NUM];
typedef struct {
AdjList vertices;
int vexnum, arcnum;
} ALGraph;
建立有向表
void createALGraph(ALGraph &G) {
ArcNode *p;
cout<<"请输入顶点数和边数"<<endl;
cin>>G->vexnum>>G->arcnum; //输入顶点数和边数
cout<<"请输入顶点"<<endl;
for(int i=0; i<G->vexnum; i++) {
cin>>G->vertices[i].data; //输入顶点信息
G->vertices[i].firstarc = NULL;
}
cout<<"请输入边(vi,vj)的顶点的下标"<<endl;
for(int k=0; k<G->arcnum; k++) {
cin>>i>>j; //输入顶点序列(即建边)
p = new ArcNode;
p->adjvex = j;
p->nextarc = G->vertices[i].firstarc;
G->vertices[i].firstarc = p;
//若是无向图,再建一条(j,i)边即可
}
}
删除有向图的一条弧,传参为<i,j>
void removeArc(ALGraph &G, int i, int j) {
if(i<0||j<0)
return;
ArcNode *pre = NULL;
ArcNode *p = G->vertices[i].firstarc;
while(p) {
if(p->adjvex==j) {
if(pre==NULL)
G->vertices[i].firstarc = p->nextarc;
else
pre->nextarc = p->nextarc;
delete p; //释放边结点
}
else {
pre = p;
p = p->nextarc;
}
}
G->arcnum--;
}
删除有向图的一条弧,传参为<v1,v2>
int Locate_Vex(ALGraph G, char ch) {
for (int i=0; i<G.vexnum; i++) {
if(G.vertices[i].data==ch)
return i;
}
return -1;
}
void removeArc(ALGraph &G, char v1, char v2) {
ArcNode *pre = NULL;
ArcNode *p = G->vertices[i].firstarc;
int i = Locate_Vex(G, v1);
int j = Locate_Vex(G, v2);
if(i<0||j<0)
return;
while(p) {
if(p->adjvex==j) {
if(pre==NULL)
G->vertices[i].firstarc = p->nextarc;
else
pre->nextarc = p->nextarc;
delete p; //释放边结点
}
else {
pre = p;
p = p->nextarc;
}
}
G->arcnum--;
}
求某顶点的入度
int countIndegree(ALGraph G, int k) {
int cnt = 0;
ArcNode *p;
for (int i = 0; i < G.vexnum; ++i) {
for(p=G.vertices[i].firstarc; p; p=p->nextarc) {
if(p->adjvex==k) //遍历整个边表
cnt++;
}
}
return cnt;
}
求某顶点的出度
int countOutdegree(ALGraph G, int k) {
int cnt = 0;
ArcNode *p = G.vertices[k].firstarc;
while(p) {
cnt++; //边表结点个数即为出度
p = p->nextarc;
}
return cnt;
}
基于邻接表的深度优先搜索
bool visited[MAX_VERTERX_NUM]; //访问标记
void DFS(ALGraph G, int v) {
ArcNode *p; //声明一个指向边结点的工作指针
visit(v); //根据题目描述修改函数即可
visited[v] = TRUE; //访问标记置为TRUE
for(p=G.vertices[i].firstarc; p; p=p->nextarc) {
if(!visited[p->adjvex])//若顶点未被访问过
DFS(G,p->adjvex); //递归调用
}
}
/*当图不是连通图时需要调用本函数*/
void DFSTraverse(ALGraph G) {
for (int i = 0; i < G.vexnum; ++i)
visited[i] = FALSE; //初始化标记数组
for (int i = 0; i < G.vexnum; ++i) {
/*针对非连通图,这样就实现了遍历下一个连通分量的遍历*/
if(!visited[i]) //顶点未被访问
DFS(G,i);
}
}
基于邻接表的广度优先搜索
bool visited[MAX_VERTERX_NUM]; //访问标记
void BFS(ALGraph G, int v) {
InitQueue(Q); //初始化一个队列,王道上是在Traverse函数里初始化的,可我觉得这里更合适
ArcNode *p; //声明一个指向边结点的工作指针
visit(v); //根据题目描述修改函数即可
visited[v] = TRUE; //访问标记设为TRUE
EnQueue(Q,v); //将访问顶点入队
while(!IsEmpty(Q)) {
DeQueue(Q,i); //取队头元素
for(p=G.vertices[i].firstarc; p; p=p->nextarc){
if(!visited[p->adjvex]) {
visit(p->adjvex); //根据题目描述修改函数即可
visited[p->adjvex] = TRUE; //访问标记设为TRUE
EnQueue(Q,p->adjvex);
}
}
}
}
/*当图不是连通图时需要调用本函数*/
void BFSTraverse(ALGraph G) {
for (int i = 0; i < G.vexnum; ++i)
visited[i] = FALSE; //初始化标记数组
for (int i = 0; i < G.vexnum; ++i) {
/*针对非连通图,这样就实现了遍历下一个连通分量的遍历*/
if(!visited[i]) //顶点未被访问
BFS(G,i);
}
}
基于邻接表的拓扑排序
//存放顶点入度信息的数组(假设题目已给出,一般都给出不然手撸代码工作量太大了)
int indegree[MAX_VERTERX_NUM];
bool TopoSort(ALGraph G) {
InitStack(S); //初始化一个栈
ArcNode *p; //声明一个指向边结点的工作指针
for(int i=0; i<G.vexnum; i++) {
if(indegree[i]==0)
Push(S,i); //将入度为0的顶点入栈
}
int cnt = 0; //计数,记录当前输出的顶点数
while(!IsEmpty(S)) { //栈不空,则存在入度为0的顶点
Pop(S,i); //取栈顶元素
cout<<G.vertices[i].data;//输出序号为i的顶点
cnt++; //计数
for(p=G.vertices[i].firstarc; p; p=p->nextarc) {
/*将所有i指向的顶点入度减1,并且将入度减为0的顶点压入栈S*/
int v = p->adjvex;
if(!(--indegree[v]))
Push(S,v);
}
}
if(cnt<G.vexnum)
return FALSE; //得到的拓扑序列顶点个数小于图的顶点个数,说明图中存在回路
else
return TRUE;
}
- 版权声明:本文采用知识共享 3.0 许可证 (保持署名-自由转载-非商用-非衍生)
- 发表于 2021-07-02