文章目录
一、图的存储结构
1. 邻接表
// 边表
typedef struct ArcNode{
int adjvex; // 邻接点下标
int info; // 边权
struct ArcNode* nextarc; // 邻接边
}ArcNode;
// 顶点表
typedef struct VNode{
char data;
ArcNode* firstarc;
}VNode;
// 邻接表
typedef struct{
VNode adjlist[MaxSize];
int edgenum, vexnum;
}AGraph;
2. 邻接矩阵
typedef struct{
int no; // 顶点编号,也可以是char
char info; // 顶点的其他信息,不做特殊要求可以不写
}VexType;
typedef struct
{
VexType vex[MaxSize];
int edges[MaxSize][MaxSize];
int edgenum, vexnum;
}MGraph;
二、图的深度优先遍历(DFS)
1. 邻接表
(1) DFS递归方式
bool visited[MaxSize];
void DfsTraverse(AGraph* G) // 用的指针
{
memset(visited, false, sizeof visited);
for (int i = 0; i < G->vexnum; i ++)
if (!visited[i]) dfs(G, i);
}
// 图的dfs类似树的preorder
void dfs(AGraph* G, int u)
{
visited[u] = true;
visit(u);
auto p = G->adjlist[u].firstarc;
while (p)
{
auto v = p->adjvex;
if (!visited[v]) dfs(G, v);
p = p->nextarc;
}
}
(2) DFS非递归方式
bool visited[MaxSize];
void DfsTraverse(AGraph* G) // 用的指针
{
memset(visited, false, sizeof visited);
for (int i = 0; i < G->vexnum; i ++)
if (!visited[i]) dfs(G, i);
}
// 图的dfs类似树的preorder
void dfs(AGraph* G, int u)
{
stack<int> s;
s.push(u);
visited[u] = true;
while (s.size())
{
auto t = s.top();
s.pop();
visit(t);
auto p = G->adjlist[t].firstarc;
while (p)
{
auto v = p->adjvex;
if (!visited[v])
{
s.push(v);
visited[v] = true;
}
p = p->nextarc;
}
}
}
2. 邻接矩阵
bool visited[MaxSize];
void DfsTraverse(MGraph G) // 没用指针
{
memset(visited, false, sizeof visited);
for (int i = 0; i < G.vexnum; i ++)
if (!visited[i]) dfs(G, i);
}
void dfs(MGraph G, int u)
{
visited[u] = true;
visit(u);
for (int i = 0; i < G.vexnum; i ++)
if (!visited[i] && G.edges[u][i] != 0) dfs(G, i);
}
三、图的广度优先遍历(BFS)
1. 邻接表
bool visited[MaxSize];
void BfsTraverse(AGraph* G) // 用的指针
{
memset(visited, false, sizeof visited);
for (int i = 0; i < G->vexnum; i ++)
if (!visited[i]) bfs(G, i);
}
void bfs(AGraph* G, int u)
{
queue<int> q;
q.push(u);
visited[u] = true;
visit(u);
while (q.size())
{
auto t = q.front();
q.pop();
auto p = G->adjlist[t].firstarc;
while (p)
{
auto v= p->adjvex;
if (!visited[v])
{
q.push(v);
visited[v] = true;
visit(v);
}
p = p=>nextarc;
}
}
}
2. 邻接矩阵
bool visited[MaxSize];
void BfsTraverse(MGraph G) // 没用指针
{
memset(visited, false, sizeof visited);
for (int i = 0; i < G.vexnum; i ++)
if (!visited[i]) bfs(G, i);
}
void bfs(MGraph G, int u)
{
queue<int> q;
q.push(u);
visited[u] = true;
visit(u);
while (q.size())
{
auto t = q.front();
q.pop();
for (int i = 0; i < G.vexnum; i ++)
if (!visit[i] && G.edges[t][i] != 0)
{
q.push(i);
visited[i] = true;
visit(i);
}
}
}
四、图的拓扑排序算法
1. 邻接表
方法1(对邻接表的存储结构进行改造 )
首先,对邻接表表头结点定义进行修改,加入一个统计结点入度的计数器
假设图的邻接表已经生成,并且各个顶点的入度已经统计在了count中
而后进行程序编写
// 顶点表
typedef struct VNode{
char data;
int count; // count统计顶点当前入度是多少
ArcNode* firstarc;
}VNode;
// 拓扑排序
bool TopSort(AGraph* G)
{
stack<int> s;
vector<int> res; // 用来盛放topsort的结果
for (int i = 0; i < G->vexnum; i ++)
if (G.adjlist[i].count == 0)
s.push(i);
while (s.size())
{
auto t = s.top();
s.pop();
res.push_back(t);
auto p = G->adjlist[t].firstarc;
while (p)
{
auto v = p->adjvex;
if (-- (G->adjlist[v].count) == 0) s.push(v);
p = p->nextarc;
}
}
if (res.size() == G->vexnum)
{
for (auto r : res) cout << r << ' ';
puts("");
return true;
}
return false;
}
方法2(不对邻接表的存储结构进行改造 )
int dist[MaxSize];
bool TopSort(AGraph* G)
{
memset(dist, 0, sizeof dist);
// 统计图中各结点的入度
for (int i = 0; i < G->vexnum; i ++)
{
auto p = G->adjlist[i].firstarc;
while (p)
{
int v = p->adjvex;
dist[v] ++;
p = p->nextarc;
}
}
// 将入度为0的结点入栈
stack<int> s;
vector<int> res;
for (int i = 0; i < G->vexnum; i ++)
if (dist[i] == 0) s.push(i);
// TopSort正式开始
while (s.size())
{
auto t = s.top();
s.pop();
res.push_back(t);
auto p = G->adjlist[t].firstarc;
while (p)
{
auto v = p->adjvex;
if (-- dist[v] == 0) s.push(v);
p = p->nextarc;
}
}
if (res.size() == G->vexnum)
{
for (auto r : res) cout << r << ' ';
puts("");
return true;
}
return false;
}
2. 邻接矩阵
int dist[MaxSize];
bool TopSort(MGraph G)
{
memset(dist, 0, sizeof dist);
for (int i = 0; i < G.vexnum; i ++)
for (int j = 0; j < G.vexnum; j ++)
if (G.edges[i][j] != 0) dist[j] ++;
stack<int> s;
vector<int> res;
for (int i = 0; i < G.vexnum; i ++)
if (dist[i] == 0) s.push(i);
while (s.size())
{
auto t = s.top();
s.pop();
res.push_back(t);
for (int i = 0; i < G.vexnum; i ++)
if (-- dist[i] == 0) s.push(i);
}
if (res.size() == G.vexnum)
{
for (auto r : res) cout << r << ' ';
puts("");
return true;
}
return false;
}
五、图的度数问题
1. 邻接表
(1) 有向图
// 计算所有结点的入度
int dist[MaxSize];
void in_degree(AGraph* G)
{
memset(dist, 0, sizeof dist);
for (int i = 0; i < G->vexnum; i ++)
{
auto p = G->adjlist[i].firstarc;
while (p)
{
auto v = p->adjvex;
dist[v] ++;
p = p->nextarc;
}
}
}
// 计算所有结点的出度
int dist[MaxSize];
void out_degree(AGraph* G)
{
memset(dist, 0, sizeof dist);
for (int i = 0; i < G->vexnum; i ++)
{
auto p = G->adjlist[i].firstarc;
while (p)
{
dist[i] ++;
p = p->nextarc;
}
}
}
(2) 无向图
int dist[MaxSize]; // 记录无向图中各顶点的度数
void degree(MGraph G)
{
memset(dist, 0, sizeof dist);
for (int i = 0; i < G.vexnum; i ++)
{
auto p = G.adjlist[i].firstarc;
while (p)
{
dist[i] ++;
p = p->nextarc;
}
}
}
2. 邻接矩阵
(1) 有向图
// 计算所有结点的入度
int dist[MaxSize];
void in_degree(MGraph G)
{
memset(dist, 0, sizeof dist);
for (int j = 0; j < G.vexnum; j ++)
for (int i = 0; i < G.vexnum; i ++)
dist[j] += G.edges[i][j];
}
// 计算所有结点的出度
int dist[MaxSize];
void out_degree(MGraph G)
{
memset(dist, 0, sizeof dist);
for (int i = 0; i < G.vexnum; i ++)
for (int j = 0; j < G.vexnum; j ++)
dist[i] += G.edges[i][j];
}
(2) 无向图
int dist[MaxSize];
void degree(MGraph G)
{
memset(dist, 0, sizeof dist);
for (int i = 0; i < G.vexnum; i ++)
for (int j = 0; j < G.vexnum; j ++)
dist[i] += G.edges[i][j];
}