单源最短路径、最小生成树及堆的Java实现
2013-04-16 22:19
585 查看
1. 堆
import java.util.ArrayList; import java.util.Collection; import java.util.List; public class Heap<T extends Comparable<T>> { private List<T> list; private boolean isMaxHeap = true; public Heap() { list = new ArrayList<T>(); list.add(null); } public Heap(Collection<T> col) { this(); addAll(col); } private int getLeftChildIndex(int i) { return i * 2; } private int getRightChildIndex(int i) { return i * 2 + 1; } private void maxHeapify(int rootIdx) { int li = this.getLeftChildIndex(rootIdx); int ri = this.getRightChildIndex(rootIdx); int largestIdx; if (li <= this.size() && list.get(li).compareTo(list.get(rootIdx)) > 0) { largestIdx = li; } else { largestIdx = rootIdx; } if (ri <= this.size() && list.get(ri).compareTo(list.get(largestIdx)) > 0) { largestIdx = ri; } if (largestIdx != rootIdx) { T tmp = list.get(rootIdx); list.set(rootIdx, list.get(largestIdx)); list.set(largestIdx, tmp); this.maxHeapify(largestIdx); } } private void minHeapify(int rootIdx) { int li = this.getLeftChildIndex(rootIdx); int ri = this.getRightChildIndex(rootIdx); int smallestIdx; if (li <= this.size() && list.get(li).compareTo(list.get(rootIdx)) < 0) { smallestIdx = li; } else { smallestIdx = rootIdx; } if (ri <= this.size() && list.get(ri).compareTo(list.get(smallestIdx)) < 0) { smallestIdx = ri; } if (smallestIdx != rootIdx) { T tmp = list.get(rootIdx); list.set(rootIdx, list.get(smallestIdx)); list.set(smallestIdx, tmp); this.minHeapify(smallestIdx); } } private void heapify(int i) { if (this.isMaxHeap) { this.maxHeapify(i); } else { this.minHeapify(i); } } public void add(T e) { list.add(e); for (int i = this.size() / 2; i > 0; i--) { heapify(i); } } public void addAll(Collection<T> col) { list.addAll(list.size(), col); for (int i = this.size() / 2; i > 0; i--) { heapify(i); } } public void remove(int i) { list.set(i, list.get(this.size())); list.remove(this.size()); this.heapify(i); } public T top() { return list.get(1); } public T pop() { T value = list.get(1); this.remove(1); return value; } public boolean isMaxHeap() { return isMaxHeap; } public void setMaxHeap(boolean isMaxHeap) { boolean lastFlag = this.isMaxHeap; this.isMaxHeap = isMaxHeap; if (lastFlag != isMaxHeap) { for (int i = this.size() / 2; i > 0; i--) { heapify(i); } } } public int size() { return list.size() - 1; } public void clear() { this.list.clear(); this.list.add(null); } public boolean isEmpty() { return this.size() == 0; } }
2. 最小生成树的Kruskal算法
import heap.Heap; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Scanner; import java.util.Set; public class Main { public static void main(String[] args) { List<Path> mst = Kruskal.execute(); for (Path path: mst) { System.out.println(path.p1 + "\t" + path.p2 + "\t" + path.len); } } } /* * 实现最小生成树的Kruskal算法 * 需要通过标准输入流输入无向图的信息 * 第一行为两个整数n m,n为总结点树,m为边数 * 结点的编号从0到n-1 * 接下来的m行为无向边的信息,格式为f t l * f和t分别为某条无向边的两个顶点,l为边权值 * 测试数据示例见最后 */ class Kruskal { public static List<Path> execute() { List<Path> mst = new ArrayList<Path>(); Scanner in = new Scanner(System.in); int n = in.nextInt(); int m = in.nextInt(); List<Set<Integer>> sets = new ArrayList<Set<Integer>>(); for (int i = 0; i < n; i++) { Set<Integer> set = new HashSet<Integer>(); set.add(i); sets.add(set); } Heap<Path> heap = new Heap<Path>(); heap.setMaxHeap(false); int f, t, l; for (int i = 0; i < m; i++) { f = in.nextInt(); t = in.nextInt(); l = in.nextInt(); Path path = new Path(f, t, l); heap.add(path); } in.close(); while (sets.size() != 1 && !heap.isEmpty()) { Path path = heap.pop(); int p1 = path.p1; int p2 = path.p2; Set<Integer> p1Set = null; for (Set<Integer> s: sets) { if (s.contains(p1)) { p1Set = s; break; } } if (!p1Set.contains(p2)) { Set<Integer> p2Set = null; for (Set<Integer> s: sets) { if (s.contains(p2)) { p2Set = s; break; } } sets.remove(p2Set); p1Set.addAll(p2Set); mst.add(path); } } return mst; } } class Path implements Comparable<Path> { public int p1; public int p2; public int len; public Path(int p1, int p2, int len) { this.p1 = p1; this.p2 = p2; this.len = len; } @Override public int compareTo(Path o) { return this.len - o.len; } } //测试数据 //7 11 //0 1 12 //1 2 32 //2 5 3 //5 6 24 //0 6 18 //0 3 25 //1 3 14 //0 4 34 //3 4 10 //3 5 8 //4 5 7
3. 单源最短路径的Dijkstra算法
import java.util.ArrayList; import java.util.List; import java.util.Scanner; public class Main { public static void main(String[] args) { new Dijkstra().execute(); } } /* * 实现单源最短路径的Dijkstra算法 * 通过标准输入流输入图的信息 * 本程序实现的是无向图中的单源最短路径,若要求有向图,则只需修改第45行 * 输入数据第一行为两个整数n m,n为结点数,m为边数 * 结点的编号从0到n-1 * 接下来为m行数据,表示每条边的信息,格式为f t l,分别表示起点和终点的编号,以及边权值 * 最后一行为两个整数,表示要求路径的起点和终点编号 * 测试数据见最后 */ class Dijkstra { private static final int INFINITE = 9999; public void execute() { Scanner in = new Scanner(System.in); int n = in.nextInt(); // number of points int m = in.nextInt(); // number of paths int[][] paths = new int ; for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { paths[i][j] = INFINITE; } } int f, t, l; for (int i = 0; i < m; i++) { f = in.nextInt(); t = in.nextInt(); l = in.nextInt(); paths[f][t] = paths[t][f] = l; } int sp = in.nextInt(); // starting point int fp = in.nextInt(); // finishing point in.close(); int[] dist = new int ; List<List<Integer>> sPaths = new ArrayList<List<Integer>>(); List<Integer> list = new ArrayList<Integer>(); for (int i = 0; i < n; i++) { dist[i] = paths[sp][i]; if (sp != i) { list.add(i); } if (dist[i] < INFINITE) { List<Integer> spa = new ArrayList<Integer>(); sPaths.add(spa); } else { sPaths.add(null); } } while (!list.isEmpty()) { Integer minIdx = list.get(0); for (int i: list) { if (dist[i] < dist[minIdx]) { minIdx = i; } } list.remove(minIdx); for (int i = 0; i < n; i++) { if (dist[i] > dist[minIdx] + paths[minIdx][i]) { dist[i] = dist[minIdx] + paths[minIdx][i]; List<Integer> tmp = new ArrayList<Integer>(sPaths.get(minIdx)); tmp.add(minIdx); sPaths.set(i, tmp); } } } System.out.println(dist[fp]); System.out.print(sp + " --> "); for (int p: sPaths.get(fp)) { System.out.print(p + " --> "); } System.out.println(fp); } } //测试数据 //10 14 //0 1 3 //0 5 4 //0 8 5 //1 2 6 //2 3 1 //2 5 4 //3 4 8 //3 6 2 //3 7 5 //4 7 2 //5 6 3 //6 7 7 //8 9 2 //9 7 3 //0 4
4. 附记
由于时间的关系,关于这几个算法的思想将在以后的博文中总结。总结因为时间紧张的原因,总结了好多东西,只能在有空的时候才能弄到电脑里,再搬到博客上。
希望能找到一个薪水高一些的实习工作吧!
相关文章推荐
- 数据结构-图-Java实现:有向图 图存储(邻接矩阵),最小生成树,广度深度遍历,图的连通性,最短路径
- 数据结构-图-Java实现:有向图 图存储(邻接矩阵),最小生成树,广度深度遍历,图的连通性,最短路径
- 数据结构-图-Java实现:有向图 图存储(邻接矩阵),最小生成树,广度深度遍历,图的连通性,最短路径
- Java实现Dijkstra单源最短路径
- 贪心算法 最小生成树prim与单源最短路径dijkstra
- 关于图的常用算法——Dijkstra单源最短路径、Floyd多源最短路径、Prim和Kruskal最小生成树算法
- 算法java实现--贪心算法--单源最短路径问题--Dijkstra算法
- 图(有向图,无向图)的邻接矩阵表示C++实现(遍历,拓扑排序,最短路径,最小生成树) Implement of digraph and undigraph using adjacency matrix
- 单源最短路径+最小花费生成树
- 单源最短路径Dijkstra算法(java实现)
- 浅析最小生成树和单源最短路径的区别(含Prim、Kruskal、Dijkstra、Bellman-Ford)
- 最小生成树与最短路径的区别以及实现方法
- 图的遍历、最小生成树以及单源最短路径
- 图(有向图)的邻接表表示 C++实现(遍历,拓扑排序,最短路径,最小生成树) Implement of digraph and undigraph using adjacency list
- 最小生成树Prim算法和单源最短路径Dijkstra算法
- 图的邻接矩阵表示形式,DFS和BFS,最小生成树Prim和Kruscal,单源最短路径Dijkstra算法
- 最小生成树、拓扑排序、单源最短路径
- 图的实现、无向图的最小生成树、有向图的最短路径
- 算法篇-7-贪心算法-Huffman编码&Dijkstra单源最短路径&Kruskal最小生成树
- Spark GraphX之Dijkstra(单源最短路径)、Prime(最小生成树)、FloydWarshall(多源最短路径)