/** 节点 */ function V(data) { if (!(this instanceof V)) { return new V(data); } this._id = uuid(10, 10); //随机生成的 uuid this.data = data; //头节点的数据 this.children = null; //指向链表的其它节点 this.index = null; //节点在数组中的位置(数组下标) this.d = Infinity; //从源节点到当前节点的最短距离的估计指(初始位无穷大) }
function E() { if (!(this instanceof E)) { return new E(); } this.next = null; //边指向下一个 E 类型的jie'dian this.index = null; // 边指向的节点在 Adj 中的下标 例如边 (u,v) 则 index 指向v this.w = null; //边的权重 }
function G() { if (!(this instanceof G)) { return new G(); } this.Adj = []; //构成图 G 的邻接链表 } G.prototype = { constructor: G, // 添加边 addEdge: function (u, v, w) { let e = E(); e.index = v.index; e.w = w; let next = u.children; if (next == null) { u.children = e; } else { while (true) { if (next.next == null) { next.next = e; break; } else { next = next.next; } } } }, //获取节点 u 的全部邻接节点 adj: function (u) { let next = u.children; let list = []; while (true) { if (next == null) { break; } else { list.push(this.Adj[next.index]); next = next.next; } } return list; }, // 权重函数 w: function (u, v) { let next = u.children; while (next != null) { if (this.Adj[next.index]._id == v._id) { return next.w; } next = next.next; } }, // 添加节点 addVertex: function (v) { if (v.index != null) { return; } let index = this.Adj.push(v) - 1; //该节点在数组中的位置 v.index = index; }, //松弛 relax: function (u, v) { if (v.d > u.d + this.w(u, v)) { v.d = u.d + this.w(u, v); return true; } return false; } }
/** 生成一个简单的uuid len 表示长度, sys 表示进制 能够位 2, 8, 16 等等*/ function uuid(len, sys) { let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); let uuid = [], i; sys = sys || chars.length; if (len) { for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * sys]; } else { let r; uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; uuid[14] = '4'; for (i = 0; i < 36; i++) { if (!uuid[i]) { r = 0 | Math.random() * 16; uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; } } } return uuid.join(''); }
Dijkstra 算法的思想是将图中的全部节点划分到两个集合中,集合Q中存放的是最短路径未肯定的节点,集合S中存放的是已经肯定最短路径距离的节点,初始时,全部的节点都在Q中,源节点s的最短路径距离初始时为0,集合Q内部经过最小优先队列来组织节点关系javascript
松弛操做是对于节点 v
,若是从源节点到v的最短估计路径距离为 v.d
,v.d
为无穷大或为某一具体数,u
也是从源节点可达的节点,而且边(u, v)
存在且距离是w
,若是v.d > u.d + w(u, v)
, 则 v.d = u.d + w(u, v)
java
最小优先队列参照 二叉堆、堆排序、优先队列、topK问题详解及js实现 这里直接给出实现代码算法
function MinBinaryHeap(key) { if (!(this instanceof MinBinaryHeap)) return new MinBinaryHeap(key); this.key = key; //key表示用来排序的字段 this.size = 0; //堆大小 这里堆大小和数组大小一致 this.list = []; //用于存放堆元素 存放的是对象 } MinBinaryHeap.prototype = { constructor: MinBinaryHeap, //获取某个节点的父节点 parent: function (i) { let p = Math.floor((i - 1) / 2); if (i > this.size - 1 || p < 0) return null; return p; //这里返回的 p 是在数组中的下标,数组是从0开始的 }, //获取某个节点的左孩子 left: function (i) { let l = 2 * i + 1; if (l > this.size - 1) return null; return l; }, //获取某个节点的右孩子 right: function (i) { let r = 2 * i + 2; if (r > this.size - 1) return null; return r; }, minHeapify: function (i) { let list = this.list; let key = this.key; let l = this.left(i); let r = this.right(i); let smallest = null; if (l != null) { //左孩子为空则右孩子必定为空 if (r == null) smallest = l; else smallest = list[l][key] < list[r][key] ? l : r; if (list[i][key] <= list[smallest][key]) return; else { let t = list[i]; list[i] = list[smallest]; list[smallest] = t; this.minHeapify(smallest); } } }, //元素上浮 对下标为i的元素进行向上调整,使堆保持其性质 increase: function (i) { let list = this.list; let p = this.parent(i); while (i > 0 && list[p][this.key] > list[i][this.key]) { //i > 0 必定能保证 p != null let t = list[i]; list[i] = list[p]; list[p] = t; i = this.parent(i); p = this.parent(i); } }, //构建堆 buildHeap: function (a) { this.list = a; this.size = a.length; for (let i = Math.floor(a.length / 2) - 1; i > -1; i--) { this.minHeapify(i); } }, //堆排序 由大到小 heapSort: function (a) { this.buildHeap(a); for (let i = this.size - 1; i > 0; i--) { let t = this.list[0]; this.list[0] = this.list[i]; this.list[i] = t; this.size--; this.minHeapify(0); } return this.list; }, //更新排序 fresh: function() { this.size = this.list.length; for (let i = Math.floor(this.size / 2) - 1; i > -1; i--) { this.minHeapify(i); } } } //最小优先队列 function MinPriorityQueue(key, a) { if (!(this instanceof MinPriorityQueue)) { return new MinPriorityQueue(key, a); } if (a == null) { a = []; } this.minBinaryHeap = MinBinaryHeap(key); this.minBinaryHeap.buildHeap(a); this.key = key; } MinPriorityQueue.prototype = { constructor: MinPriorityQueue, insert: function (x) { //加入一个元素 this.minBinaryHeap.size++; this.minBinaryHeap.list[this.minBinaryHeap.size - 1] = x; //向上调整 this.minBinaryHeap.increase(this.minBinaryHeap.size - 1); }, //remove 表示获取后是否删除 true 删除 false 不删除 min: function (remove) { //获取最小元素 let min = this.minBinaryHeap.list[0]; if (remove) this.removeMin(); return min; }, removeMin: function () { //移除最小元素 let list = this.minBinaryHeap.list; let size = this.minBinaryHeap.size; let min = list[0]; list[0] = list[size - 1]; list.shift(size - 1); //删除 this.minBinaryHeap.size--; this.minBinaryHeap.minHeapify(0); return min; }, update: function (i, x) { //更新元素 this.minBinaryHeap.list[i] = x; this.minBinaryHeap.minHeapify(i); this.minBinaryHeap.increase(i); }, fresh: function() { this.minBinaryHeap.fresh(); } }
function dijkstra(g, s) { let minPriorityQueue = MinPriorityQueue('d', null); s.d = 0; //初始s的最短路径距离 g.Adj.forEach(v => { minPriorityQueue.insert(v); }); let u = minPriorityQueue.removeMin(); //取出 d 值最小的节点 while (u != null) { let adj = g.adj(u); //获取节点u的全部邻接节点 adj.forEach(v => { //对u的全部邻接节点进行松弛操做 let isRelax = g.relax(u, v); if(isRelax) { minPriorityQueue.fresh(); //刷新最小优先队列 } }); u = minPriorityQueue.removeMin(); } }
let g = G(); let v1 = V('v1'); let v2 = V('v2'); let v3 = V('v3'); let v4 = V('v4'); let v5 = V('v5'); g.addVertex(v1); g.addVertex(v2); g.addVertex(v3); g.addVertex(v4); g.addVertex(v5); g.addEdge(v1, v2, 10); g.addEdge(v1, v3, 5); g.addEdge(v2, v4, 1); g.addEdge(v2, v3, 2); g.addEdge(v3, v4, 9); g.addEdge(v3, v5, 2); g.addEdge(v3, v2, 3); g.addEdge(v4, v5, 4); g.addEdge(v5, v4, 6); g.addEdge(v5, v1, 7); let a = dijkstra(g, v1); console.log(g);
function G() { if (!(this instanceof G)) { return new G(); } this.Adj = []; } G.prototype = { constructor: G, // 添加边 addEdge: function (u, v, w) { let e = E(); e.index = v.index; e.w = w; let next = u.children; if (next == null) { u.children = e; } else { while (true) { if (next.next == null) { next.next = e; break; } else { next = next.next; } } } }, adj: function (u) { let next = u.children; let list = []; while (true) { if (next == null) { break; } else { list.push(this.Adj[next.index]); next = next.next; } } return list; }, // 权重函数 w: function (u, v) { let next = u.children; while (next != null) { if (this.Adj[next.index]._id == v._id) { return next.w; } next = next.next; } }, // 添加节点 addVertex: function (v) { if (v.index != null) { return; } let index = this.Adj.push(v) - 1; //该节点在数组中的位置 v.index = index; }, //松弛 relax: function (u, v) { if (v.d > u.d + this.w(u, v)) { v.d = u.d + this.w(u, v); return true; } return false; } } /** 节点 */ function V(data) { if (!(this instanceof V)) { return new V(data); } this._id = uuid(10, 10); this.data = data; this.children = null; this.index = null; //节点在数组中的位置 this.d = Infinity; } /** 边 */ function E() { if (!(this instanceof E)) { return new E(); } this.next = null; this.index = null; // 边指向的节点 在Adj中的下标 例如边(u,v) 则 index 指向v this.w = null; } /** 生成一个简单的uuid */ function uuid(len, sys) { let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); let uuid = [], i; sys = sys || chars.length; if (len) { for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * sys]; } else { let r; uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; uuid[14] = '4'; for (i = 0; i < 36; i++) { if (!uuid[i]) { r = 0 | Math.random() * 16; uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; } } } return uuid.join(''); } function MinBinaryHeap(key) { if (!(this instanceof MinBinaryHeap)) return new MinBinaryHeap(key); this.key = key; //key表示用来排序的字段 this.size = 0; //堆大小 这里堆大小和数组大小一致 this.list = []; //用于存放堆元素 存放的是对象 } MinBinaryHeap.prototype = { constructor: MinBinaryHeap, //获取某个节点的父节点 parent: function (i) { let p = Math.floor((i - 1) / 2); if (i > this.size - 1 || p < 0) return null; return p; //这里返回的 p 是在数组中的下标,数组是从0开始的 }, //获取某个节点的左孩子 left: function (i) { let l = 2 * i + 1; if (l > this.size - 1) return null; return l; }, //获取某个节点的右孩子 right: function (i) { let r = 2 * i + 2; if (r > this.size - 1) return null; return r; }, minHeapify: function (i) { let list = this.list; let key = this.key; let l = this.left(i); let r = this.right(i); let smallest = null; if (l != null) { //左孩子为空则右孩子必定为空 if (r == null) smallest = l; else smallest = list[l][key] < list[r][key] ? l : r; if (list[i][key] <= list[smallest][key]) return; else { let t = list[i]; list[i] = list[smallest]; list[smallest] = t; this.minHeapify(smallest); } } }, //元素上浮 对下标为i的元素进行向上调整,使堆保持其性质 increase: function (i) { let list = this.list; let p = this.parent(i); while (i > 0 && list[p][this.key] > list[i][this.key]) { //i > 0 必定能保证 p != null let t = list[i]; list[i] = list[p]; list[p] = t; i = this.parent(i); p = this.parent(i); } }, //构建堆 buildHeap: function (a) { this.list = a; this.size = a.length; for (let i = Math.floor(a.length / 2) - 1; i > -1; i--) { this.minHeapify(i); } }, //堆排序 由大到小 heapSort: function (a) { this.buildHeap(a); for (let i = this.size - 1; i > 0; i--) { let t = this.list[0]; this.list[0] = this.list[i]; this.list[i] = t; this.size--; this.minHeapify(0); } return this.list; }, //更新排序 fresh: function() { this.size = this.list.length; for (let i = Math.floor(this.size / 2) - 1; i > -1; i--) { this.minHeapify(i); } } } //最小优先队列 function MinPriorityQueue(key, a) { if (!(this instanceof MinPriorityQueue)) { return new MinPriorityQueue(key, a); } if (a == null) { a = []; } this.minBinaryHeap = MinBinaryHeap(key); this.minBinaryHeap.buildHeap(a); this.key = key; } MinPriorityQueue.prototype = { constructor: MinPriorityQueue, insert: function (x) { //加入一个元素 this.minBinaryHeap.size++; this.minBinaryHeap.list[this.minBinaryHeap.size - 1] = x; //向上调整 this.minBinaryHeap.increase(this.minBinaryHeap.size - 1); }, //remove 表示获取后是否删除 true 删除 false 不删除 min: function (remove) { //获取最小元素 let min = this.minBinaryHeap.list[0]; if (remove) this.removeMin(); return min; }, removeMin: function () { //移除最小元素 let list = this.minBinaryHeap.list; let size = this.minBinaryHeap.size; let min = list[0]; list[0] = list[size - 1]; list.shift(size - 1); //删除 this.minBinaryHeap.size--; this.minBinaryHeap.minHeapify(0); return min; }, update: function (i, x) { //更新元素 this.minBinaryHeap.list[i] = x; this.minBinaryHeap.minHeapify(i); this.minBinaryHeap.increase(i); }, fresh: function() { this.minBinaryHeap.fresh(); } } function dijkstra(g, s) { let minPriorityQueue = MinPriorityQueue('d', null); s.d = 0; g.Adj.forEach(v => { minPriorityQueue.insert(v); }); let u = minPriorityQueue.removeMin(); while (u != null) { let adj = g.adj(u); adj.forEach(v => { let isRelax = g.relax(u, v); if(isRelax) { minPriorityQueue.fresh(); } }); u = minPriorityQueue.removeMin(); } } let g = G(); let v1 = V('v1'); let v2 = V('v2'); let v3 = V('v3'); let v4 = V('v4'); let v5 = V('v5'); g.addVertex(v1); g.addVertex(v2); g.addVertex(v3); g.addVertex(v4); g.addVertex(v5); g.addEdge(v1, v2, 10); g.addEdge(v1, v3, 5); g.addEdge(v2, v4, 1); g.addEdge(v2, v3, 2); g.addEdge(v3, v4, 9); g.addEdge(v3, v5, 2); g.addEdge(v3, v2, 3); g.addEdge(v4, v5, 4); g.addEdge(v5, v4, 6); g.addEdge(v5, v1, 7); let a = dijkstra(g, v1); console.log(g);
将以上代码复制粘贴到浏览器控制台运行后结果为segmentfault