拓扑排序
//邻接表无权的有向图
public class Graph<V> {
class Vertex<V> {//内部类,存储顶点的信息
int in;//入度
V date;//顶点值
LinkedList<Integer> adj;//顶点的每一个邻接顶点构成的邻接表,Integer为顶点在顶点数组中的下标
//顶点的构造方法
Vertex(V date) {
this.date = date;
adj = new LinkedList<Integer>();
in = 0;
}
}
Vertex<V>[] vertexList;//由顶点组成的数组
int numOfVertex;//顶点的数量
int numOfEdge;//边的数量
int size;//顶点的最大规模
Graph() {
}
Graph(int size) {
vertexList = new Vertex[size];
numOfVertex = 0;
numOfEdge = 0;
}
public void addVertex(V v) {
vertexList[numOfVertex] = new Vertex<V>(v);
numOfVertex++;
}
public void addEdge(int from, int to) {
//传入的是一个Vertex对象在数组中的索引
//根据顶点值找这个Vertex对象在数组中的索引
vertexList[from].adj.add(to);
numOfEdge++;
}
public void print() {
for (Vertex v : vertexList) {
System.out.println(v.in + "---" + v.date + "---" + v.adj);
}
}
public void setIn() {//求入度
for (int x = 0; x < numOfVertex; x++) {
for (int i = 0; i < numOfVertex; i++) {
for (int j = 0; j < vertexList[i].adj.size(); j++) {
if (vertexList[i].adj.get(j) == x) {
vertexList[x].in++;
}
}
}
}
}
//拓扑排序
public void topologicalSort() {
Stack<Vertex<V>> stack = new Stack<>();
//将入度为0的顶点入栈
for (int i = 0; i < numOfVertex; i++) {
if (vertexList[i].in == 0) {
stack.push(vertexList[i]);
}
}
int count = 0;//统计出栈的顶点个数
while (!stack.empty()) {
Vertex<V> temp = stack.pop();//出栈并返回出栈的顶点
System.out.println(temp.date);//打印出栈的顶点
count++;
//把出栈的顶点指向的顶点的入度-1(即在图中删除这个顶点)
for (int index : temp.adj) {
vertexList[index].in--;
if (vertexList[index].in == 0) {
stack.push(vertexList[index]);
}
}
}
if (count < numOfVertex) {
System.out.println("存在环");
} else {
System.out.println("打印完毕");
}
}
}
public class GraphDemo {
public static void main(String[] args) {
Graph<String> graph = new Graph<String>(14);
//添加顶点
graph.addVertex("v0");
graph.addVertex("v1");
graph.addVertex("v2");
graph.addVertex("v3");
graph.addVertex("v4");
graph.addVertex("v5");
graph.addVertex("v6");
graph.addVertex("v7");
graph.addVertex("v8");
graph.addVertex("v9");
graph.addVertex("v10");
graph.addVertex("v11");
graph.addVertex("v12");
graph.addVertex("v13");
//添加边
graph.addEdge(0, 11);
graph.addEdge(0, 5);
graph.addEdge(0, 4);
graph.addEdge(1, 8);
graph.addEdge(1, 4);
graph.addEdge(1, 2);
graph.addEdge(2, 9);
graph.addEdge(2, 6);
graph.addEdge(2, 5);
graph.addEdge(3, 13);
graph.addEdge(3, 2);
graph.addEdge(4, 7);
graph.addEdge(5, 12);
graph.addEdge(5, 8);
graph.addEdge(6, 5);
graph.addEdge(8, 7);
graph.addEdge(9, 11);
graph.addEdge(9, 10);
graph.addEdge(10, 13);
graph.addEdge(12, 9);
graph.setIn();
graph.print();
//拓扑排序
graph.topologicalSort();
}
}
关键路径
//邻接表带权的有向图
public class Graph<V> {
class Vertex<V> {//内部类,存储顶点的信息
int in;//入度
V date;//顶点值
HashMap<Integer, Integer> adj;//邻接表,顶点+弧的权值
//顶点的构造方法
Vertex(V date) {
this.date = date;
adj = new HashMap<Integer, Integer>();
in = 0;
}
}
Vertex<V>[] vertexList;//由顶点组成的数组
int numOfVertex;//顶点的数量
int numOfEdge;//边的数量
int size;//顶点的最大规模
Graph() {
}
Graph(int size) {
vertexList = new Vertex[size];
numOfVertex = 0;
numOfEdge = 0;
}
public void addVertex(V v) {
vertexList[numOfVertex] = new Vertex<V>(v);
numOfVertex++;
}
public void addEdge(int from, int to, int weight) {
//传入的是一个Vertex对象在数组中的索引
//根据顶点值找这个Vertex对象在数组中的索引
vertexList[from].adj.put(to, weight);
numOfEdge++;
}
public void print() {
for (Vertex v : vertexList) {
System.out.println(v.in + "---" + v.date + "---" + v.adj);
}
}
public void setIn() {//求入度
for (int x = 0; x < numOfVertex; x++) {
for (int i = 0; i < numOfVertex; i++) {//遍历所有顶点的邻接表
Set<Integer> set = vertexList[i].adj.keySet();//拿到邻接表的所有键的集合
for (Integer integer : set) {
if (integer == x) {
vertexList[x].in++;
}
}
}
}
}
//根据date找索引
public int getIndex(V v) {
int i;
for (i = 0; i < numOfVertex; i++) {
if (vertexList[i].date == v) {
break;
}
}
return i;
}
//关键路径
public void topologicalSort() {
int[] etv = new int[numOfVertex];//事件(顶点)的最早发生时间数组
int[] ltv = new int[numOfVertex];//事件(顶点)的最晚发生时间数组
//第一步:求事件(顶点)的最早发生时间数组和拓扑序列
Stack<Vertex<V>> stack = new Stack<>();
Stack<Vertex<V>> stack2 = new Stack<>();//拓扑序列
//将入度为0的顶点入栈
for (int i = 0; i < numOfVertex; i++) {
if (vertexList[i].in == 0) {
stack.push(vertexList[i]);
}
}
int count = 0;//计数
while (!stack.empty()) {
Vertex<V> temp = stack.pop();//出栈并返回出栈的顶点
stack2.push(temp);//把出栈的顶点加入到拓扑序列
count++;//出栈的元素数量
//遍历栈顶元素的邻接表
for (int index : temp.adj.keySet()) {
vertexList[index].in--; //把栈顶元素指向的顶点的入度-1(即在图中删除栈顶元素)
if (vertexList[index].in == 0) {
stack.push(vertexList[index]);
}
etv[index] = Math.max(etv[index], etv[getIndex(temp.date)] + temp.adj.get(index));
//Math.max(指向的元素 : 当前元素 + 当前元素到指向元素的权值)
}
}
// if (count < numOfVertex) {
// System.out.println("存在环");
// } else {
// //打印拓扑序列
// for (Vertex vertex : stack2) {
// System.out.println(vertex.date);
// }
// }
// System.out.println(Arrays.toString(etv));
//第二步:求事件(顶点)的最晚发生时间数组
for (int i = 0; i < numOfVertex; i++) {
ltv[i] = etv[numOfVertex - 1];
}//初始化最晚发生时间数组
int point = numOfVertex - 1;
while (point>=0) {
Vertex<V> temp = stack2.get(point);
point--;
for (int index : temp.adj.keySet()) {
ltv[getIndex(temp.date)] = Math.min(ltv[getIndex(temp.date)], ltv[index] - temp.adj.get(index));
// Math.min(当前元素 : 指向的元素 - 当前元素到指向元素的权值)
}
}
// System.out.println(Arrays.toString(ltv));
//第三步:求出关键路径
int i = getIndex(stack2.get(0).date);//栈底元素的下标
while (i != numOfVertex - 1) {
Set<Integer> set = vertexList[i].adj.keySet();//拿到邻接表的所有键的集合
for (int index : set) {
if (etv[index] == ltv[index]) {
System.out.println("(" + vertexList[i].date + "," + vertexList[index].date
+ ")" + vertexList[i].adj.get(index));
i = index;
}
}
}
}
}
public class GraphDemo {
public static void main(String[] args) {
Graph<String> graph = new Graph<String>(10);
//添加顶点
graph.addVertex("v0");
graph.addVertex("v1");
graph.addVertex("v2");
graph.addVertex("v3");
graph.addVertex("v4");
graph.addVertex("v5");
graph.addVertex("v6");
graph.addVertex("v7");
graph.addVertex("v8");
graph.addVertex("v9");
//添加边
graph.addEdge(0, 2,4);
graph.addEdge(0, 1,3);
graph.addEdge(1, 4,6);
graph.addEdge(1, 3,5);
graph.addEdge(2, 5,7);
graph.addEdge(2, 3,8);
graph.addEdge(3, 4,3);
graph.addEdge(4, 7,4);
graph.addEdge(4, 6,9);
graph.addEdge(5, 7,6);
graph.addEdge(6, 9,2);
graph.addEdge(7, 8,5);
graph.addEdge(8, 9,3);
graph.setIn();
// graph.print();
graph.topologicalSort();
}
}