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[n][n];
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[n];
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. 附记
由于时间的关系,关于这几个算法的思想将在以后的博文中总结。
总结因为时间紧张的原因,总结了好多东西,只能在有空的时候才能弄到电脑里,再搬到博客上。
希望能找到一个薪水高一些的实习工作吧!