数据结构之图(邻接表 稀疏图)

<!DOCTYPE html>
<html>
<head>
    <title>邻接表</title>
    <meta charset="utf-8">
    <script type="text/javascript">
        // 稀疏图  邻接表
        class SparseGraph{
            constructor(n, directed){
                // n为定点数  m为边数
                this.n = n;
                this.m = 0;
                this.directed = directed;
                this.data = new Array();
                for(var i=0; i<n; i++){
                    this.data[i] = new Array();
                }
                // 判断节点是否是访问过得
                this.visited = [];
                // 用来记录从哪个节点 到这个节点的值
                this.from = [];
                // 用来记录从源点到本节点的长度
                this.ord = [];
            }

            V() { return this.n; }
            E() { return this.m; }
            result() { return this.data; }
            // 添加一条边
            addEdge(v,w){
                console.assert( v >= 0 && v < this.n);
                console.assert( w >= 0 && w < this.n );

                // 判断v和w是否有边
                if(this.hasEdge(v, w)){
                    return ;
                }

                this.data[v].push(w);
                if(v!=w && !this.directed){
                    this.data[w].push(v);
                }
                
                this.m++;
            }

            // 判断是否有边
            hasEdge(v, w){
                console.assert( v >= 0 && v < this.n);
                console.assert( w >= 0 && w < this.n )
                
                return (this.data[v].length && this.data[v].indexOf(w) > 0);
            }

            // 图的深度优先遍历
            DFSTraverse(){
                // 给每个节点设置 false(未遍历)
                for(var i=0; i<this.n; i++){
                    this.visited[i] = false;
                }

                for(var i=0; i<this.n; i++){
                    if(!this.visited[i]){
                        // console.log(i)
                        this.DFS(i)
                    }
                }
            }

            DFS(v){
                // 第v个顶点 应该是访问过的
                
                this.visited[v] = true;
                console.log(v)

                for(var w = this.FirstAdjVex(v); w >= 0; w = this.NextAdjVex(v, w)){
                    // 如果v中的相邻节点没有遍历的话  那么就在遍历这个节点中的相邻节点
                    if(!this.visited[w]){
                        // 记录从哪个节点遍历 到这
                        this.from[w] = v;
                        this.visited[w] = true;
                        console.log(w)
                        // 获得w中 第一个未遍历的元素
                        var x = this.FirstFlase(w);
                        if(x >=0){
                            // 这个是由于 要走w的第一个元素 故要记录 x的前一个是w
                            this.from[x] = w;
                            this.DFS(x)
                        }
                        
                    }
                }
            }

            // 获得w中的第一个未遍历的元素
            FirstFlase(w){
                if(this.data[w]){
                    for(var i=0; i<this.data[w].length; i++){
                        if(!this.visited[this.data[w][i]]){
                            return this.data[w][i];
                        }
                    }
                }
                return -1;
            }

            // 图的 广度优先遍历
            BFSTraverse(){
                // 给每个节点设置 false (未遍历)
                for(var i=0; i<this.n; i++){
                    this.visited[i] = false;
                }

                // 这个循环是 为了解决图 有多个联通分量  问题
                for(var i=0; i<this.n; i++){
                    if(!this.visited[i]){
                        // 实现一个队列 来广度遍历图
                        this.visited[i] = true;
                        // 把源点的长度记录为0  如果是多个联通分量,初始的节点的长度也是0
                        this.ord[i] = 0;
                        var res = []
                        res.push(i);
                        var node = null;
                        while(node != null || res.length>0){
                            var node = res.shift()
                            if(node != null){
                                console.log(node)
                            }
                            
                            for(var w = this.FirstAdjVex(node); w >= 0; w = this.NextAdjVex(node, w)){
                                // 如果v中的相邻节点没有遍历的话  那么就在遍历这个节点中的相邻节点
                                if(!this.visited[w]){
                                    // 如果w 未遍历 则标志改变 且加入res中
                                    this.visited[w] = true;
                                    this.from[w] = node;
                                    // 这个节点到源点的长度 等于它上个节点的长度 +1
                                    this.ord[w] = this.ord[node] + 1;
                                    res.push(w);
                                }
                            }
                        }
                    }
                }
                
            }

            // 深度遍历 获得任意节点的路径
            DFSPath(v, w){
                // v -> w 的路径
                this.DFSTraverse();

                return this.Path(v, w);
            }
            // 广度优先遍历 获得两节点之间的路径
            BFSPath(v, w){
                // 广度遍历
                this.BFSTraverse();
                return this.Path(v, w);
            }

            //

            Path(v, w){
                // 存储路径
                var ww = w;
                var res = []

                while(v != w){
                    res.push(this.from[w])
                    w = this.from[w]
                }
                res.reverse().push(ww);
                res = res.join(" -> ");

                return res;
            }

            // 获得v 的 第一个连接的节点
            FirstAdjVex(v){

                // 检测this.data[v]是否存在
                if(this.data[v]){
                    var len = this.data[v].length;
                
                    if(len > 0){
                        var sum = this.data[v][0];
                        return sum;
                    }
                }
                
                return -1;
            }

            // 获得v的下一个连接的节点
            NextAdjVex(v, w){
                for(var i=0; i<this.data[v].length; i++){
                    if(this.data[v][i] == w){
                        //判断v中的邻接表w的下一个节点 是否存在
                        return this.data[v][i+1] ? this.data[v][i+1] : -1;
                    }
                }
                return -1;
            }
        }


        var sGraph = new SparseGraph(7, false);

        var wdata = [[0, 1], [0, 2], [0, 5], [0, 6], [3, 4], [3, 5], [4, 5], [4, 6]]
        for(var i=0; i<wdata.length; i++){
            sGraph.addEdge(wdata[i][0], wdata[i][1]);
        }
        console.log(sGraph.result())
        //sGraph.BFSTraverse();
           //sGraph.DFSTraverse()

           console.log(sGraph.from)

           console.log(sGraph.BFSPath(0, 6))
        
    </script>
</head>
<body>

</body>
</html>

猜你喜欢

转载自blog.csdn.net/qq_39081958/article/details/82762938