数据结构-图

图的术语:

度:一个顶点的度是相邻顶点的数量
简单路径:简单路径要求不包含重复的顶点
回路:第一个顶点和最后一个顶点相同的路径称为回路
带权图:带权图表示边有一定的权重
无权图:边没有携带权重
邻接矩阵:
邻接矩阵让每个节点和一个整数相关联,整数作为数组的下标值。可以用二维数组来表示顶点之间的连接
在这里插入图片描述
邻接矩阵有一个比较严重的问题,如果图是稀疏图,那么矩阵中将存在大量的0,这就意味着我们浪费了计算机存储空间来表示不存在的边。
邻接表:
邻接表由每个顶点和顶点相邻的顶点列表组成。
在这里插入图片描述
邻接表计算出度比较简单,计算入度比较麻烦(出度:指向别人的数量。入度:指向自己的数量)

图的遍历

图的遍历意味着需要将图中每个顶点访问一遍,并且不能有重复的访问。
广度优先搜索(Breadth-First Search, 简称BFS)
深度优先搜索(Depth-First Search, 简称DFS)
两种遍历算法,都需要明确指定第一个被访问的顶点
用white表示节点没有被访问过
用gray表示节点被访问过,但与之相邻的节点没有被访问完
用black表示节点被访问过且与之相邻的节点都被访问完了

<body>
<script src="./dict.js"></script>
<script src="./queue.js"></script>
<script>
    function Graph() {
        // 属性
        this.vertexes = [] // 存储顶点
        this.adjList = new Dictionay() // 存储边

        // 添加方法
        Graph.prototype.addVertex = function (v) {
            this.vertexes.push(v)
            this.adjList.set(v, [])
        }

        Graph.prototype.addEdge = function (v1, v2) {
            this.adjList.get(v1).push(v2)
            this.adjList.get(v2).push(v1)
        }

        Graph.prototype.toString = function () {
            var resultStr = ""
            for (var i = 0; i < this.vertexes.length; i++) {
                resultStr += this.vertexes[i] + "->"
                var adj = this.adjList.get(this.vertexes[i])
                for (var j = 0; j < adj.length; j++) {
                    resultStr += adj[j] + " "
                }
                resultStr += "\n"
            }
            return resultStr
        }

        // 初始化颜色
        Graph.prototype.initializeColor = function () {
            var colors = []
            for (var i = 0; i < this.vertexes.length; i++) {
                colors[this.vertexes[i]] = "white"
            }
            return colors
        }

        // 广度优先算法
        Graph.prototype.bfs = function (v, handler) {
            // 1.初始化颜色
            var color = this.initializeColor()

            // 2.创建队列
            var queue = new Queue()

            // 3.将传入的顶点放入队列中
            queue.enqueue(v)

            // 4.从队列中依次取出和放入数据
            while (!queue.isEmpty()) {
                // 4.1.从队列中取出数据
                var qv = queue.dequeue()

                // 4.2.获取qv相邻的所有顶点
                var qAdj = this.adjList.get(qv)

                // 4.3.将qv的颜色设置成灰色
                color[qv] = "gray"

                // 4.4.将qAdj的所有顶点依次压入队列中
                for (var i = 0; i < qAdj.length; i++) {
                    var a = qAdj[i]
                    if (color[a] === "white") {
                        color[a] = "gray"
                        queue.enqueue(a)
                    }
                }

                // 4.5.因为qv已经探测完毕, 将qv设置成黑色
                color[qv] = "black"

                // 4.6.处理qv
                if (handler) {
                    handler(qv)
                }
            }
        }

        // 深度优先搜索
        Graph.prototype.dfs = function (handler) {
            // 1.初始化颜色
            var color = this.initializeColor()

            // 2.遍历所有的顶点, 开始访问
            for (var i = 0; i < this.vertexes.length; i++) {
                if (color[this.vertexes[i]] === "white") {
                    this.dfsVisit(this.vertexes[i], color, handler)
                }
            }
        }

        // dfs的递归调用方法
        Graph.prototype.dfsVisit = function (v, color, handler) {
            // 1.将v的颜色设置为灰色
            color[v] = "gray"

            // 2.处理v顶点
            if (handler) {
                handler(v)
            }

            // 3.v的所有邻接顶点的访问
            var vAdj = this.adjList.get(v)
            for (var i = 0; i < vAdj.length; i++) {
                var w = vAdj[i]
                if (color[w] === "white") {
                    this.dfsVisit(w, color, handler)
                }
            }

            // 4.将v设置为黑色
            color[v] = "black"
        }
    }

    // 测试代码
    var graph = new Graph()

    // 添加顶点
    var myVertexes = ["A", "B", "C", "D", "E", "F", "G", "H", "I"]
    for (var i = 0; i < myVertexes.length; i++) {
        graph.addVertex(myVertexes[i])
    }

    // 添加边
    graph.addEdge('A', 'B');
    graph.addEdge('A', 'C');
    graph.addEdge('A', 'D');
    graph.addEdge('C', 'D');
    graph.addEdge('C', 'G');
    graph.addEdge('D', 'G');
    graph.addEdge('D', 'H');
    graph.addEdge('B', 'E');
    graph.addEdge('B', 'F');
    graph.addEdge('E', 'I');

    // 打印结果
    alert(graph)

    // 调用广度优先算法
    var result = ""
    graph.bfs(graph.vertexes[0], function (v) {
        result += v + " "
    })
    alert(result) // A B C D E F G H I

    // 调用深度优先算法
    result = ""
    graph.dfs(function (v) {
        result += v + " "
    })
    alert(result) // A B E I F C D G H
 </script>

dict.js

// 创建字典的构造函数
function Dictionay() {
    // 字典属性
    this.items = {}

    // 字典操作方法
    // 在字典中添加键值对
    Dictionay.prototype.set = function (key, value) {
        this.items[key] = value
    }

    // 判断字典中是否有某个key
    Dictionay.prototype.has = function (key) {
        return this.items.hasOwnProperty(key)
    }

    // 从字典中移除元素
    Dictionay.prototype.remove = function (key) {
        // 1.判断字典中是否有这个key
        if (!this.has(key)) return false

        // 2.从字典中删除key
        delete this.items[key]
        return true
    }

    // 根据key去获取value
    Dictionay.prototype.get = function (key) {
        return this.has(key) ? this.items[key] : undefined
    }

    // 获取所有的keys
    Dictionay.prototype.keys = function () {
        return Object.keys(this.items)
    }

    // 获取所有的value
    Dictionay.prototype.values = function () {
        return Object.values(this.items)
    }

    // size方法
    Dictionay.prototype.size = function () {
        return this.keys().length
    }

    // clear方法
    Dictionay.prototype.clear = function () {
        this.items = {}
    }
}

queue.js

// 自定义队列
function Queue() {
    var items = []

    // 队列操作的方法
    // enter queue方法
    this.enqueue = function (element) {
        items.push(element)
    }

    // delete queue方法
    this.dequeue = function () {
        return items.shift()
    }

    // 查看前端的元素
    this.front = function () {
        return items[0]
    }

    // 查看队列是否为空
    this.isEmpty = function () {
        return items.length == 0
    }

    // 查看队列中元素的个数
    this.size = function () {
        return items.length
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值