这段时间学算法,用JS实现了一个Prim,用于在连通图中找出最小树,具体内容、代码解析周末会不上,现在先把源码献上:
1 <!DOCTYPE html> 2 <html charset='GB2312'> 3 4 <head> 5 <title>最小树生成算法</title> 6 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 7 8 <style type="text/css"> 9 body>canvas { 10 border: 1px solid black; 11 padding: 10px; 12 margin: 10px auto; 13 } 14 </style> 15 </head> 16 17 <body> 18 <canvas id="canvas" width="1000px" height="400px"></canvas> 19 <canvas id="sub-canvas" width="1000px" height="400px"></canvas> 20 <script type="text/javascript"> 21 !(function() { 22 var canvas_context = document.getElementById('canvas').getContext('2d'), 23 sub_ctx = document.getElementById('sub-canvas').getContext('2d'), 24 _getRandom = function(max, min) { 25 max = max || 100; 26 min = min || 0; 27 return Math.round(Math.random() * (max - min) + min); 28 }, 29 _getRandomMatix = function(nodes) { 30 var matix = [], 31 power = 0, 32 max = 10, 33 min = 0, 34 tmp = 0; 35 for (var i = 0; i < nodes; i++) { 36 for (var j = i; j < nodes; j++) { 37 power = _getRandom(max, min); 38 matix[i] = matix[i] || []; 39 matix[j] = matix[j] || []; 40 tmp = i === j ? 0 : (Math.random() > 0.6 ? 1 : 0) * power; 41 matix[i][j] = matix[j][i] = tmp; 42 } 43 console.log(matix[i].join(',')) 44 } 45 46 // 构造连通图 47 for (var i = 0; i < matix.length; i++) { 48 var isValid = true; 49 for (var j = 0; j < matix[i].length; j++) { 50 isValid = isValid && matix[i][j] !== 0; 51 } 52 if (!isValid) { 53 var rindex = _getRandom(matix[i].length - 1, 0), 54 v = _getRandom(max, min + 1); 55 matix[i][rindex] = matix[rindex][i] = v; 56 } 57 } 58 return matix; 59 }, 60 _matix2graph = function(matix) { 61 var len = matix.length, 62 row = null, 63 cell = null, 64 graph = {}, 65 x, 66 y; 67 canvas_context.font = cycle_width / 2 + 'px Arial bold'; 68 canvas_context.textAlign = 'center'; 69 for (var i = 0; i < len; i++) { 70 x = _getRandom(pain_rect.x2, pain_rect.x1); 71 y = _getRandom(pain_rect.y2, pain_rect.y1); 72 73 graph[i] = { 74 x: x, 75 y: y, 76 powers: matix[i] 77 } 78 } 79 return graph; 80 }, 81 _getMinTree = function(graph) { 82 var point1 = graph[0], 83 min_tree = { 84 x: point1.x, 85 y: point1.y, 86 index: 0, 87 sub: [] 88 }, 89 min_x = -1, 90 min_y = -1, 91 min = Number.MAX_VALUE, 92 index_inTree = [0], 93 node = null, 94 _findNode = function(index, roots) { 95 if (roots.length === 0) return null; 96 97 var subRoots = []; 98 for (var i in roots) { 99 if (roots[i].index === index) return roots[i]; 100 else subRoots = subRoots.concat(roots[i].sub); 101 } 102 return _findNode(index, subRoots); 103 }; 104 105 for (var k in graph) { 106 min_x = -1; 107 min_y = -1; 108 min = Number.MAX_VALUE; 109 for (var i = 0; i < index_inTree.length; i++) { 110 point1 = graph[index_inTree[i]]; 111 for (var j = 1; j < point1.powers.length; j++) { 112 if (index_inTree.indexOf(j) >= 0) continue; 113 else if (point1.powers[j] > 0 && point1.powers[j] < min) { 114 min_x = point1.index; 115 min_y = j; 116 min = point1.powers[j] 117 } 118 } 119 } 120 if (min_x >= 0) { 121 index_inTree.push(min_y); 122 point1 = graph[min_y]; 123 node = _findNode(graph[min_x].index, [min_tree]); 124 if ( !! node) node.sub.push({ 125 x: point1.x, 126 y: point1.y, 127 index: min_y, 128 power: min, 129 sub: [] 130 }); 131 } 132 console.log('min tree node count: ' + index_inTree.length + ' ; ' + node); 133 } 134 return min_tree; 135 }, 136 canva_width = 1000, 137 canva_height = 400, 138 x_range = 490, 139 y_range = 190, 140 pain_rect = { 141 x1: canva_width / 2 - x_range, 142 x2: canva_width / 2 + x_range, 143 y1: canva_height / 2 - y_range, 144 y2: canva_height / 2 + y_range 145 }, 146 cycle_width = 10, 147 _renderGraph = function(graph) { 148 var point1, 149 point2, 150 count = 0; 151 for (var i in graph) { 152 point1 = graph[i]; 153 i = i - 0; 154 point1.index = i; 155 for (var j = 0; j < point1.powers.length; j++) { 156 point2 = graph[j]; 157 point2.index = j; 158 159 _renderPoint(point1); 160 _renderPoint(point2); 161 if ( !! point1.powers[j]) { 162 _renderLine(point1, point2, point1.powers[j]); 163 console.log('graph ' + i + ' to ' + j + ': ' + point1.powers[j]); 164 count += point1.powers[j]; 165 } 166 } 167 } 168 console.log('end graph :' + count); 169 return graph; 170 }, 171 _renderTree = function(tree) { 172 var _count = 0, 173 _renderer = function(root) { 174 var point1 = root, 175 point2 = null; 176 _renderPoint(point1, sub_ctx); 177 for (var i = 0; i < root.sub.length; i++) { 178 point2 = root.sub[i]; 179 _renderLine(point1, point2, point2.power, sub_ctx); 180 _renderer(point2); 181 _count += point2.power; 182 console.log('tree ' + point1.index + ' to ' + point2.index + ' : ' + point2.power); 183 } 184 }; 185 _renderer(tree); 186 187 console.log('end tree :' + _count) 188 }, 189 _renderPoint = function(point1, ctx) { 190 ctx = ctx || canvas_context; 191 requestAnimationFrame(function() { 192 // 画点 193 ctx.beginPath(); 194 ctx.fillStyle = 'red'; 195 ctx.arc(point1.x, point1.y, cycle_width, 0, Math.PI * 2, true); 196 ctx.fill(); 197 ctx.closePath(); 198 199 // 点中间的字——点的序号 200 ctx.beginPath(); 201 ctx.fillStyle = 'white'; 202 ctx.fillText(point1.index, point1.x, point1.y + cycle_width / 4); 203 ctx.closePath(); 204 }); 205 }, 206 _renderLine = function(point1, point2, power, ctx) { 207 ctx = ctx || canvas_context; 208 209 requestAnimationFrame(function() { 210 // 点与点间的连线 211 ctx.beginPath(); 212 ctx.moveTo(point1.x, point1.y); 213 ctx.lineTo(point2.x, point2.y); 214 ctx.closePath(); 215 ctx.stroke(); 216 217 // 点与点间连线的字——权重 218 ctx.beginPath(); 219 ctx.fillStyle = 'red'; 220 var x1 = Math.min(point1.x, point2.x), 221 x2 = Math.max(point1.x, point2.x), 222 y1 = Math.min(point1.y, point2.y), 223 y2 = Math.max(point1.y, point2.y); 224 ctx.fillText(power, 0.5 * x2 + 0.5 * x1, 0.5 * y2 + 0.5 * y1); 225 ctx.closePath(); 226 }); 227 }; 228 229 var graph = _renderGraph(_matix2graph(_getRandomMatix(9))); 230 _renderTree(_getMinTree(graph)) 231 })(); 232 </script> 233 </body> 234 235 </html>
这里可以在线运行哦:http://www.w3cfuns.com/home.php?mod=space&uid=5446932&do=blog&quickforward=1&id=5398698