【考研-数据结构】图
1.图的存储结构和遍历
//图
//1.邻接矩阵(唯一)
//适合稠密图,二维矩阵:用0,1表示边是否存在,带权图用权值代替1
//2.邻接表(不唯一)
//顺序+链式存储,适合存储稀疏图(表示方法不唯一)
//3.十字链表(不唯一)
//存储有向图
//4.邻接多重表(不唯一)
//存储无向图
#include<iostream>
#define MaxVertexNum 20
#define Max_num 20
using namespace std;
//***邻接表***
typedef struct ALGraph{
AdjList vertices;
int vexNum; //结点个数
int arcNum; //边的个数
}ALGraph;
//顶点
typedef struct VNode{
char data; //顶点信息
ArcNode *first; //第一条边
}VNode,AdjList[MaxVertexNum];
//边
typedef struct ArcNode{
int adjvex; //边指向那个节点
ArcNode *next; //指向下一条弧的指针
}ArcNode;
//*****广度优先遍历*****
bool visited[Max_num]; //用于记录结点是否被访问过,初始化为false
void BFSTraverse(Graph G){
//初始化标记数组
for(int i = 0;i<G.vexNum;i++){
visited[i] = false;
}
//初始化队列
InitQueue(Q);
for(int i = 0;i<G.vexNum;i++){
//对每个连通分量都调用一次BFS
if(!visited[i]){
BFS(G,i);
}
}
}
//NextNeighbor(G,v,w)表示图G中v顶点除了w邻接点以外的邻接点
void BFS(Graph G,int v){
visit(v); //访问初始顶点v
visited[v] = true; //做标记
Enqueue(Q,v); //顶点v入队
while(!Empty(Q)){
DeQueue(Q,v); //顶点v出队
for(VNode w = FirstNeighbor(G,v);w>=0;w = NextNeighbor(G,v,w)){
//检测所有v的邻接点
if(!visited[w]){
visit(w); //访问顶点w
visited[w] = true; //顶点w做标记
EnQueue(Q,w); //顶点w入队
}
}
}
}
//*****深度优先遍历*****
bool visited[Max_NUM];
void DFSTraverse(Graph G){
for(v = 0;v<G.vexNum;v++){
visited[v] = false;
}
for(v = 0;v<G.vexNum;v++){
if(!visited[v]){
DFS(G,v);
}
}
}
void DFS(Graph G,int v){
visit(v);
visited[v] = true;
//w为未被访问的结点
for(w = FirstNeighbor(G,v);w>=0;w = NextNeighbor(G,v,w)){
if(!visited[w]){
DFS(G,w);
}
}
}
int main() {
return 0;
}
2.图的应用
//图的应用
//**1.求最小生成树
// (1)Prim算法(时间复杂度O(|V|^2))
// (2)kulusiteer(时间复杂度O(|E|*log2|E|))
//**2.单源最短路径:
// (1)广度优先遍历实现(只能用于无权图)
// (2)Dijkstra算法(可以用于有权图,用于负权值的时候会出问题,时间复杂度O(|V|^2))
//**3.各个顶点之间的最短路径
// (1)Floyd算法(带权图和无权图和负权图都适用,但是无法解决带有负权回路的图,时间复杂度O(|V|^3))
//**4.拓扑排序
//
//广度优先遍历实现
void BFS_MIN_Distance(Graph G,int u){
//d[i]表示从u到i结点的最短路径
for(int i = 0;i<G.vexnum;i++){ //vexnum为结点个数
d[i] = 0; //此处等于无穷
path[i] = -1; //最短路径从那个顶点过来(某个定点的直接前驱)
}
d[u] = 0;
visited[u] = true;
EnQueue(Q,u);
while(!isEmpty(Q)){
DeQueue(Q,u); //队头元素出队
for(w = FitstNeighbor(G,u);w>=0;w = NextNeighbor(G,u,w)){
if(!visited[w]){ //w为u的尚未访问的临界顶点
d[w] = d[u]+1; //路径长度+1
path[w] = u; //最短路径应从u到w
visited[w] = true; //设已访问标记
EnQueue(Q,w); //顶点w入队
}
}
}
}
//Dijkstra算法
//Floyd算法(伪代码)
//准备工作。。。初始化矩阵a和path
void Floyd(Graph G){
for(int k = 0;k<n;k++){
for(int i = 0;i<n;i++){ //遍历矩阵
for(int j = 0;j<n;j++){
if(A[i][j]>A[i][k]+A[k][j]){
A[i][j] = A[i][k]+A[k][j]; //更新路径长度
path[i][j] = k;
}
}
}
}
}
//拓扑排序
bool TopologicalSort(Graph G){
InitStack(S); //初始化栈,存储入度为0的顶点
for(int i = 0;i<G.vexnum;i++){
if(indegree[i] == 0){
Push(S,i); //将所有入度为0的顶点入栈
}
}
int count = 0; //计数。记录当前已经输出的顶点数
while(!isEmpty(S)){ //栈不空,则存在入度为0的顶点
Pop(S,i); //栈顶元素出栈
print[count++] = i; //输出顶点i
for(p = G.vertices[i].firstarc;p;p = p->nextarc){
//将所有i指向的顶点的入度-1.并且将入度减为0的顶点压入栈S
v = p->adjvex;
if(!(--indegree[v])){
Push(S,v); //入度为0,则入栈
}
}
}
if(count<<G.vexnum) return false; //排序失败,说明图中有回路
else return true; //排序成功
}
//逆拓扑排序(找到出度为0的顶点)
//用DFS算法实现逆拓扑排序
void DFSTraverse(Graph G){
for(v = 0;v<G.vexnum;v++){
visited[v] = false;
}
for(v = 0;v<G.vexnum;v++){
if(!visited[v]){
DFS(G,v);
}
}
}
void DFS(Graph G,int v){
visited[v] = true;
for(w = FirstNeighbor(G,v);w>=0;w = NextNeighbor(G,v,w)){
if(!visited[w]){
DFS(G,w);
}
}
print(v); //输出逆拓扑排序
}