JS Graph (圖-數據結構)

Code:

/**
 * 基於鄰接表實現的無向圖
 * @class
 */
class GraphAdjList {
    /**
     * @type {Map<any, any[]>}
     */
    adjList;

    /**
     * 構造函數
     * @constructor
     * @param {[any, any][]} edges 
     */
    constructor(edges) {
        this.adjList = new Map();
        /**
         * 初始化現有的頂點與邊
         */
        for (const [e1, e2] of edges) {
            this.addVertex(e1);
            this.addVertex(e2);
            this.addEdge(e1, e2);
        }
    }

    /**
     * 獲取頂點數量
     * @returns 
     */
    size() {
        return this.adjList.size;
    }

    /**
     * 添加頂點
     * @param vet 
     * @returns 
     */
    addVertex(vet) {
        //// 如果該頂點已經存在
        if (this.adjList.has(vet)) {
            return;
        }
        // 在鄰接表中添加一個新鏈表
        this.adjList.set(vet, []);
    }

    /**
     * 刪除頂點
     * @param vet 
     */
    removeVertex(vet) {
        if (!this.adjList.has(vet)) {
            throw new Error('Illegal Argument Exception');
        }
        // 刪除該頂點所對應的鏈表
        this.adjList.delete(vet);
        // 刪除其他頂點與該頂點形成的“邊”
        const values = this.adjList.values();
        for (const arr of values) {
            const idx = arr.indexOf(vet);
            if (idx > -1) {
                arr.splice(idx, 1);
            }
        }
    }

    /**
     * 添加邊
     * @param v1 
     * @param v2 
     */
    addEdge(v1, v2) {
        if (!this.adjList.has(v1) || !this.adjList.has(v2) || v1 === v2) {
            throw new Error('Illegal Argument Exception');
        }
        // 連接v1-v2,形成新的邊
        this.adjList.get(v1).push(v2);
        this.adjList.get(v2).push(v1);
    }

    /**
     * 刪除邊
     * @param v1 
     * @param v2 
     */
    removeEdge(v1, v2) {
        if (!this.adjList.has(v1) || !this.adjList.has(v2) || v1 === v2) {
            throw new Error('Illegal Argument Exception');
        }
        const v1Idx = this.adjList.get(v2).indexOf(v1);
        const v2Idx = this.adjList.get(v1).indexOf(v2);
        this.adjList.get(v1).splice(v2Idx, 1);
        this.adjList.get(v2).splice(v1Idx, 1);
    }

    // 打印鏈表
    print() {
        console.log('鄰接表 =');
        for (const [key, value] of this.adjList) {
            const valList = [];
            for (const piece of value) {
                valList.push(piece);
            }
            console.log(key + ':' + valList.toString());
        }
    }
}

 

/**
 * 基於鄰接矩陣實現的無向圖
 * @class
 */
class GraphAdjMat {
    /**
     * 頂點列表(元素代表頂點值,元素索引代表頂點索引)
     * @type {any[]}
     */
    vertices;
    /**
     * 鄰接矩陣(行列索引代表頂點索引)
     * @type {any[][]}
     */
    adjMat;

    /**
     * 構造器
     * @constructor
     * @param {any[]} vertices 
     * @param {[number, number][]} edges 
     */
    constructor(vertices, edges) {
        this.vertices = [];
        this.adjMat = [];
        // 添加頂點
        for (const val of vertices) {
            this.addVertex(val);
        }
        // 添加邊
        for (const [x, y] of edges) {
            this.addEdge(x, y);
        }
    }

    /**
     * 頂點數量
     * @returns 
     */
    size() {
        return this.vertices.length;
    }

    /**
     * 添加頂點
     * @param {any} val 
     */
    addVertex(val) {
        const n = this.size();
        this.vertices.push(val);
        // 添加行
        const newRow = [];
        for (let i = 0; i < n; i++) {
            newRow.push(0);
        }
        this.adjMat.push(newRow);
        // 添加列
        for (const row of this.adjMat) {
            row.push(0);
        }
    }

    /**
     * 刪除頂點
     * @param {number} index 
     */
    removeVertex(index) {
        if (index >= this.size()) {
            throw new RangeError('Index Out Of Bounds Exception');
        }
        this.vertices.splice(index, 1);
        // 刪除行
        this.adjMat.splice(index, 1);
        // 刪除列
        for (const row of this.adjMat) {
            row.splice(index, 1);
        }
    }

    /**
     * 添加邊
     * @param {number} i 
     * @param {number} j 
     */
    addEdge(i, j) {
        // 處理邊界條件
        if (i < 0 || j < 0 || i >= this.size() || j >= this.size() || i === j) {
            throw new RangeError('Index Out Of Bounds Exception');
        }
        this.adjMat[i][j] = 1;
        this.adjMat[j][i] = 1;
    }

    /**
     * 刪除邊
     * @param {number} i 
     * @param {number} j 
     */
    removeEdge(i, j) {
        if (i < 0 || j < 0 || i >= this.size() || j >= this.size() || i === j) {
            throw new RangeError('Index Out Of Bounds Exception');
        }
        this.adjMat[i][j] = 0;
        this.adjMat[j][i] = 0;
    }
}

 

圖的遍歷操作

Code: 

function bfsGraph(graph, startVet) {
    const ans = [];
    const vis = new Set();
    vis.add(startVet);
    const q = [startVet];

    while (q.length > 0) {
        const vet = q.shift();
        ans.push(vet);
        const adjList = graph.adjList.get(vet) ?? []
        for (const adjVet of adjList) {
            if (vis.has(adjVet)) {
                continue;
            }
            q.push(adjVet);
            vis.add(adjVet);
        }
    }

    return ans;
}

 

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