自用,写的很乱
1、BFS
void BFSTraverse(Graph G,Status (*visit)(int v))
{
for(int v = 0; v < G.vexNum; v++) visited[v] = false;
InitQueue(Q);
for(int v = 0; v < G.vexNum; v++)
{
if(!visited[v])
{
visited[v] = true; visited(v);
EnQueue(Q, v);
while(!QueueEmpty(Q))
{
int u;
DeQueue(Q, u);
for(int w = FirstAdjVex(G, u); w >= 0; w = NextAdjVex(G, u, w))
{
if(!visited[w])
{
visited[w] = true;
visit(w);
EnQueue(Q, w);
}//if
}//for
}//while
}//if
}//for
} //BFSTraverse
2、DFS
bool visited[MAXSIZE];
Status (*visit)(int v); //函数变量
void DFSTraverse(Graph G)
{
for(int v = 0; v < G.numVex; v++) visited[v] = false;
for(int v = 0; v < G.numVex; v++)
{
if(visited[v] == false)
{
DFS(G, v);
}
}
}
void DFS(Graph G, int v)
{
visited[v] = true;
visit(v);
for(int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G, v, w))
{
if(!visited[v]) DFS(G, v);
}
}
3、DFS非递归(嫌麻烦,所以用C++写的,也不知道考试行不行)
#include<stack>
#include<iostream>
#include<vector>
using namespace std;
void DFS_Non_RC(AGraph &G, int v)
{
int w;
stack<int>stk;
vector<bool>visited(G.vexnum, false);
stk.push(v);
visited[v] = true;
while(!stk.empty())
{
int u = stk.top(); stk.pop();
visit(u);
for(w = FirstNeighbor(G, u); w >= 0; w = NextNeighbor(G, u, w))
{
if(!visited[w])
{
visited[w] = true;
stk.push(w);
}
}
}
}
4、用DFS创建生成树或生成森林(2021考的可能性很大)
typedef struct CSNode{
int data;
struct *CSNode *lchild, *nextSibling;
}CSNode, *CSTree;
bool visited[MAXSIZE];
void DFSForest(Graph G, CSTree &T)
{
T = NULL;
for(int v = 0; v < G.vexNum; v++)
{
visited[v] = false;
}//for
for(int v = 0; v < G.vexNum; v++)
{
if(!visited[v])
{
CSNode *p = (CSNode*)malloc(sizeof(CSNode));
*p = (GetVex(G, v), NULL, NULL);
if(!T) T = p;
else q->nextSibling = p;
q = p;
DFSTree(G, v, p);
}//if
}//for
} //DFSForest
void DFSTree(Graph G, int v, CSTree &T)
{
visited[v] = true; bool first = true;
for(int w = FirstAdjVex(G, v); w >= 0; w = NextAdjVex(G,v,w))
{
if(!visited[w])
{
CSNode *= (CSNode*)malloc(sizeof(CSNode));
*p = {GetVex(G, w), NULL, NULL};
if(first)
{
T->lchild = p; first = false;
} //if
else
{
q->nextSibling = p;
}//else
q = p;
DFSTree(G, w, q);
}//if
}//for
}//DFSTree
5、prim
void MiniSpanTree_Prim(MGraph G,int u)
{
struct{
int adjvex;
int lowcost;
}closeEdge[MAX_VERTEX_NUM];
for(int i = 0; i < G.verNum; i++)
{
if(i != u)
{
closeEdge[i] = {u, G.arcs[u][i].adj};
}
}
closeEdge[i].lowcost = 0;
for(int i = 1; i < G.vexNum; i++)
{
int k = minimum(closeEdge);
print(closeEdge[k].adjvex, G.vexs[k]); //输出生成树的边 vexs[]是顶点向量
closeEdge[k].lowcost = 0;
for(int j = 0; j < G.vexnum; j++)
{
if(G.arcs[k][j].adj < closeEdge[j].lowcost)
{
closeEdge[j] = {G.vexs[k], G.arcs[k][j].adj};
}
}
}
}
好记版本
typedef struct Gragh{ //图的定义
double matrix[MAXSIZE][MAXSIZE]; //邻接矩阵
char vertexs[MAXSIZE];
int verNum; //顶点个数
}Graph;
typedef struct{ //辅助数组类型
int src;
int lowcost;
}Edge;
void prim(Graph g, int u)//第u个结点出发(从0开始编号)
{
Edge closeEdge[MAXSIZE];
for(int i = 0; i < g.verNum; i++) //辅助数组初始化
{
Edge t;
t.src = u;
t.lowcost = g.matrix[u][i];
closeEdge[i] = t;
}
closeEdge[u].lowcost = 0; //初始, U={u}
for(int i = 1; i < g.verNum; i++) // 选择其他数组
{
int k = minimum(closeEdge); //求出T的下一顶点:第k个顶点
//此时 closeEdge[k].lowcost = min{closeEdge[vi].lowcost | closeEdge[vi].lowcost > 0, vi属于V-U}
printf("%2d,%c",closeEdge[k].lowcost, g.vertexs[k]);
closeEdge[k].lowcost = 0; //第k顶点并入U集
for(int j = 0; j < g.verNum; j++)
{
if(g.matrix[k][j] < closeEdge[j].lowcost) //新顶点并入U后更新到U-V的最短距离
{
Edge t;
t.src = k;
t.lowcost = g.matrix[k][j];
closeEdge[j] = t;
}
}
}
}
与dijkstra相差一行代码的prim
#define VERTICE_MAXSIZE 100
#define INF 99999999
typedef struct MGraph{
int edge[VERTICE_MAXSIZE][VERTICE_SIZE];
char verticeList[VERTICE_MAXSIZE]; //顶点表
int n,e; // 顶点数、边数
};
void prim(MGraph &G, int v, int lowcost[], int path[])
{
int n = numberOfVertice(G);
int S[VERTICE_MAXSIZE];
for(int i = 0; i < n; i++)
{
dist[i] = G.edeg[v][i];
S[i] = 0;
if(i != v && dist[i] < INF) path[i] = v;
else path[i] = -1;
}
S[v] = 1; dist[v] = 0;
for(int i = 0; i < n - 1; i++)
{
int min = INF;
int u = v;
for(int j = 0; j < n; j++)
{
if(!S[j] && dist[j] < min){ u = j; min = dist[j];}
}
S[u] = 1; //u结点并入生成树
for(int k = 0; k < n; k++) //新结点并入生成树更新V-U中顶点到U的距离
{
w = G.edge[u][k];
if(!S[k] && w < dist[k])
{//k是V-U中的结点 它到U的距离变短了
dist[k] = w;
path[k] = u;
}
}
}
}
===更新
二合一:
#define INF 9999999
void dijkstraOrPrim(Graph G, int start)
{
bool close[N] = {false};
int Min[N] = {INF};
close[start] = true;
Min[start] = 0;
for(int i = 0; i < n-1; i++)
{
int k = -1;
for(int j = 0; j < n; j++)
{
if(!close[j] && (k == -1 || Min[k] > Min[j])) k = j;
}
close[k] = true;
for(int j = 0; j < n; j++)
{
//dijkstra
if(Min[j] > Min[k]+G[k][j])
{
Min[j] = Min[k] + G[k][j];
}
/*
//prime
if(Min[j] > G[k][j])
{
Min[j] = Min[k] + G[k][j];
}
*/
}
}
/*其余代码*/
}
6、kruskal
版本1(殷人昆版)
typedef struct Edge{
int src;
int dest;
int weight;
}Edge;
void kruskal(ALGraph &g)
{//最小生成树的概念,算法只适用于无向图,有向图有其他的叫法
Edge w; //临时边结点
UFSet ufset; Initial(ufset); //建立并查集并初始化
minHeap heap; Initial(heap); //建立小根堆并初始化
int n = numberOfVertices(g), e = numberOfEdges(g); //图的顶点数和边数
for(int i = 0; i < n; i++) //所有边插入小根堆
{
for(int j = firstNeighbor(g, i); j >= 0; j = nextNeighbor(g, i, j));
{
if(i < j)
{//无向图只用插入一半
w.src = i;
w.dest = j;
w.weight = getWeight(g, i, j);
insert(heap, w); //将边插入小根堆,小根堆以weight排序
}
}
}
int countEdge = 0;
int xroot, yroot;
while(!heapEmpty(heap))
{
Remove(heap, w); //将小根堆堆顶的边赋值个w,并弹出
xroot = Find(ufset, w.src); //并查集中顶点src的根
yroot = Find(ufset, w.dest); //并查集中顶点dest的根
if(xroot != yroot) //两个顶点不在一个集合,可以加入最小生成树
{
printf("%4d-->%4 weight%5d",w.src, w.dest, w.weight); //输出
Merge(w.src, w.dest); //合并连通分量,使两者根一致
countEdge++;
}
}
if(countEdge < n-1) printf("该图不连图,无最小生成树");
}
版本2:c++版 基于邻接矩阵
class UFSet
{
public:
int *parent; //每个子集的根
int *rank; //每个子集的秩
UFSet(int n)
{
parent = new int[n];
rank = new int[n];
for(int i = 0; i < n; i++)
{
parent[i] = i;
rank[i] = 0;
}
}
int find(int x)
{
if(x != parent[x])
{
parent[x] = find(parent[x]); //路径压缩
}
return parent[x];
}
void merge(int x, int y)
{
int xroot = find(x);
int yroot = find(y);
if(xroot == yroot){
return ;
}
if(rank[xroot] < rank[yroot])//按秩合并
{
parent[xroot] = yroot;
}
else if(rank[xroot] > rank[yroot])
{
parent[yroot] = xroot;
}
else
{
parent[yroot] = xroot;
}
}
};
class Edge{
public:
int src;
int dest;
int weight;
Edge(int s,int d,int w)
{
src = s;
dest = d;
weight = w;
}
};
typedef struct MGraph
{
int matrix[MAXSIZE][MAXSIZE];
int vertexNum, edges;
}MGraph;
define INF 999999;
void kruskal(MGraph g)
{
UFSet ufset(g.vertexNum); //创建并查集,传入顶点个数
Edge *edges = new Edge[g.edgeNum]; //创建边集
int p = 0;
for(int i = 0; i < g.vertexNum; i++)
{
for(int j = 0; j < g.vertexNum; j++)
{
if(g.matrix[i][j]> 0 && g.matrix[i][j] != INF)
{
edges[p] = Edge(i, j, g.matrix[i][j]);
}
}
}
sort(edge, edge + g.edgeNum); //按权重进行排序
int count = 0;
for(int i = 0; i < g.edgeNum; i++)
{
x = ufset.find[edges[i].src];
y = ufset.find[edges[i].dest];
if(x != y)
{
ufset.merge(edges[i].src, edges[i].dest);
printf("%3d-->%3d weight:%5d",edges[i].src, edges[i].dest, edges[i].weight);
count++;
}
}
if(count < g.vertexNum-1) printf("该图不连通,无最小生成树");
}
版本3
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Subset
{//并查集类
public:
int* parent; //每个子集的根
int* rank; //每个子集的秩
Subset(int n)
{//构造函数初始化
parent = new int[n];
rank = new int[n];
for (int i = 0; i < n; i++)
{
parent[i] = i;
rank[i] = 0;
}
}
int find(int x) //找x的root
{
if (parent[x] != x)
{
parent[x] = find(parent[x]); //压缩路径
}
return parent[x];
}
void unionSet(int x, int y)
{//合并x合y所在的子集
int xroot = find(x);
int yroot = find(y);
if(xroot == yroot)
{
return ;
}
if (rank[xroot] < rank[yroot])
{
parent[xroot] = yroot;
}
else if (rank[xroot] > rank[yroot])
{
parent[yroot] = xroot;
}
else
{
parent[yroot] = xroot;
rank[xroot]++;
}
}
};
class Edge
{
public:
int src; //起始顶点
int dest; //目标顶点
int weight;
Edge(int _src, int _dest, int _weight)
{
src = _src;
dest = _dest;
weight = _weight;
}
Edge():src(0),dest(0),weight(0){}
bool operator < (const Edge &b) const
{//运算符重载
return weight < b.weight;
}
};
/*
class cmp
{
public:
bool operator () (Edge a, Edge b) //从小到大排
{
return a.weight < b.weight;
}
};
*/
class Graph
{
public:
int V; //顶点数
vector<Edge> edge;
Graph(int v):V(v),edge(0){}
void kruskal()
{
vector<Edge> result; //存放最小生成树的路径
//cmp cmp1;
//sort(edge.begin(), edge.end(),cmp1);
sort(edge.begin(), edge.end()); //对所有边按权重从小到大排序
Subset subsets(V); //创键并查集对象,V为顶点数
int i = 0;
while (i < edge.size()) //处理所有的边
{
int x = subsets.find(edge[i].src);
int y = subsets.find(edge[i].dest);
if (x != y) //在不在同一个集合(连同分量)
{
subsets.unionSet(x, y);
result.push_back(edge[i]);
}
i++;
}
//输出最小生成树的边
vector<Edge>::iterator it;
for (it = result.begin(); it != result.end(); it++)
{
cout << it->src << "-->" << it->dest <<" == "<<it->weight << endl;
}
}
};
int main()
{
Graph g1(4);
g1.edge.push_back(Edge(0, 1, 10));
g1.edge.push_back(Edge(0, 2, 6));
g1.edge.push_back(Edge(0, 3, 5));
g1.edge.push_back(Edge(1, 3, 15));
g1.edge.push_back(Edge(2, 3, 4));
g1.kruskal();
return 0;
}
7、从i到j是否有路径 //2020 848真题
#include<iostream>
#include<queue>
using namespace std;
int visited[MAXSIZE] = {0};
bool exit_path_dfs(ALGraph G,int i, int j)
{
int p;
if(i == j) return true;
visited[i] = true;
for(p = FirstNeighbor(G, i); p >= 0; p = NextNeighbor(G, i, p))
{
if(!visited[p] && exit_path_dfs(G,p,j))
{
return true;
}
}
return false;
}
bool exit_path_bfs(ALGraph G, int i, int j)
{
int visited[MAXSIZE] = {0};
queue<int>q;
q.push(i);
int cur;
while(!q. empty())
{
cur = q.front();
q.pop();
visited[cur] = true;
for(int w = FirstNeighbor(G, i); w >= 0; w = NextNeighbor(G, i, cur))
{
if(w == j) return true;
if(!visited[w]) q.push(w);
}
}
return false;
}
8、打印u到v的所有简单路径
#define VERTEX_MAXSIZE 100
typedef struct ENode{
int dest;
struct ENode *next;
}ENode;
typedef struct VNode{
char data;
struct ENode *adj; //指向第一个邻接顶点
}VNode;
typedef struct AGraph
{
VNode adjList[VERTEX_MAXSIZE];
int n, e; //顶点数,边数
}AGraph;
void print(char path[])
{
//打印.........
}
void findPathUtil(AGraph G,int u, int v, bool visited[],char path[], int pos)
{
int w, i;
ENode *p;
visited[u] = true;
if(u == v)
{
print(path); //打印路径
return ; //简单路径,下面可以剪掉了
}
p = G.adjList[u].adj; //p指向u的第一个邻接顶点
while(p != NULL);
{
w = p->dest;
if(visited[w] == false)
{
path[pos] = G.adjList[w].data;
findPathUtil(G, w, v, visited, path, pos+1);
}
p = p->next;
}
visited[u] = false;
}
void findPath(AGraph G,int u, int v)
{
bool visited[VERTEX_MAXSIZE]={0};
char path[VERTEX_MAXSIZE]= "\0";
findPathUtil(G, u, v,visited, path, 0);
}
9、单源带权非负最短路径dijkstra算法:
版本1:
#define VERTICE_MAXSIZE 100
#define INF 99999999
typedef struct MGraph{
int edge[VERTICE_MAXSIZE][VERTICE_SIZE];
int n,e; // 顶点数、边数
};
void shortestPath_DIJ(MGraph &G, int v, int dist[], int path[])
{
int n = numberOfVertice(G);
int S[VERTICE_MAXSIZE];
for(int i = 0; i < n; i++)
{
dist[i] = G.edeg[v][i];
S[i] = 0;
if(i != v && dist[i] < INF) path[i] = v;
else path[i] = -1;
}
S[v] = 1; dist[v] = 0;
for(int i = 0; i < n - 1; i++)
{
int min = INF;
int u = v; //u指向具有最短路径的顶点
for(int j = 0; j < n; j++)
{
if(!S[j] && dist[j] < min){ u = j; min = dist[j];}
}
S[u] = 1;
for(int k = 0; k < n; k++)
{
w = G.edge[u][k];
if(!S[k] && w < INF && dist[u] + w < dist[k])
{
dist[k] = dist[u] + w;
path[k] = u;
}
}
}
}
//输出
void printShortestPath(MGraph &G, int v, int dist[], int path[])
{
printf("从顶点到[%c]到其他各顶点的最短路径为:\n",G.verticeList[v]);
int n = numberOfVertices(G);
int d[VERTICE_MAXSIZE];
for(int i = 0; i < n; i++)
{
if(i != v)
{
int j = i, k = 0;
while(j != v) { d[k++] = j; j = path[j]; }
d[k++] = v;
printf("到顶点[%c]的最短路径为:",G.verticeList[i]);
while(k > 0) printf("%c ", G.verticeList[d[k--]]);
printf(" 长度: %6d\n",dist[i]);
}
}
}
10、无向图从i到j存不存在长度为k的简单路径
版本1:严版课后习题答案 dfs
int exist_path_len(ALGraph G,int i, int j, int k)
{
int visited[MAXSIZE]={0};
return exist_path_len_util(G, i, j, k, visited);
}
int exist_path_len_util(ALGraph G,int i, int j, int k,int visited[])
{
if(i == j && k == 0) return 0;
else if(k > 0)
{
visited[i] = 1;
for(int w = firstNeighbor(G,i); w >= 0; w = nextNeighbor(G,i,w))
{
if(!visited[w] && exist_path_len_util(G, i, j, k-1, visited));
}
visited[i] = 0;
}
return 0;
}
版本2 BFS(错误示例, 写完发现错了)
int exist_path_len2(ALGraph G, int i, int j, int k)
{
if(k < 0 || i < 0 || j < 0) return 0;
InitQueue(Q);
EnQueue(Q,i);
int cur;
int level;
int visited[MAXSIZE] = {0};
while(!QueueEmpty(Q))
{
DeQueue(Q,cur);
visited[cur] = 0;
level++;
if(lever > k) return 0;
for(int w = firstNeighbor(G, cur); w >= 0; w = nextNeighbor(G, cur, w))
{
if(level == k && w == j) return 1;
if(!visited[w])
{
EnQueue(Q, w);
}
}
}
return 0;
}
12、拓扑排序
版本1:严版
typedef struct VNode {
VertexType data;
ArcNode *firstarc;
} VNode, AdjList[MAX_VERTEX_NUM];
typedef struct ArcNode{
int adjvex;
struct ArcNode *nextarc;
InfoType *info;
}ArcNode;
typedef struct {
AdjList vertices;
int vexnum, arcnum;
int kind;
} ALGraph;
Status topologicalSort(ALGraph G)
{
int indegree[VERTICE_MAXSIZE];
FindInDegree(G, indegree);
InitStack(S);
for(int i = 0; i < G.vexnum; i++)
{
if(!indegree[i]) Push(S, i);
}
count = 0;
while(!StackEmpty(S))
{
Pop(S); print(i, G.vertice[i].data);
count++;
for(p = G.vertices[i].firstarc; p != NULL; p = p->nextarc)
{
int k = p->adjvex;
if(!(--indegree[k])) Push(S, k);
}
}
if(count < G.vexnum) return ERROR;
else return OK;
}
版本2:
#define maxsize 100
bool topologicalSort(Graph G,int topoArray[], int &k)
{//G为给定图,函数通过topoArray返回拓扑排序(若有),通过k返回topoArray中顶点个数
//若小于顶点个数则该图无拓扑排序
int S[maxsize]; int top = -1; //定义栈,存放入度为0的顶点
int n = numberOfVertices(G); //顶点个数
int* indegree = (int*)malloc(sizeof(int)*n); //创建入度数组
getIndegree(G,indegree); //计算给定图每个顶点的入度
for(int i = 0; i < n; i++)
{
if(indegree[i] == 0) S[++top] = i; //入度为0的顶点入栈
}
int cur;
k = 0;
while(top > -1)
{
cur = S[top--];
topoArray[k++] = cur;
for(int w = firstNeighbor(G,cur); w >= 0; w = nextNeighbor(G,cur,w))
{//扫描cur顶点的出边表
if((--indegree[w])==0) S[++top] = w; //邻接顶点入度减一,减后该顶点入度为0则入栈
}
}
if(k < n)
{
printf("给定图有环,无拓扑排序");
return false;
}
return true;
}
12、关键路径
#define maxsize 100
bool topologicalSort(Graph G,int topoArray[], int &k)
{//G为给定图,函数通过topoArray返回拓扑排序(若有),通过k返回topoArray中顶点个数
//若小于顶点个数则该图无拓扑排序
int S[maxsize]; int top = -1; //定义栈,存放入度为0的顶点
int n = numberOfVertices(G); //顶点个数
int* indegree = (int*)malloc(sizeof(int)*n); //创建入度数组
getIndegree(G,indegree); //计算给定图每个顶点的入度
for(int i = 0; i < n; i++)
{
if(indegree[i] == 0) S[++top] = i; //入度为0的顶点入栈
}
int cur;
k = 0;
while(top > -1)
{
cur = S[top--];
topoArray[k++] = cur;
for(int w = firstNeighbor(G,cur); w >= 0; w = nextNeighbor(G,cur,w))
{//扫描cur顶点的出边表
if((--indegree[w])==0) S[++top] = w; //邻接顶点入度减一,减后该顶点入度为0则入栈
}
}
if(k < n)
{
printf("给定图有环,无拓扑排序");
return false;
}
return true;
}
bool criticalPath(Graph G)
{
int n = numberOfVertices(G);
int *topoArray = (int*)malloc(sizeof(int)*n);
int k = 0;
if(!topologicalSort(G,topoArray,k)) return false;
int *ve = (*int)malloc(sizeof(int)*n); //ve[i]表示事件i最早开始时间
int *vl = (*int)malloc(sizeof(int)*n); //vl[i]表示事件i最迟开始时间
for(int i = 0; i < n; i++)
{
ve[i] = 0;
vl[i] = INF;
}
for(int i = 0; i < n-1; i++) //计算各事件最早开始时间
{
int cur = topoArray[i];
for(int w = firstNeighbor(G,cur); w >= 0; w = nextNeighbor(G,cur,w))
{
if(ve[cur] + getWeight(G,cur,w) > ve)
ve[w] = ve[cur] + getWeight(G,cur,w);
}
}
vl[n-1] = ve[n-1];
for(int i = n-2; i >= 0; i--)
{//计算各事件最晚开始时间
int cur = topoArray[i];
for(int w = firstNeighbor(G,cur); w >= 0; w = nextNeighbor(G,cur,w))
{
if(vl[w] - getWeight(G,cur,w) < vl[cur])
vl[cur] = vl[w] - getWeight(G,cur,w);
}
}
for(int i = 0; i < n; i++) //计算所有活动最早和最晚开始时间
{
for(int w = firstNeighbor(G, i); w >= 0; w = nextNeighbor(G, i, w))
{
int ae = ve[i]; // <i,w>活动最早开始时间
int al = vl[w] - getWeight(G, i, w); // <i,w>最晚开始时间
char tag = (ae == ee)?'Y':'N';
printf("%d->%d 持续时间:%d, 最早开始时间:%d,最晚开始时间:%d,\
是否是关键路径的一条边:", i,w,getWeight(G,i,w),ae,al,tag);
}
}
return true;
}