geneVertexAxis() {
let i = 0
const vertexList = []
while (vertexList.length < vertex) {
const p = this._random()
if (this.axis[p.x][p.y] == -1) {
this.axis[p.x][p.y] = i
this.vertexPoints[i] = p
vertexList.push(i)
i++
}
}
}
geneEdge() {
for (let i = 0; i < edge; i++) {
let v1 = random(vertex)
let v2 = random(vertex)
if (v1 !== v2) {
let e = `${v1}-${v2}-${random(maxWeight)}`
let eReverse = `${v2}-${v1}`
if (!this._repeat(`${v1}-${v2}`) && !this._repeat(eReverse)) {
this.edgeList.push(e)
}
}
}
}
演示地址
源码
问题引入
在学习了加权无向图寻找最小生成树的算法之后,想通过可视化的方式来表示一个图的构造和最小生成树的寻路过程,就使用canvas来模拟了图的构造,连接边和加重显示最小生成树组成的边的过程
效果图
分析
整个过程可以分为三步
通过canvas画圆圈来表示图的M个顶点,随机生成顶点的坐标
随机生成N条边,通过canvas来连接每条边对应的两个顶点
prim算法寻找最小生成树,canvas加粗显示最小生成树中的边
实现
主要用到的canvas方法有
arc()
,moveTo()
,lineTo()
,fillText()
以及修改样式和颜色将canvas画布表示成一个(M+1)*(M+1)的二维数组,对于M个顶点,为每个顶点随机生成不大于M的两个二维数组的索引
顶点的表示
需要注意的是,因为是随机生成的,两个顶点在数组中的位置可能重复,所以遇到重复的情况,应该为顶点重新生成一个位置
大体过程
同样通过random()来随机生成两个需要连接的顶点(不大于M),并为这条边加一个权重,同时不能生成重复边, v-w 和 w-v视为同一条边
重要的是:
使用canvas来绘制圆,绘制直线都很简单,但这里,为了美观,在将两个顶点连接(即在两个圆之间画一条直线)时,对于直线,不能始于一个圆的圆心,止于另一个圆的圆心,而应该取两个圆与直线的焦点作为直线的两个端点
要做到这一点,需要借助数学中的勾股定理和等比三角形(O(∩_∩)O) 来求出焦点相对于圆心的横纵方向的偏移量
使用prim算法求出最小生成树后,我们可以得到一组最小生成树中的顶点列表,然后将列表中的顶点对延时加粗绘制出来