图论 C++实现 笔记2-有权图

32 阅读4分钟

有权图 邻接矩阵

image.png

有权图 邻接表

image.png

有权图 邻接矩阵实现

edge.h 关于边的权重模板类

#ifndef WEIGHT_GRAPH_EDGE_HEAD
#define WEIGHT_GRAPH_EDGE_HEAD

#include <iostream>
#include <cassert>

using namespace std;

// 模板类
template <typename Weight>
class Edge
{
private:
    int from, to; // 边的两个顶点
    Weight w;     // 权重
public:
    Edge() {}
    Edge(int from, int to, Weight w) : from(from), to(to), w(w) {}
    ~Edge() {}
    int getFrom() { return from; }
    int getTo() { return to; }
    Weight getW() { return w; }
    // 获取边的另一个顶点
    int getOtherV(int v)
    {
        assert(v == from || v == to);
        return v == from ? to : from;
    }
    // 操作符的重载
    friend ostream &operator<<(ostream &os, const Edge &e)
    {
        os << e.from << "-" << e.to << ":" << e.w;
        return os;
    }
    bool operator<(Edge<Weight> &other_e) { return w < other_e.getW(); }
    bool operator<=(Edge<Weight> &other_e) { return w <= other_e.getW(); }
    bool operator>(Edge<Weight> &other_e) { return w > other_e.getW(); }
    bool operator>=(Edge<Weight> &other_e) { return w >= other_e.getW(); }
    bool operator==(Edge<Weight> &other_e) { return w == other_e.getW(); }
};

#endif

weight_dense_graph.h

#ifndef WEIGHT_DENSE_GRAPH_HEAD
#define WEIGHT_DENSE_GRAPH_HEAD

#include <iostream>
#include <vector>
#include <cassert>
#include "edge.h"

using namespace std;

// 有权图 邻接矩阵
template <typename Weight>
class WeightDenseGraph
{
private:
    int vertices;                   // 点的数量
    int edges;                      // 边的数量
    bool directed;                  // 是否为有向图
    vector<vector<Edge<Weight> *> > g; // 否则编译器会误以为是 >>
public:
    WeightDenseGraph(int v, bool d) : vertices(v), directed(d)
    {
        this->edges = 0;
        // n * n 的矩阵
        for (int i = 0; i < vertices; i++)
        {
            vector<Edge<Weight> *> vec(vertices, NULL);
            g.push_back(vec);
            // g.push_back(vector<Edge<Weight>*>(vertices, NULL));
        }
    }
    ~WeightDenseGraph()
    {
        for (int i = 0; i < vertices; i++)
            for (int j = 0; j < vertices; j++)
                if (g[i][j] != NULL)
                    delete (g[i][j]);
    }
    int V() { return vertices; }
    int E() { return edges; }
    void addEdge(int v1, int v2, Weight w);
    bool hasEdge(int v1, int v2);
    void show();

    // 迭代器
    class adjIterator
    {
    private:
        WeightDenseGraph &G;
        int v;
        int index;

    public:
        adjIterator(WeightDenseGraph &graph, int v);
        Edge<Weight> *begin();
        Edge<Weight> *next();
        bool end();
    };
};

template <typename Weight>
void WeightDenseGraph<Weight>::addEdge(int v1, int v2, Weight w)
{
    assert(v1 >= 0 && v1 < vertices);
    assert(v2 >= 0 && v2 < vertices);
    if (hasEdge(v1, v2))
    {
        delete g[v1][v2];
        if (!directed)
        {
            delete g[v2][v1];
        }
        edges--;
    }
    g[v1][v2] = new Edge<Weight>(v1, v2, w);
    if (!directed)
    {
        // 无向图
        g[v2][v1] = new Edge<Weight>(v2, v1, w);
    }
    edges++;
}

template <typename Weight>
bool WeightDenseGraph<Weight>::hasEdge(int v1, int v2)
{
    assert(v1 >= 0 && v1 < vertices);
    assert(v2 >= 0 && v2 < vertices);
    return g[v1][v2] != NULL;
}

template <typename Weight>
void WeightDenseGraph<Weight>::show()
{
    for (int i = 0; i < vertices; i++)
    {
        for (int j = 0; j < vertices; j++)
            if (g[i][j] != NULL)
                cout << g[i][j]->getW() << "\t";
            else
                cout << "NULL"
                     << "\t";
        cout << endl;
    }
}

template <typename Weight>
WeightDenseGraph<Weight>::adjIterator::adjIterator(WeightDenseGraph &graph, int v) : G(graph)
{
    this->v = v;
    this->index = NULL;
}

template <typename Weight>
Edge<Weight> *WeightDenseGraph<Weight>::adjIterator::begin()
{
    index = -1;
    return next();
}

template <typename Weight>
Edge<Weight> *WeightDenseGraph<Weight>::adjIterator::next()
{
    for (index += 1; index < G.V(); index++)
        if (G.g[v][index] != NULL)
            return G.g[v][index];
    return NULL;
}

template <typename Weight>
bool WeightDenseGraph<Weight>::adjIterator::end()
{
    return index >= G.V();
}
#endif

有权图 邻接表实现

weight_sparse_graph.h

#ifndef WEIGHT_SPARSE_GRAPH_HEAD
#define WEIGHT_SPARSE_GRAPH_HEAD

#include <iostream>
#include <vector>
#include <cassert>
#include "edge.h"

using namespace std;

