package org.apache.hadoop.hdfs; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.Arrays; import java.util.PriorityQueue; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.hadoop.io.Writable; public class MinimumSpanningTree implements Writable { static public int DISCONNECTED = java.lang.Integer.MAX_VALUE; public static final Log LOG = LogFactory.getLog(MinimumSpanningTree.class); abstract static public class TreeNode implements Writable { abstract public int getChildrenNumber(); abstract public String getHostName(); abstract public TreeNode getChild(int index); abstract public boolean addChild(TreeNode child); abstract public boolean isLeaf(); abstract public void write(DataOutput out) throws IOException; abstract public void readFields(DataInput in) throws IOException; abstract public boolean equals(Object obj); abstract public void dropChildren(); } public static class Result { public int totalWeight; public int[] chosed; public Result() { totalWeight = 0; chosed = null; } public Result(int totalWeight, int[] chosed) { this.totalWeight = totalWeight; this.chosed = chosed; } } private TreeNode root; public MinimumSpanningTree(TreeNode root) { this.root = root; } public TreeNode getRoot() { return root; } @Override public void write(DataOutput out) throws IOException { root.write(out); } @Override public void readFields(DataInput in) throws IOException { root.readFields(in); } static private class Vertex implements Comparable<Vertex> { public int id; public int value; public int to; public Vertex(int id, int to, int value) { this.id = id; this.value = value; this.to = to; } @Override public int compareTo(Vertex o) { if (value > o.value) { return +1; } else if(value < o.value) { return -1; } else { return 0; } } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Vertex other = (Vertex) obj; if (id != other.id) return false; if (to != other.to) return false; if (value != other.value) return false; return true; } } static public MinimumSpanningTree build(TreeNode[] nodes, int[][] distances, int root) { MinimumSpanningTree mst = new MinimumSpanningTree(nodes[root]); PriorityQueue<Vertex> costList = new PriorityQueue<Vertex>(); for(int i = 0; i < distances.length; i++) { if(i != root) costList.add(new Vertex(i, root, distances[i][root])); } while(!costList.isEmpty()) { Vertex next = costList.poll(); nodes[next.to].addChild(nodes[next.id]); Vertex[] remains = costList.toArray(new Vertex[0]); for(int i = 0; i<remains.length; i++) { if(distances[remains[i].id][next.id] <= remains[i].value) { costList.remove(remains[i]); remains[i].to = next.id; remains[i].value = distances[remains[i].id][next.id]; costList.add(remains[i]); } } } return mst; } static public Result chooseAndBuildTree(TreeNode[] nodes, int[][] distances, int root, int nodeNumber) { PriorityQueue<Vertex> costList = new PriorityQueue<Vertex>(); int[] locationsChoosed = new int[nodeNumber]; int totalWeight = 0; for(int i = 0; i < distances.length; i++) { if(i != root) costList.add(new Vertex(i, root, distances[i][root])); } int number = 0; while((number < nodeNumber) && (!costList.isEmpty())) { Vertex next = costList.poll(); nodes[next.to].addChild(nodes[next.id]); totalWeight += next.value; //LOG.info("NTar: add " + nodes[next.id] + " as child of " + nodes[next.to]); locationsChoosed[number] = next.id; number = number + 1; Vertex[] remains = costList.toArray(new Vertex[0]); for(int i = 0; i<remains.length; i++) { if(distances[remains[i].id][next.id] < remains[i].value) { costList.remove(remains[i]); remains[i].to = next.id; remains[i].value = distances[remains[i].id][next.id]; costList.add(remains[i]); } } } return new Result(totalWeight, locationsChoosed); } static public Result chooseAndBuildLine(TreeNode[] nodes, int[][] distances, int root, int nodeNumber) { PriorityQueue<Vertex> costList = new PriorityQueue<Vertex>(); int[] locationsChoosed = new int[nodeNumber]; Arrays.fill(locationsChoosed, -1); int totalWeight = 0; for (int i = 0; i < distances.length; i++) { if (i != root) costList.add(new Vertex(i, root, distances[i][root])); } int number = 0; while ((number < nodeNumber) && (!costList.isEmpty())) { Vertex next = costList.poll(); nodes[next.to].addChild(nodes[next.id]); totalWeight += next.value; //LOG.info("NTar: add " + nodes[next.id] + " as child of " + nodes[next.to]); locationsChoosed[number] = next.id; number = number + 1; Vertex[] remains = costList.toArray(new Vertex[0]); for (int i = 0; i<remains.length; i++) { costList.remove(remains[i]); remains[i].to = next.id; remains[i].value = distances[remains[i].id][next.id]; costList.add(remains[i]); } } return new Result(totalWeight, locationsChoosed); } static public Result chooseAndBuildStar(TreeNode[] nodes, int[][] distances, int root, int nodeNumber) { PriorityQueue<Vertex> costList = new PriorityQueue<Vertex>(); int[] locationsChoosed = new int[nodeNumber]; int totalWeight = 0; for(int i = 0; i < distances.length; i++) { if(i != root) costList.add(new Vertex(i, root, distances[i][root])); } int number = 0; while((number < nodeNumber) && (!costList.isEmpty())) { Vertex next = costList.poll(); totalWeight += next.value; nodes[next.to].addChild(nodes[next.id]); //LOG.info("TREE: add " + nodes[next.id] + " as child of " + nodes[next.to]); locationsChoosed[number] = next.id; number = number + 1; } return new Result(totalWeight, locationsChoosed); } }