用C/C++手搓图结构:从基础到高阶的完整算法指南

一、图的本质与核心结构

图是描述多对多关系的数据结构,由顶点集合V和边集合E组成。每个顶点代表一个实体,边描述实体间的关系。

1.1 图的表示方法

邻接矩阵(稠密图)
 
class GraphMatrix {
private:
    vector<vector<int>> matrix; // 二维数组存储边信息
    int vertexCount;

public:
    GraphMatrix(int n) : vertexCount(n), matrix(n, vector<int>(n, 0)) {}

    void addEdge(int u, int v, int weight = 1) {
        matrix[u][v] = weight;
        matrix[v][u] = weight; // 无向图需双向设置
    }
};
邻接表(稀疏图)
 
struct EdgeNode {
    int adjvex;
    int weight;
    EdgeNode* next;
    EdgeNode(int v, int w) : adjvex(v), weight(w), next(nullptr) {}
};

class GraphList {
private:
    vector<EdgeNode*> adjList;
    int vertexCount;

public:
    GraphList(int n) : vertexCount(n), adjList(n, nullptr) {}

    void addEdge(int u, int v, int weight = 1) {
        EdgeNode* newNode = new EdgeNode(v, weight);
        newNode->next = adjList[u];
        adjList[u] = newNode;
    }
};

二、图的六大核心算法

2.1 广度优先搜索(BFS)

 
void BFS(GraphList& graph, int start) {
    vector<bool> visited(graph.vertexCount, false);
    queue<int> q;
    q.push(start);
    visited[start] = true;

    while (!q.empty()) {
        int u = q.front();
        q.pop();
        cout << u << " ";

        EdgeNode* curr = graph.adjList[u];
        while (curr) {
            if (!visited[curr->adjvex]) {
                visited[curr->adjvex] = true;
                q.push(curr->adjvex);
            }
            curr = curr->next;
        }
    }
}

2.2 深度优先搜索(DFS)

 
void DFS(GraphList& graph, int u, vector<bool>& visited) {
    visited[u] = true;
    cout << u << " ";

    EdgeNode* curr = graph.adjList[u];
    while (curr) {
        if (!visited[curr->adjvex])
            DFS(graph, curr->adjvex, visited);
        curr = curr->next;
    }
}

2.3 Dijkstra最短路径

 
void dijkstra(GraphList& graph, int src) {
    vector<int> dist(graph.vertexCount, INT_MAX);
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;

    dist[src] = 0;
    pq.push({0, src});

    while (!pq.empty()) {
        auto [d, u] = pq.top();
        pq.pop();

        EdgeNode* curr = graph.adjList[u];
        while (curr) {
            if (dist[curr->adjvex] > d + curr->weight) {
                dist[curr->adjvex] = d + curr->weight;
                pq.push({dist[curr->adjvex], curr->adjvex});
            }
            curr = curr->next;
        }
    }
}

2.4 Floyd-Warshall全源最短路径

 
void floydWarshall(GraphMatrix& graph) {
    int n = graph.vertexCount;
    vector<vector<int>> dist = graph.matrix;

    for (int k = 0; k < n; ++k)
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < n; ++j)
                if (dist[i][k] != INT_MAX && dist[k][j] != INT_MAX)
                    dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}

2.5 拓扑排序(Kahn算法)

 
vector<int> topologicalSort(GraphList& graph) {
    vector<int> inDegree(graph.vertexCount, 0);
    queue<int> q;
    vector<int> result;

    // 计算入度
    for (int i = 0; i < graph.vertexCount; ++i) {
        EdgeNode* curr = graph.adjList[i];
        while (curr) {
            inDegree[curr->adjvex]++;
            curr = curr->next;
        }
    }

    // 入队零入度节点
    for (int i = 0; i < graph.vertexCount; ++i)
        if (inDegree[i] == 0) q.push(i);

    while (!q.empty()) {
        int u = q.front();
        q.pop();
        result.push_back(u);

        EdgeNode* curr = graph.adjList[u];
        while (curr) {
            if (--inDegree[curr->adjvex] == 0)
                q.push(curr->adjvex);
            curr = curr->next;
        }
    }

    return result;
}

2.6 最小生成树(Prim算法)

 
void primMST(GraphList& graph) {
    vector<int> key(graph.vertexCount, INT_MAX);
    vector<bool> inMST(graph.vertexCount, false);
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> pq;

    key[0] = 0;
    pq.push({0, 0});

    while (!pq.empty()) {
        int u = pq.top().second;
        pq.pop();

        inMST[u] = true;

        EdgeNode* curr = graph.adjList[u];
        while (curr) {
            if (!inMST[curr->adjvex] && curr->weight < key[curr->adjvex]) {
                key[curr->adjvex] = curr->weight;
                pq.push({key[curr->adjvex], curr->adjvex});
            }
            curr = curr->next;
        }
    }
}

三、高阶算法扩展

3.1 强连通分量(Kosaraju算法)

 
void kosarajuSCC(GraphList& graph) {
    vector<bool> visited(graph.vertexCount, false);
    stack<int> stk;

    // 第一次DFS获取完成顺序
    function<void(int)> fillOrder = [&](int u) {
        visited[u] = true;
        EdgeNode* curr = graph.adjList[u];
        while (curr) {
            if (!visited[curr->adjvex])
                fillOrder(curr->adjvex);
            curr = curr->next;
        }
        stk.push(u);
    };

    // 反转图
    GraphList transposed(graph.vertexCount);
    for (int u = 0; u < graph.vertexCount; ++u) {
        EdgeNode* curr = graph.adjList[u];
        while (curr) {
            transposed.addEdge(curr->adjvex, u, curr->weight);
            curr = curr->next;
        }
    }

    // 第二次DFS按完成顺序处理
    fill(visited.begin(), visited.end(), false);
    while (!stk.empty()) {
        int u = stk.top();
        stk.pop();

        if (!visited[u]) {
            DFS(transposed, u, visited);
            cout << endl;
        }
    }
}

四、复杂度分析

算法时间复杂度空间复杂度
BFS/DFSO(V+E)O(V)
DijkstraO((V+E)logV)O(V)
Floyd-WarshallO(V3)O(V2)
PrimO((V+E)logV)O(V)
KosarajuO(V+E)O(V)

五、应用场景

  • 社交网络:使用BFS查找二度人脉
  • 路径规划:Dijkstra实现最短路径导航
  • 任务调度:拓扑排序检测依赖关系
  • 电路设计:最小生成树优化布线成本

暮乘白帝过重山,期待与的每一次相见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暮乘白帝过重山

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值