// 有权图 邻接表
template <typename Weight>
class WeightSparseGraph
{
private:
    int vertices;                     // 点的数量
    int edges;                        // 边的数量
    bool directed;                    // 是否为有向图
    vector<vector<Edge<Weight> *> > g; // 否则编译器会误以为是 >>
public:
    WeightSparseGraph(int v, bool d) : vertices(v), directed(d)
    {
        this->edges = 0;
        for (int i = 0; i < vertices; i++)
            g.push_back(vector<Edge<Weight> *>()); // 初始化每个顶点的邻接点
    }
    ~WeightSparseGraph()
    {
        for (int i = 0; i < vertices; i++)
            for (int j = 0; j < g[i].size(); j++)
                if (g[i][j] != NULL)
                    delete (g[i][j]);
    }
    int V() { return vertices; }
    int E() { return edges; }
    void addEdge(int v1, int v2, Weight w);
    bool hasEdge(int v1, int v2);
    void show();

    // 迭代器
    class adjIterator
    {
    private:
        WeightSparseGraph &G;
        int v;
        int index;

    public:
        adjIterator(WeightSparseGraph &graph, int v);
        Edge<Weight> *begin();
        Edge<Weight> *next();
        bool end();
    };
};

template <typename Weight>
void WeightSparseGraph<Weight>::addEdge(int v1, int v2, Weight w)
{
    assert(v1 >= 0 && v1 < vertices);
    assert(v2 >= 0 && v2 < vertices);
    // 稀疏图不处理平行边问题
    g[v1].push_back(new Edge<Weight>(v1, v2, w));
    if (!directed && v1 != v2)
        g[v2].push_back(new Edge<Weight>(v2, v1, w));
    edges++;
}

template <typename Weight>
bool WeightSparseGraph<Weight>::hasEdge(int v1, int v2)
{
    assert(v1 >= 0 && v1 < vertices);
    assert(v2 >= 0 && v2 < vertices);
    for (int i = 0; i < g[v1].size(); i++)
    {
        if (g[v1][i]->getOtherV() == v2)
            return true;
    }
    return false;
}

template <typename Weight>
void WeightSparseGraph<Weight>::show()
{
    for (int i = 0; i < vertices; i++)
    {
        cout << "vertex" << i << ":\t";
        for (int j = 0; j < g[i].size(); j++)
            cout << "( to:" << g[i][j]->getTo() << ", weight:" << g[i][j]->getW() << " )\t";
        cout << endl;
    }
}

template <typename Weight>
WeightSparseGraph<Weight>::adjIterator::adjIterator(WeightSparseGraph<Weight> &graph, int v) : G(graph)
{
    this->index = 0;
    this->v = v;
}

template <typename Weight>
Edge<Weight> *WeightSparseGraph<Weight>::adjIterator::begin()
{
    index = 0;
    if (G.g[v].size())
        return G.g[v][index];
    return NULL;
}

template <typename Weight>
Edge<Weight> *WeightSparseGraph<Weight>::adjIterator::next()
{
    index++;
    if (index < G.g[v].size())
        return G.g[v][index];
    return NULL;
}

template <typename Weight>
bool WeightSparseGraph<Weight>::adjIterator::end()
{
    return index >= G.g[v].size();
}
#endif

读取文件构建有权图

weight_read_graph.h

#ifndef WEIGTH_READ_GRAPH_HEAD
#define WEIGTH_READ_GRAPH_HEAD

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <cassert>
#include "edge.h"

using namespace std;

template <typename Graph, typename Weight>
class WeightReadGraph
{
public:
    WeightReadGraph(Graph &g, const string &file_name)
    {
        ifstream file(file_name);
        string line;
        int V, E;
        assert(file.is_open());
        assert(getline(file, line));
        stringstream ss(line);
        ss >> V >> E;
        assert(V == g.V());
        for (int i = 0; i < E; i++)
        {
            assert(getline(file, line));
            stringstream ss(line);
            int v1, v2;
            Weight w;
            ss >> v1 >> v2 >> w;
            assert(v1 >= 0 && v1 < V);
            assert(v2 >= 0 && v2 < V);
            g.addEdge(v1, v2, w);
        }
    }
};

#endif

测试用例

graph_data3.txt

8 16
4 5 .35
4 7 .34
5 7 .25
0 7 .65
1 5 .78
0 4 .23
2 3 .98
1 7 .12
0 2 .02
1 2 .65
1 3 .36
2 7 .69
6 2 .55
3 6 .33
6 0 .86
6 4 .99
#include <iostream>
#include "weight_dense_graph.h"
#include "weight_sparse_graph.h"
#include "weight_read_graph.h"

using namespace std;

void testcase11()
{
    int V = 8;
    cout << fixed << setprecision(2);
    string file_name = "graph_data3.txt";
    WeightDenseGraph<double> wdg(8, false);
    WeightReadGraph<WeightDenseGraph<double>, double> readGraph(wdg, file_name);
    wdg.show();
}

void testcase12()
{
    int V = 8;
    cout << fixed << setprecision(2);
    string file_name = "graph_data3.txt";
    WeightSparseGraph<double> wsg(8, false);
    WeightReadGraph<WeightSparseGraph<double>, double> readGraph(wsg, file_name);
    wsg.show();
}

// g++ main.cpp && ./a.out
// g++ main.cpp -o maincpp.out && ./maincpp.out
int main()
{
    testcase12();
    return 0;
}