1.起因
为什么要总结图,因为两次华为面试过程中,因为有关图的面试题都回答不上来。
问题一:什么是深度优先什么是广度优先,最短路径使用的是深度优先还是广度优先。
问题二:什么是拓扑排序?怎么实现?
2.图的定义
领接矩阵
typedef struct
{
int edges[MaxSize][MaxSize];
int n, e;//n顶点数,e边数
int vex[MaxSize];//节点信息,顶点编号
}MGraph;
领接表
//领接表定义
typedef struct ArcNode
{
int adjvex;//该边指向的节点位置
struct ArcNode *nextarc;//指向下一条边的指针
int info;//该边的相关信息,比如权重
};
typedef struct VNode {
char data;//顶点信息
ArcNode *firstarc;//指向第一条边的指针
};
typedef struct AGraph
{
VNode adjlist[MaxSize];//领接表
int n, e;//顶点数和边数
};
3.深度优先遍历
首先访问任意一个节点V并标记为已访问,然后选择v的任意一个未被访问的领接点w并访问,继续选择w的任意未被访问的领接点,依次重复。
如果一个节点的所有领接点都已经被访问,依次退回最近访问过的节点,如果该节点有未被访问的领接点则访问,直到所有的节点都被访问。
递归实现
循环实现
4.广度优先遍历
5.最小代价生成树
6.最短路径
7.拓扑排序
7.1拓扑排序
邻接表表头结构进行修改:增加一个count字段,统计顶点当前入度
typedef struct VNode {
char data;//顶点信息
ArcNode *firstarc;//指向第一条边的指针
int count;//记录顶点当前的入度
};
outputNum:记录当前输出的顶点个数,初始化为0.
1.扫描所有顶点,将入度为0的顶点入栈;
2.在栈不为空的情形下执行循环:
2.1出栈,outputNum+1,输出出栈顶点
2.2将由该顶点引出边所指向的所有顶点的入度减1,如果入度减为0入栈
3.退出循环后,判断outputNum是否等于图形的顶点数,是1否0
实现代码
int TopSort(AGraph *g)
{
int outputNum = 0;//记录已经输出顶点个数
//1.扫描所有顶点,将入度为0的顶点入栈
int m_stack[MaxSize], top = -1;
for (int i = 0; i < g->n;i++)
{
if (g->adjlist[i].count==0)
{
++top;
m_stack[top] = i;
}
}
//栈不空时,执行循环
while (top!=-1)
{
//1.顶点出栈
int i = m_stack[top];
top--;
//2.计数加1,输出当前顶点
++outputNum;
cout << i << " ";
//由此顶点引出的边所指向的多有顶点入度都减1,如果入度变为了0的顶点如栈
ArcNode* p = g->adjlist[i].firstarc;
while (p!=nullptr)
{
int j = p->adjvex;
--(g->adjlist[j].count);
if (g->adjlist[j].count==0)
{
++top;
m_stack[top] = j;
}
p->nextarc;
}
}
if (outputNum==g->n)
{
return 1;
}
return 0;
}
7.2逆序拓扑排序,DFS实现