/** 節點 */ 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