Bootstrap

邻接矩阵实现

文章目录

介绍

  • 学习记录
  • 定义
    • 使用方阵A[n][n]表示n个顶点之间构成的图,其中每个单元负责对一对顶点之间邻接关系进行描述
  • 缺点
    • 方阵可以描述所有可能存在的边的关系, 但是实际问题边并没有出现那么多,浪费了大量的空间; 可以使用A[n] = LIST代替(邻接列表),列表中只存放当前节点一定存在的邻接顶点

实现

//
// Created by carso on 2020/3/14.
//

#ifndef C___GRAPMATRIX_H
#define C___GRAPMATRIX_H

#include <Graph.h>
#include <Vector.h>
#include <limits.h>

// 定义顶点
template<typename Tv>
struct Vertex {
    Tv data; // 数据
    int inDegree, outDegree, // 入度,出度
            VStatus
    status; // 状态 未发现,发现,访问
    int dTime, fTime; // 时间标签 (用来算法判断边类型)
    int parent; // 遍历树中的父级顶点
    int priority; // 遍历树中的优先级

    // 构造函数
    Vertex(Tv const &d = (Tv) 0) : data(d), inDegree(0), outDegree(0), status(UNDETERMINED),
                                   dTime(-1), fTime(-1), parent(-1), priority(INT_MAX) {}

};

// 定义边
template<typename Te>
struct Edge {
    Te data; // 数据
    int weight; //权重
    EType type; // 边类型

    // 构造函数
    Edge(Te const &d, int w) : data(d), weight(w), type(UNDETERMINED) {}
};

// 定义邻接矩阵
template<typename Tv, typename Te>
class GraphMatrix : public Graph {
private:
    // 顶点集(向量)
    Vector <Vertex<Tv>> V;

    // 边集合 (邻接矩阵)
    Vector <Vector<Edge<Te> *>> E;

public:
    // 构造函数
    GraphMatrix() { n = e = 0 }

    // 析构函数
    ~GraphMatrix() {
        // 删除所有边
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < n; ++j) {
                delete E[i][j];
            }
            delete V[i];
        }
    }

    // 顶点操作
    // 返回特定顶点的数据
    virtual Tv &vertex(int i) { return V[i].data; }

    // 入度
    virtual int inDegree(int i) {
        return V[i].inDegree;
    }

    // 出度
    virtual int outDegree(int i) {
        return V[i].outDegree;
    }

    // 首个邻接顶点
    virtual int firstNbr(int i) {
        return nextNbr(i, n);
    }

    // 下一个邻接顶点, 注意不包含下标j
    virtual int nextNbr(int i, int j) {
        while (j > -1 && !exist(i, --j)) {}
        return j;
    }

    // 状态
    virtual VStatus &status(int i) { return V[i].status; }

    // 时间标签
    virtual int &dTime(int i) {
        return V[i].dTime;
    }

    virtual int &fTime(int i) {
        return V[i].fTime;
    }

    // 在遍历树中父节点
    virtual int &parent(int i) { return V[i].parent; }

    // 遍历树中的优先级
    virtual int &priority(int i) {
        return V[i].priority;
    }

    // 顶点动态操作
    // 插入顶点,返回编号
    virtual int insert(Tv const &vertex) {
        // 各个顶点预留一条潜在的关联边
        for (int i = 0; i < n; ++i) {
            E[i].insert(NULL);
        }

        // 总顶点数+1
        n++;
        // 创建新边
        Vector < Edge<Te> * > newEdgePoint = new Vector(n, n, (Edge<Te> *) NULL);
        E.insert(newEdgePoint);

        // 顶点向量增加一个顶点
        return V.insert(Vertex(vertex));
    }

    // 删除顶点和关联边
    virtual Tv remove(int i) {
        // 删除可能存在的边
        for (int j = 0; j < n; ++j) {
            if (exists(i, j)) {
                delete E[i][j];
                V[j].inDegree--;
            }
        }

        E.remove(i);
        n--;

        // 删除顶点
        Tv vBak = V.remove(i);

        // 删除所有的入边
        for (int k = 0; k < n; ++k) {
            if (Edge(Te) * e = E[k].remove(i)) {
                delete e;
                V[k].outDegree--;
            }
        }

        return vBak;
    }

    // 边操作
    // 边(i,j)是否存在
    virtual bool exists(int i, int j) {
        return i > 0 && j > 0 && i < n && j < n && (E[i][j] != NULL);
    }

    // 边的类型
    virtual EType &type(int i, int j) {
        return E[i][j]->type;
    }

    // 边的数据
    virtual Te &edge(int i, int j) {
        return E[i][j]->data;
    }

    // 边的权重
    virtual int &weight(int i, int j) {
        return E[i][j]->weight;
    }

    // 插入操作
    virtual void insert(Te const &edge, int w, int i, int j) {
        // 如果边已经存在
        if (exists(i, j)) {
            return;
        }

        // 创建新边
        E[i][j] = new Edge(edge, w);

        e++;
        V[i].outDegree++;
        V[J].inDegree++;
    }

    // 边删除操作
    virtual Te remove(int i, int j) {
        // 边不存在
        if (!exists(i, j)) {
            return;
        }

        Te edge = edge(i, j);

        // 删除边
        delete E[i][j];

        // 维持空边
        E[i][j] = NULL;

        // 出度入度
        V[i].outDegree--;
        V[j].inDegree--;

        // 边数
        e--;
        return edge;
    }
};


#endif //C___GRAPMATRIX_H

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;