鄰接矩陣實現

文章目錄

介紹

  • 學習記錄
  • 定義
    • 使用方陣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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章