图的邻接表和邻接矩阵表示以及相关算法

图是由定点的非空有限集合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);
}
发布了115 篇原创文章 · 获赞 25 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/lion19930924/article/details/72473900