图是由定点的非空有限集合V与变得集合E组成的,其形式化定义为:G = (V, E),若图中的每一条边是没有方向的则称G为无向图,否则称为有向图。图的表示方法有邻接矩阵和邻接表表示法。图的常见算法有深度优先搜索,广度优先搜索,Prim算法,dijsktra算法,floyd算法,拓扑排序和关键路径。我用C++进行了实现,代码如下,具体的算法请上网搜索。
图的邻接矩阵表示:
#include <iostream>
#include <climits>
#include <sstream>
#include <queue>
#include <string>
#include <stack>
#include <cstring>
#include <vector>
using namespace std;
const bool UNDIGRAPH = 0;
struct Graph{
string *vertexLabel;//the number of the labels is equal to vertexes
int vertexes;
int edges;
int **AdjMat;
bool *visited;
int *distance;
int *path;
};
void buildGraph(Graph *&graph, int n) {
if (graph == NULL)
{
graph = new Graph();
graph->vertexes = n;
graph->edges = 0;
graph->AdjMat = new int *[n];
graph->vertexLabel = new string[n];
graph->visited = new bool[n];
graph->distance = new int[n];
graph->path = new int[n];
for (int i = 0; i < graph->vertexes; i++)
{
stringstream ss;
ss<<"v" << i+1;
ss >> graph->vertexLabel[i];
graph->visited[i] = false;
graph->distance[i] = INT_MAX;
graph->path[i] = -1;
graph->AdjMat[i] = new int[n];
if(UNDIGRAPH)
memset(graph->AdjMat[i],0, n * sizeof(int));
else
for (int j = 0; j < graph->vertexes; j++)
{
if(i == j)
graph->AdjMat[i][j] = 0;
else
graph->AdjMat[i][j] = INT_MAX;
}
}
}
}
void emptyGraph(Graph *graph) {
if (graph == nullptr) {
return;
}
delete []graph->vertexLabel;
delete []graph->visited;
delete []graph->distance;
delete []graph->path;
for (int i = 0;i < graph->vertexes;i++) {
delete []graph->AdjMat[i];
}
delete []graph->AdjMat;
delete graph;
}
void addEdge(Graph *graph, int v1, int v2, int weight) {
if (graph == nullptr) {
return;
}
if ((v1 < 0 || v1 > graph->vertexes) || (v2 < 0 || v2 > graph->vertexes)) {
return;
}
if (v1 == v2) {
return;
}
if (UNDIGRAPH) {
if (graph->AdjMat[v1][v2] == 0) {
graph->edges++;
}
graph->AdjMat[v1][v2] = graph->AdjMat[v2][v1] = weight;
}
else {
if (graph->AdjMat[v1][v2] == 0 || graph->AdjMat[v1][v2] == INT_MAX)
graph->edges++;
graph->AdjMat[v1][v2] = weight;
}
}
void removeEdges(Graph *graph, int v1, int v2) {
if (graph == nullptr) {
return;
}
if ((v1 < 0 || v1 > graph->vertexes) || (v2 < 0 || v2 > graph->vertexes)) {
return;
}
if (v1 == v2) {
return;
}
if (UNDIGRAPH)
{
if (graph->AdjMat[v1][v2] == 0)//not exists,return
return;
graph->AdjMat[v1][v2] = graph->AdjMat[v2][v1] = 0;
graph->edges--;
}
else
{
if (graph->AdjMat[v1][v2] == 0 || graph->AdjMat[v1][v2] == INT_MAX)//not exists,return
return;
graph->AdjMat[v1][v2] = INT_MAX;
graph->edges--;
}
}
void clearVisit(Graph *graph) {
for (int i = 0;i < graph->vertexes;i++) {
graph->visited[i] = false;
}
}
void clearDistance(Graph *graph) {
for (int i = 0;i < graph->vertexes;i++) {
graph->distance[i] = INT_MAX;
}
}
void clearPath(Graph *graph) {
for (int i = 0;i < graph->vertexes;i++) {
graph->path[i] = -1;
}
}
int getIndegree(Graph *graph, int v) {
if (graph == NULL) {
return -1;
}
if (v < 0 || v > graph->vertexes) {
return -2;
}
if (UNDIGRAPH) {
return -3;
}
int degree = 0;
for (int i = 0;i < graph->vertexes;i++) {
if(graph->AdjMat[i][v] != 0 && graph->AdjMat[i][v] != INT_MAX)
degree++;
}
return degree;
}
int getOutdegree(Graph *graph, int v) {
if (graph == NULL) {
return -1;
}
if (v < 0 || v > graph->vertexes) {
return -2;
}
if (UNDIGRAPH) {
return -3;
}
int degree = 0;
for (int i = 0;i < graph->vertexes;i++) {
if(graph->AdjMat[v][i] != 0 && graph->AdjMat[v][i] != INT_MAX)
degree++;
}
return degree;
}
int getUndirectedDegree(Graph *graph, int v) {
if (graph == NULL) {
return -1;
}
if (v < 0 || v > graph->vertexes) {
return -2;
}
if(UNDIGRAPH)
{
int degree = 0;
for (int i = 0; i < graph->vertexes; i++)
{
if(graph->AdjMat[v][i] != 0)
degree++;
}
return degree;
}
else
return getIndegree(graph,v) + getOutdegree(graph,v);
}
//DFS递归的方式
void dfsR(Graph *graph, int i) {
if (!graph->visited[i]) {
cout << i << " has been visited" << endl;
graph->visited[i] = true;
}
for (int j = 0;j < graph->vertexes;j++) {
if (UNDIGRAPH) {
if (graph->AdjMat[i][j] != 0 && !graph->visited[j]) {
dfsR(graph, j);
}
}
else {
if (graph->AdjMat[i][j] != INT_MAX && !graph->visited[j])
dfsR(graph,j);
}
}
}
//dfs非递归
void dfsI(Graph *graph, int i) {
stack<int> st;
st.push(i);
while (!st.empty()) {
int top = st.top();
st.pop();
if (!graph->visited[top]) {
cout << top << " has been visited" << endl;
graph->visited[top] = true;
}
for (int j = 0;j < graph->vertexes;j++) {
if (UNDIGRAPH) {
if (graph->AdjMat[top][j] != 0 && !graph->visited[j]) {
st.push(j);
}
}
else {
if (graph->AdjMat[top][j] != INT_MAX && !graph->visited[j])
st.push(j);
}
}
}
}
void travelDFS(Graph *gra
ph) {
clearVisit(graph);
if(graph == NULL) return;
cout << "DFS\n";
for (int i = 0; i < graph->vertexes; i++)
graph->visited[i] = false;
for (int i = 0; i < graph->vertexes; i++)
dfsI(graph,i);
}
//bfs
void travelBFS(Graph *graph) {
if (graph == NULL) {
return;
}
clearVisit(graph);
cout << "BFS" << endl;
queue<int> qu;
for (int i = 0;i < graph->vertexes;i++) {
if (!graph->visited[i]) {
qu.push(i);
while (!qu.empty()) {
int top = qu.front();
qu.pop();
if (!graph->visited[top]) {
cout << top << " has been visited" << endl;
graph->visited[top] = true;
}
for(int j = 0;j < graph->vertexes;j++) {
if (UNDIGRAPH) {
if (graph->AdjMat[top][j] != 0 && !graph->visited[j]) {
qu.push(j);
}
}
else {
if (graph->AdjMat[top][j] != INT_MAX && !graph->visited[j])
qu.push(j);
}
}
}
}
}
}
//prim算法求一个图的最小生成树时间复杂度是O(n3)
void primOriginal(Graph *graph) {
if (graph == NULL) {
return;
}
clearVisit(graph);
int n = graph->vertexes;
bool *isin = new bool[n];
for (int i = 0;i < graph->vertexes;i++) {
isin[i] = false;
}
isin[0] = true;
vector<int> in;
in.push_back(0);
for (int i = 1;i < graph->vertexes;i++) {
int minWeight = INT_MAX;
int lastSt = -1;
int start = -1;
int nextIn = -1;
for(int j = 0;j < in.size();j++) {
start = in[j];
for (int k = 0;k < graph->vertexes;k++) {
if (UNDIGRAPH) {
if (graph->AdjMat[start][k] != 0 && !isin[k] && k != start) {
if (graph->AdjMat[start][k] < minWeight) {
minWeight = graph->AdjMat[start][k];
lastSt = start;
nextIn = k;
}
}
}
else {
if (graph->AdjMat[start][k] != INT_MAX && !isin[k] && k != start) {
if (graph->AdjMat[start][k] < minWeight) {
minWeight = graph->AdjMat[start][k];
lastSt = start;
nextIn = k;
}
}
}
}
}
if (nextIn == -1) {
cout << "can't find the MST" << endl;
return;
}
isin[nextIn] = true;
in.push_back(nextIn);
cout << lastSt << " to " << nextIn << " weight " << graph->AdjMat[lastSt][nextIn] << endl;
}
}
//利用distance和path将时间复杂度缩小到O(n2)
void primMin(Graph *graph) {
if (!graph) {
return;
}
clearVisit(graph);
graph->visited[0] = true;
graph->distance[0] = 0;
graph->path[0] = 0;
for (int i = 1;i < graph->vertexes;i++) {
graph->path[i] = 0;
graph->distance[i] = graph->AdjMat[0][i];
}
for (int i = 1;i < graph->vertexes;i++) {
int minWeight = INT_MAX;
int nextIn = -1;
for (int j = 0;j < graph->vertexes;j++) {
if (!graph->visited[j] && graph->distance[j] < minWeight) {
minWeight = graph->distance[j];
nextIn = j;
}
}
if (nextIn == -1) {
cout << "prim algorithm end " << endl;
return;
}
cout << graph->path[nextIn] << " to " << nextIn << " weight " << graph->distance[nextIn] << endl;
graph->visited[nextIn] = true;
for (int j = 0;j < graph->vertexes;j++) {
if(!graph->visited[j] && graph->distance[j] > graph->AdjMat[nextIn][j]) {
graph->path[j] = nextIn;
graph->distance[j] = graph->AdjMat[nextIn][j];
}
}
}
}
//dijsktra算法
void dijsktra(Graph *graph, int v) {
if (graph == NULL) {
return;
}
clearVisit(graph);
clearDistance(graph);
clearPath(graph);
graph->visited[v] = true;
graph->distance[v] = 0;
int minNode = v;
int minDistance = INT_MAX;
for (int i = 0;i < graph->vertexes;i++) {
if (i == v) {
continue;
}
graph->distance[i] = graph->AdjMat[v][i];
graph->path[i] = v;
}
cout << minNode << " has been visited distance : " << graph->distance[minNode] << " path node : " << graph->path[minNode] << endl;
while(true) {
minNode = -1;
minDistance = INT_MAX;
for(int i = 0;i < graph->vertexes;i++) {
if (!graph->visited[i] && graph->distance[i] < minDistance) {
minDistance = graph->distance[i];
minNode = i;
}
}
if (minNode == -1) {
cout << "dijsktra algorithm end" << endl;
break;
}
graph->visited[minNode] = true;
cout << minNode << " has been visited distance : " << graph->distance[minNode] << " path node : " << graph->path[minNode] << endl;
for (int i = 0;i < graph->vertexes;i++) {
if (!graph->visited[i] && graph->AdjMat[minNode][i] != INT_MAX && graph->distance[i] > graph->distance[minNode] + graph->AdjMat[minNode][i]) {
graph->distance[i] = graph->distance[minNode] + graph->AdjMat[minNode][i];
graph->path[i] = minNode;
}
}
}
}
//floyd算法,计算图中任意两个节点的最短距离
int **floyd(Graph *graph) {
if (!graph) {
return NULL;
}
int n = graph->vertexes;
int **res = new int *[n];
for (int i = 0;i < n;i++) {
res[i] = new int[n];
res[i][i] = 0;
}
for (int i = 0;i < n;i++) {
for (int j = 0;j < n;j++) {
res[i][j] = graph->AdjMat[i][j];
}
}
for (int i = 0;i < n;i++) {
for (int j = 0;j < n;j++) {
if (i == j) {
continue;
}
for (int k = 0;k < n;k++) {
if(res[i][k] == INT_MAX || res[k][j] == INT_MAX) {
continue;
}
res[i][j] = min(res[i][j], res[i][k] + res[k][j]);
}
}
}
for (int i = 0;i < n;i++) {
for (int j = 0;j < n;j++) {
cout << res[i][j] << ' ';
}
cout << endl;
}
return res;
}
//拓扑排序可以扩展为检查一个图中是否有环
void topoSort(Graph *graph) {
if(UNDIGRAPH) return;
if(graph == NULL) return;
cout << "TopologicalSort"<<"\n";
int counter = 0;
queue <int> qVertex;
for (int i = 0; i < graph->vertexes; i++)
{
if(getIndegree(graph,i) == 0)
qVertex.push(i);
}
while (!qVertex.empty())
{
int vertexNO = qVertex.front();
counter++;
cout << graph->vertexLabel[vertexNO];
if(counter != graph->vertexes)
cout << " > ";
qVertex.pop();
for (int i = 0; i < graph->vertexes; i++)
{
if(i == vertexNO)
continue;
if (getIndegree(graph,i) != 0)
{
graph->AdjMat[vertexNO][i] = INT_MAX;//indegree--
if(getIndegree(graph,i) == 0)
qVertex.push(i);
}
}
}
cout << "\n";
}
int main() {
Graph *graph = NULL;
buildGraph(graph,7);
addEdge(graph,0,1,2);
addEdge(graph,0,3,1);
addEdge(graph,1,3,3);
addEdge(graph,1,4,10);
addEdge(graph,2,0,4);
addEdge(graph,2,5,5);
addEdge(graph,3,2,2);
addEdge(graph,3,4,2);
addEdge(graph,3,5,8);
addEdge(graph,3,6,4);
addEdge(graph,4,6,6);
addEdge(graph,6,5,1);
//travelDFS(graph);
//travelBFS(graph);
//prim(graph);
//primMin(graph);
//dijsktra(graph, 0);
//floyd(graph);
//topoSort(graph);
}
图的邻接表表示:
#include <iostream>
#include <climits>
#include <sstream>
#include <queue>
#include <string>
#include <stack>
using namespace std;
struct edgeNode{
int vtxNQ;
int weight;
edgeNode *next;
};
struct vNode{
string vertexLabel;
edgeNode *first;
bool visited;
int distance;
int path;
int indegree;
};
struct Graph{
vNode *vertexList;
int vertexes;
int edges;
};
void buildGraph(Graph *&graph, int n) {
if (graph == NULL) {
graph = new Graph();
graph->vertexList = new vNode[n];
graph->vertexes = n;
graph->edges = 0;
for (int i = 0;i < n;i++) {
stringstream ss;
ss<<"v" << i+1;
ss >> graph->vertexList[i].vertexLabel;
graph->vertexList[i].path = -1;
graph->vertexList[i].visited = false;
graph->vertexList[i].first = NULL;
graph->vertexList[i].indegree = 0;
}
}
}
void makeEmpty(Graph *graph) {
if(graph == NULL) {
return;
}
for (int i = 0;i < graph->vertexes;i++) {
edgeNode *pEdge = graph->vertexList[i].first;
while (pEdge) {
edgeNode *tmp = pEdge;
pEdge = pEdge->next;
delete tmp;
}
}
delete graph;
}
void addEdge(Graph *graph, int v1, int v2, int weight) {
if (graph == NULL) return;
if (v1 < 0 || v1 > graph->vertexes-1) return;
if (v2 < 0 || v2 > graph->vertexes-1) return;
if (v1 == v2) return;
edgeNode *p = graph->vertexList[v1].first;
if(p == NULL) {
graph->vertexList[v1].first = new edgeNode;
graph->vertexList[v1].first->next = NULL;
graph->vertexList[v1].first->vtxNQ = v2;
graph->vertexList[v1].first->weight = weight;
graph->edges++;
graph->vertexList[v2].indegree++;
return;
}
while (p->next) {
if (p->vtxNQ == v2) {
return;
}
p = p->next;
}
if ( p->vtxNQ == v2) {
return;
}
edgeNode *node = new edgeNode();
node->next = NULL;
node->vtxNQ = v2;
node->weight = weight;
p->next = node;
graph->edges++;
graph->vertexList[v2].indegree++;
}
void removeEdge(Graph *graph, int v1, int v2) {
if (graph == NULL) return;
if (v1 < 0 || v1 > graph->vertexes-1) return;
if (v2 < 0 || v2 > graph->vertexes-1) return;
if (v1 == v2) return;
edgeNode *p = graph->vertexList[v1].first;
if(p == NULL) {
return;
}
if(p->vtxNQ == v2) {
edgeNode *q = p->next;
graph->vertexList[v1].first = q;
delete p;
graph->edges--;
graph->vertexList[v2].indegree--;
return;
}
edgeNode *q = NULL;
while(p->vtxNQ != v2) {
q = p;
p = p->next;
}
q->next = p->next;
p->next = NULL;
delete p;
graph->edges--;
graph->vertexList[v2].indegree--;;
}
//DFS遍历
void dfs(Graph *graph, int v) {
if (!graph->vertexList[v].visited) {
graph->vertexList[v].visited = true;
cout << v << " has been visited" << endl;
}
edgeNode *p = graph->vertexList[v].first;
while(p != NULL) {
if(!(graph->vertexList[p->vtxNQ].visited)) {
dfs(graph, p->vtxNQ);
}
p = p->next;
}
}
void dfsIter(Graph *graph, int v) {
if (!graph) {
return;
}
stack<int> nodes;
nodes.push(v);
while(!nodes.empty()) {
int top = nodes.top();
nodes.pop();
if (!graph->vertexList[top].visited) {
graph->vertexList[top].visited = true;
cout << top << " has been visited" << endl;
}
edgeNode *p = graph->vertexList[top].first;
while(p != NULL) {
if (!graph->vertexList[p->vtxNQ].visited) {
nodes.push(p->vtxNQ);
}
p = p->next;
}
}
}
void criticalPath(Graph *graph) {
int i, j, k;
int n = graph->vertexes;
int m = graph->edges;
int *ee = new int[n];
int *le = new int[n];
int *e = new int[m];
int *l = new int[m];
edgeNode *p;
for(int i = 0;i < n;i++) {
ee[i] = 0;
}
for(int i = 0;i < n - 1;i++) {
p = graph->vertexList[i].first;
while (p != NULL) {
j = p->vtxNQ;
if (ee[j] < ee[i] + p->weight) {
ee[j] = ee[i] + p->weight;
}
p = p->next;
}
}
for(int i = 0;i < n;i++) {
le[i] = 0;
}
le[n - 1] = ee[n - 1];
for(int i = n - 2;i >= 0;i--) {
p = graph->vertexList[i].first;
while(p != NULL) {
j = p->vtxNQ;
if (le[i] > le[j] - p->weight) {
le[i] = le[j] - p->weight;
}
p = p->next;
}
}
k = -1;
for(int i = 0;i < n - 1;i++) {
p = graph->vertexList[i].first;
while(p != NULL) {
j = p->vtxNQ;
e[++k] = ee[i];
l[k] = le[j] - p->weight;
if(l[k] == e[k]) {
cout << i << " "<<j << " " << p->weight << endl;
}
p = p->next;
}
}
}
void beginDFS(Graph* graph) {
if (!graph) {
return;
}
cout << "dfs\n";
for(int i = 0;i < graph->vertexes;i++) {
graph->vertexList[i].visited = false;
}
for(int i = 0;i < graph->vertexes;i++) {
dfsIter(graph, i);
}
}
int main() {
Graph *graph = NULL;
buildGraph(graph,7);
addEdge(graph,0,1,1);
addEdge(graph,0,2,1);
addEdge(graph,0,3,1);
addEdge(graph,1,3,1);
addEdge(graph,1,4,1);
addEdge(graph,2,5,1);
addEdge(graph,3,2,1);
addEdge(graph,3,5,1);
addEdge(graph,3,6,1);
addEdge(graph,4,3,1);
addEdge(graph,4,6,1);
addEdge(graph,6,5,1);
//beginDFS(graph);
criticalPath(graph);
}