1. 程式人生 > >JS實現最小生成樹之克魯斯卡爾(Kruskal)演算法

JS實現最小生成樹之克魯斯卡爾(Kruskal)演算法

 

克魯斯卡爾演算法列印最小生成樹:

  構造出所有邊的集合 edges,從小到大,依次選出篩選邊列印,遇到閉環(形成迴路)時跳過。

JS程式碼:

  1 //定義鄰接矩陣
  2 let Arr2 = [
  3     [0, 10, 65535, 65535, 65535, 11, 65535, 65535, 65535],
  4     [10, 0, 18, 65535, 65535, 65535, 16, 65535, 12],
  5     [65535, 18, 0, 22, 65535, 65535, 65535, 65535, 8],
  6     [65535, 65535, 22, 0, 20, 65535, 65535, 16, 21],
7 [65535, 65535, 65535, 20, 0, 26, 65535, 7, 65535], 8 [11, 65535, 65535, 65535, 26, 0, 17, 65535, 65535], 9 [65535, 16, 65535, 65535, 65535, 17, 0, 19, 65535], 10 [65535, 65535, 65535, 16, 7, 65535, 19, 0, 65535], 11 [65535, 12, 8, 21, 65535, 65535, 65535, 65535, 0], 12 ] 13 14
let numVertexes = 9, //定義頂點數 15 numEdges = 15; //定義邊數 16 17 // 定義圖結構 18 function MGraph() { 19 this.vexs = []; //頂點表 20 this.arc = []; // 鄰接矩陣,可看作邊表 21 this.numVertexes = null; //圖中當前的頂點數 22 this.numEdges = null; //圖中當前的邊數 23 } 24 let G = new MGraph(); //建立圖使用 25 26 //建立圖 27 function
createMGraph() { 28 G.numVertexes = numVertexes; //設定頂點數 29 G.numEdges = numEdges; //設定邊數 30 31 //錄入頂點資訊 32 for (let i = 0; i < G.numVertexes; i++) { 33 G.vexs[i] = 'V' + i; //scanf('%s'); //ascii碼轉字元 //String.fromCharCode(i + 65); 34 } 35 console.log(G.vexs) //列印頂點 36 37 //鄰接矩陣初始化 38 for (let i = 0; i < G.numVertexes; i++) { 39 G.arc[i] = []; 40 for (j = 0; j < G.numVertexes; j++) { 41 G.arc[i][j] = Arr2[i][j]; //INFINITY; 42 } 43 } 44 console.log(G.arc); //列印鄰接矩陣 45 } 46 47 function Edge() { 48 this.begin = 0; 49 this.end = 0; 50 this.weight = 0; 51 } 52 53 function Kruskal() { 54 let n, m; 55 let parent = []; //定義一陣列用來判斷邊與邊是否形成環路 56 let edges = []; //定義邊集陣列 57 58 for (let i = 0; i < G.numVertexes; i++) { 59 for (let j = i; j < G.numVertexes; j++) { //因為是無向圖所以相同的邊錄入一次即可,若是有向圖改為0 60 if (G.arc[i][j] != 0 && G.arc[i][j] != 65535) { 61 let edge = new Edge(); 62 edge.begin = i; 63 edge.end = j; 64 edge.weight = G.arc[i][j]; 65 edges.push(edge); 66 } 67 } 68 } 69 70 edges.sort((v1, v2) => { 71 return v1.weight - v2.weight 72 }); 73 74 console.log('**********列印所有邊*********'); 75 console.log(edges); 76 77 for (let i = 0; i < G.numVertexes; i++) { 78 parent[i] = 0; 79 } 80 81 for (let i = 0; i < edges.length; i++) { 82 n = Find(parent, edges[i].begin) 83 m = Find(parent, edges[i].end) 84 if (n != m) { //假如n與m不等,說明此邊沒有與現有生成樹形成環路 85 parent[n] = m; 86 console.log("(%s,%s) %d", G.vexs[edges[i].begin], G.vexs[edges[i].end], edges[i].weight); 87 } 88 } 89 } 90 91 92 function Find(parent, f) { //查詢連線頂點的尾部下標 93 while (parent[f] > 0) { 94 f = parent[f] 95 } 96 return f; 97 } 98 99 createMGraph(); 100 console.log('*********列印最小生成樹**********') 101 Kruskal();

列印結果:

程式碼部分過程解析:

 

克魯斯卡爾演算法主要針對邊展開,時間複雜度為 O(elog e),e為圖的邊數,普利姆演算法的時間複雜度為O(n²),n為最小生成樹的邊數。所以,邊數少(稀疏圖)用克魯斯卡爾演算法,邊數多(稠密圖)用普利姆演算法。

 

參考文獻: 程傑老師的 《大話資料結構》