用STL存储邻接链表

图的存储最常见的方式是邻接链表和邻接矩阵存储. 邻接矩阵和邻接链表具体是什么这里就不多说了. 由于项目需要, 我需要实现一个能够自动查重的邻接链表, 即不能插入重复结点的邻接链表. 考虑到”不能重复”这一特点, 如果使用stl容器的话, 非map/set/hashmap/hashset莫属. 多的不说, 上代码:

一. 顶点类的定义

enum State
{
    WHITE, GRAY, BLACK
};
extern struct Edge;
typedef set<Edge> AdjVerticeSet;
struct Vertice
{
    AdjVerticeSet adjacentVertices;
    int id;
    State color;
    unsigned int begin; // dfs或bfs发现节点的时间
    unsigned int end;   // dfs完成访问的时间
    int distance;       // 记录最短路径
    Vertice(int _id = 0) :id(_id), color(WHITE), begin(0), end(0), adjacentVertices(AdjVerticeSet()),distance(1){}
    void addEdge(Vertice* target);
};
typedef pair<int, Vertice*> Node;
typedef map<int, Vertice*> VerticeSet;

对顶点添加边

void Vertice::addEdge(Vertice* target)
{
    Edge e = Edge(target);
    adjacentVertices.insert(e);
}

二. 边节点的定义

extern struct Vertice;
struct Edge {
    int weight;
    Vertice* target;
    Edge(Vertice* _target, int _weight = 1) :target(_target), weight(_weight){}
    bool operator<(const Edge& another) const
    {
        return target - another.target < 0;
    }
    bool operator==(const Edge& another) const
    {
        return target - another.target == 0;
    }
    bool operator>(const Edge& another) const
    {
        return target - another.target > 0;
    }
};

三. 邻接链表的封装类

class Graph
{
private:
    // 出度邻接链表
    VerticeSet allVertices;

#pragma region 内存管理
public:
    Graph()
    {
        allVertices = VerticeSet();
    }
    ~Graph(){
        for (auto n : allVertices)
        {
            delete n.second;
        }
    }
#pragma endregion 内存管理
private:
    void dfs_visit(Vertice* n, int& timestamp);
public:
    void dfs();
    void appendEdge(int id_a, int id_b, int weight=1);
    void appendUndirectedEdge(int id_a, int id_b, int weight = 1)
    {
        appendEdge(id_a, id_b, weight);
        appendEdge(id_b, id_a, weight);
    }
    void display();
    bool bellmanFord(int source_id);
    Vertice* operator[](int id)
    {
        if (allVertices.count(id)>0)
            return allVertices.find(id)->second;
        else return NULL;
    }
    
    void dijkstra(int source_id);
};

typedef map<Vertice*, int> ResultList;
typedef pair<Vertice*, int> ResultPair;

向邻接链表添加边:

void Graph::appendEdge(int id_a, int id_b, int weight)
{
    if (allVertices.count(id_a) == 0)
        allVertices.insert(Node(id_a, new Vertice(id_a)));
    if (allVertices.count(id_b) == 0)
        allVertices.insert(Node(id_b, new Vertice(id_b)));
    Vertice* va = allVertices.find(id_a)->second;
    Vertice* vb = allVertices.find(id_b)->second;
    va->adjacentVertices.insert(Edge(vb,weight));
}

转载于:https://www.cnblogs.com/roy-mustango/p/4224592.html

下面是使用Dijkstra算法以邻接链表的形式实现最短路径的示例代码: ```cpp #include <iostream> #include <vector> #include <queue> #include <limits.h> using namespace std; // 邻接链表中的边结构体 struct Edge { int to; // 目标节点 int weight; // 边权重 Edge(int t, int w): to(t), weight(w) {} }; // 邻接链表中的节点结构体 struct Node { int id; // 节点编号 int distance; // 起点到该节点的最短距离 vector<Edge> edges; // 与该节点相连的边 bool operator<(const Node& other) const { // 定义小于运算符,用于优先队列中 return distance > other.distance; } }; // 计算起点到所有节点的最短路径 vector<int> dijkstra(vector<Node>& graph, int start) { vector<int> distances(graph.size(), INT_MAX); // 起点到每个节点的最短距离 distances[start] = 0; // 起点到自己的距离为0 priority_queue<Node> pq; pq.push({start, 0, graph[start].edges}); while (!pq.empty()) { Node node = pq.top(); pq.pop(); if (distances[node.id] < node.distance) continue; // 优化1:如果已经处理过该节点,则忽略 distances[node.id] = node.distance; for (Edge edge : node.edges) { int newDist = node.distance + edge.weight; if (newDist < distances[edge.to]) { pq.push({edge.to, newDist, graph[edge.to].edges}); distances[edge.to] = newDist; } } } return distances; } int main() { int n, m; cin >> n >> m; vector<Node> graph(n); for (int i = 0; i < m; i++) { int u, v, w; cin >> u >> v >> w; graph[u].edges.push_back({v, w}); graph[v].edges.push_back({u, w}); } vector<int> distances = dijkstra(graph, 0); for (int i = 0; i < n; i++) { cout << "Distance from 0 to " << i << " is " << distances[i] << endl; } return 0; } ``` 在上述代码中,我们首先定义了邻接链表中的边和节点结构体,然后实现了计算起点到所有节点的最短路径的dijkstra函数。在函数中,我们使用一个优先队列来保存待处理的节点,并根据节点与起点的距离从小到大排序。在每次处理队首节点时,我们更新与该节点相连的所有节点的最短距离,并将它们加入优先队列中。在处理完所有节点后,我们返回起点到所有节点的最短距离。 在main函数中,我们首先读取输入的节点数量和边数量,并根据输入构造邻接链表。然后调用dijkstra函数,计算起点到所有节点的最短距离,并输出结果。 需要注意的是,由于STL中的优先队列使用堆实现,每次插入和删除元素的时间复杂度为O(log n),因此总时间复杂度为O((m + n) log n),其中m为边数,n为节点数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值