Day31:整数矩阵及其运算
import java.util.Arrays;
public class IntMatrix {
//数据
int[][] data;
//构造函数
public IntMatrix(int paraRows, int paraColumns) {
data = new int[paraRows][paraColumns];
}
//第二个构造函数
public IntMatrix(int[][] paraMatrix) {
data = new int[paraMatrix.length][paraMatrix[0].length];
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[0].length; j++) {
data[i][j] = paraMatrix[i][j];
}
}
}
//第三个构造函数
public IntMatrix(IntMatrix paraMatrix) {
this(paraMatrix.getData());
}
//获取单位矩阵
public static IntMatrix getIdentityMatrix(int paraRows) {
IntMatrix resultMatrix = new IntMatrix(paraRows, paraRows);
for (int i = 0; i < paraRows; i++) {
resultMatrix.data[i][i] = 1;
}
return resultMatrix;
}
public String toString() {
return Arrays.deepToString(data);
}
//获取数据
public int[][] getData() {
return data;
}
//获取矩阵行
public int getRows() {
return data.length;
}
//获取矩阵列
public int getColumns() {
return data[0].length;
}
//设置某个位置的值
public void setValue(int paraRow, int paraColumn, int paraValue) {
data[paraRow][paraColumn] = paraValue;
}
//获取某个位置的值
public int getValue(int paraRow, int paraColumn) {
return data[paraRow][paraColumn];
}
//矩阵相加
public void add(IntMatrix paraMatrix) throws Exception {
// Step 1. 获取目标矩阵的数据获取
int[][] tempData = paraMatrix.getData();
// Step 2. 比较矩阵大小是否匹配
if (data.length != tempData.length) {
throw new Exception("Cannot add matrices. Rows not match: " + data.length + " vs. "
+ tempData.length + ".");
}
if (data[0].length != tempData[0].length) {
throw new Exception("Cannot add matrices. Rows not match: " + data[0].length + " vs. "
+ tempData[0].length + ".");
}
// Step 3. 矩阵相加
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[0].length; j++) {
data[i][j] += tempData[i][j];
} /
} /
}
//两个矩阵相加
public static IntMatrix add(IntMatrix paraMatrix1, IntMatrix paraMatrix2) throws Exception {
// Step 1.复制第一个矩阵
IntMatrix resultMatrix = new IntMatrix(paraMatrix1);
// Step 2. 加上第二个矩阵
resultMatrix.add(paraMatrix2);
return resultMatrix;
}
//矩阵相乘
public static IntMatrix multiply(IntMatrix paraMatrix1, IntMatrix paraMatrix2)
throws Exception {
// Step 1. 匹配矩阵大小
int[][] tempData1 = paraMatrix1.getData();
int[][] tempData2 = paraMatrix2.getData();
if (tempData1[0].length != tempData2.length) {
throw new Exception("Cannot multiply matrices: " + tempData1[0].length + " vs. "
+ tempData2.length + ".");
}
// Step 2. 分配空间
int[][] resultData = new int[tempData1.length][tempData2[0].length];
// Step 3. 相乘
for (int i = 0; i < tempData1.length; i++) {
for (int j = 0; j < tempData2[0].length; j++) {
for (int k = 0; k < tempData1[0].length; k++) {
resultData[i][j] += tempData1[i][k] * tempData2[k][j];
}
}
}
// Step 4.构造目标函数
IntMatrix resultMatrix = new IntMatrix(resultData);
return resultMatrix;
}
public static void main(String args[]) {
IntMatrix tempMatrix1 = new IntMatrix(3, 3);
tempMatrix1.setValue(0, 1, 1);
tempMatrix1.setValue(1, 0, 1);
tempMatrix1.setValue(1, 2, 1);
tempMatrix1.setValue(2, 1, 1);
System.out.println("The original matrix is: " + tempMatrix1);
IntMatrix tempMatrix2 = null;
try {
tempMatrix2 = IntMatrix.multiply(tempMatrix1, tempMatrix1);
} catch (Exception ee) {
System.out.println(ee);
}
System.out.println("The square matrix is: " + tempMatrix2);
IntMatrix tempMatrix3 = new IntMatrix(tempMatrix2);
try {
tempMatrix3.add(tempMatrix1);
} catch (Exception ee) {
System.out.println(ee);
}
System.out.println("The connectivity matrix is: " + tempMatrix3);
}
}
Day32:图的连通性检测
令图的连通矩阵为 M ,M0=I 为单位矩阵。要知道图的连通性, 只需要计算 Ma=M0+M1+⋯+Mn−1,其中 n 是节点个数。Ma中第 i 行第 j 列元素为 0 的话, 就表示从节点 i 到节点 j 不可达。
package DataStructure.graph;
import matrix.IntMatrix;
public class Graph {
//连通矩阵
IntMatrix connectivityMatrix;
// 第一个构造函数
public Graph(int paraNumNodes) {
connectivityMatrix = new IntMatrix(paraNumNodes, paraNumNodes);
}
// 第二个构造函数
public Graph(int[][] paraMatrix) {
connectivityMatrix = new IntMatrix(paraMatrix);
}
public String toString() {
String resultString = "This is the connectivity matrix of the graph.\r\n"
+ connectivityMatrix;
return resultString;
}
//判断连通性
public boolean getConnectivity() throws Exception {
// 初始化单位矩阵
IntMatrix tempConnectivityMatrix = IntMatrix
.getIdentityMatrix(connectivityMatrix.getData().length);
// 初始化目标矩阵
IntMatrix tempMultipliedMatrix = new IntMatrix(connectivityMatrix);
// 计算矩阵
for (int i = 0; i < connectivityMatrix.getData().length - 1; i++) {
tempConnectivityMatrix.add(tempMultipliedMatrix);
tempMultipliedMatrix = IntMatrix.multiply(tempMultipliedMatrix, connectivityMatrix);
}
// 判断连通性
System.out.println("The connectivity matrix is: " + tempConnectivityMatrix);
int[][] tempData = tempConnectivityMatrix.getData();
for (int i = 0; i < tempData.length; i++) {
for (int j = 0; j < tempData.length; j++) {
if (tempData[i][j] == 0) {
System.out.println("Node " + i + " cannot reach " + j);
return false;
}
}
}
return true;
}
public static void getConnectivityTest() {
// 测试一个非连通图
int[][] tempMatrix = { { 0, 1, 0 }, { 1, 0, 1 }, { 0, 1, 0 } };
Graph tempGraph2 = new Graph(tempMatrix);
System.out.println(tempGraph2);
boolean tempConnected = false;
try {
tempConnected = tempGraph2.getConnectivity();
} catch (Exception e) {
System.out.println(e);
}
System.out.println("Is the graph connected? " + tempConnected);
// 测试一个连通图
tempGraph2.connectivityMatrix.setValue(1, 0, 0);
tempConnected = false;
try {
tempConnected = tempGraph2.getConnectivity();
} catch (Exception e) {
System.out.println(e);
}
System.out.println("Is the graph connected? " + tempConnected);
}
public static void main(String args[]) {
Graph tempGraph = new Graph(3);
System.out.println(tempGraph);
getConnectivityTest();
}
}
Day33:图的广度优先遍历
图的广度优先遍历与树的广度优先遍历类似,可以模仿着学习。
代码:
public String breadthFirstTraversal(int paraStartIndex) {
CircleObjectQueue tempQueue = new CircleObjectQueue();
String resultString = "";
int tempNumNodes = connectivityMatrix.getRows();
boolean[] tempVisitedArray = new boolean[tempNumNodes];
tempVisitedArray[paraStartIndex] = true;
//初始化队列
tempVisitedArray[paraStartIndex] = true;
resultString += paraStartIndex;
tempQueue.enqueue(new Integer(paraStartIndex));
//广度遍历
int tempIndex;
Integer tempInteger = (Integer)tempQueue.dequeue();
while (tempInteger != null) {
tempIndex = tempInteger.intValue();
//未访问的相邻点入队
for (int i = 0; i < tempNumNodes; i ++) {
if (tempVisitedArray[i]) {
continue;
}
if (connectivityMatrix.getData()[tempIndex][i] == 0) {
continue;
}
tempVisitedArray[i] = true;
resultString += i;
tempQueue.enqueue(new Integer(i));
}
//取队首元素
tempInteger = (Integer)tempQueue.dequeue();
}
return resultString;
}
public static void breadthFirstTraversalTest() {
// 测试无向图
int[][] tempMatrix = { { 0, 1, 1, 0 }, { 1, 0, 0, 1 }, { 1, 0, 0, 1}, { 0, 1, 1, 0} };
Graph tempGraph = new Graph(tempMatrix);
System.out.println(tempGraph);
String tempSequence = "";
try {
tempSequence = tempGraph.breadthFirstTraversal(2);
} catch (Exception ee) {
System.out.println(ee);
}
System.out.println("The breadth first order of visit: " + tempSequence);
}
public static void main(String args[]) {
System.out.println("Hello!");
Graph tempGraph = new Graph(3);
System.out.println(tempGraph);
getConnectivityTest();
breadthFirstTraversalTest();
}
Day34: 图的深度优先遍历
与二叉树的深度优先遍历类似; 又见 while (true), 循环的退出条件是栈为空;需要在前面 import ObjectStack 。
代码:
public String depthFirstTraversal(int paraStartIndex) {
ObjectStack tempStack = new ObjectStack();
String resultString = "";
int tempNumNodes = connectivityMatrix.getRows();
boolean[] tempVisitedArray = new boolean[tempNumNodes];
//初始化栈
tempVisitedArray[paraStartIndex] = true;
resultString += paraStartIndex;
tempStack.push(new Integer(paraStartIndex));
System.out.println("Push " + paraStartIndex);
System.out.println("Visited " + resultString);
//访问剩余点
int tempIndex = paraStartIndex;
int tempNext;
Integer tempInteger;
while (true){
//找到一个未访问的邻点
tempNext = -1;
for (int i = 0; i < tempNumNodes; i ++) {
if (tempVisitedArray[i]) {
continue;
}
if (connectivityMatrix.getData()[tempIndex][i] == 0) {
continue;
}
tempVisitedArray[i] = true;
resultString += i;
tempStack.push(new Integer(i));
System.out.println("Push " + i);
tempNext = i;
break;
}
if (tempNext == -1) {
//回溯未访问的邻点
if (tempStack.isEmpty()) {
break;
}
tempInteger = (Integer)tempStack.pop();
System.out.println("Pop " + tempInteger);
tempIndex = tempInteger.intValue();
} else {
tempIndex = tempNext;
}
}/
return resultString;
}
public static void depthFirstTraversalTest() {
// 测试一个无向图
int[][] tempMatrix = { { 0, 1, 1, 0 }, { 1, 0, 0, 1 }, { 1, 0, 0, 0}, { 0, 1, 0, 0} };
Graph tempGraph = new Graph(tempMatrix);
System.out.println(tempGraph);
String tempSequence = "";
try {
tempSequence = tempGraph.depthFirstTraversal(0);
} catch (Exception ee) {
System.out.println(ee);
}
System.out.println("The depth first order of visit: " + tempSequence);
}
public static void main(String args[]) {
System.out.println("Hello!");
Graph tempGraph = new Graph(3);
System.out.println(tempGraph);
getConnectivityTest();
breadthFirstTraversalTest();
depthFirstTraversalTest();
}
Day35:图的 m 着色问题
向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。是否有一种着色法使G中每条边的2个顶点着不同颜色。这个问题是图的m可着色判定问题。
代码:
package DataStructure.graph;
import DataStructure.LinkedList;
import DataStructure.queue.CircleObjectQueue;
import DataStructure.stack.ObjectStack;
public class NeighborList {
class NeighborNode {
//图序号
int data;
//下一节点
NeighborNode next;
public NeighborNode(int data) {
this.data = data;
next = null;
}
}
//节点数量
int numNodes;
//每行的头节点
NeighborNode[] headers;
public NeighborList(int[][] paraMatrix) {
numNodes = paraMatrix.length;
NeighborNode tpNode;
headers = new NeighborNode[numNodes];
//链接上每个节点相邻接的节点
for (int i = 0; i < numNodes; i++) {
headers[i] = new NeighborNode(i);
tpNode = headers[i];
for (int j = 0; j < numNodes; j++) {
if (paraMatrix[i][j] == 0) {
continue;
}
tpNode.next = new NeighborNode(j);
tpNode = tpNode.next;
}
}
}
public String toString() {
String resString = "NeighborList: \n";
NeighborNode tpNode;
for (int i = 0; i < numNodes; i++) {
tpNode = headers[i];
while (tpNode.next != null) {
resString += tpNode.data + "->";
tpNode = tpNode.next;
}
resString += tpNode.data + "\n";
}
return resString;
}
public String breadthFirstTraversal(int paraStartIndex) {
CircleObjectQueue tpQueue = new CircleObjectQueue();
String resString = "";
boolean[] tpVisitedArray = new boolean[numNodes];
tpVisitedArray[paraStartIndex] = true;
resString += paraStartIndex;
tpQueue.enqueue(paraStartIndex);
//利用节点去遍历
int tpIndex;
Integer tempInteger = (Integer) tpQueue.dequeue();
NeighborNode tpNode;
while (tempInteger != null) {
tpIndex = tempInteger.intValue();
tpNode = headers[tpIndex];
while (tpNode.next != null) {
tpNode = tpNode.next;
if (tpVisitedArray[tpNode.data]) {
continue;
}
tpQueue.enqueue(tpNode.data);
tpVisitedArray[tpNode.data] = true;
resString += tpNode.data;
}
tempInteger = (Integer) tpQueue.dequeue();
}
return resString;
}
//广度优先遍历
public static void breadthFirstTraversalTest() {
// Test an undirected graph.
int[][] tempMatrix = {{0, 1, 1, 0}, {1, 0, 0, 1}, {1, 0, 0, 1}, {0, 1, 1, 0}};
NeighborList tpNeighborList = new NeighborList(tempMatrix);
System.out.println(tpNeighborList);
String tempSequence = "";
try {
tempSequence = tpNeighborList.breadthFirstTraversal(2);
} catch (Exception e) {
System.out.println(e);
}
System.out.println("The breadth first order of visit: " + tempSequence);
}
//深度优先遍历
public String depthFirstTraversal(int paraStartIndex) {
ObjectStack tpStack = new ObjectStack();
String resString = "";
boolean[] tpVisitedArray = new boolean[numNodes];
tpVisitedArray[paraStartIndex] = true;
NeighborNode tpNode = headers[paraStartIndex];
;
resString += paraStartIndex;
tpStack.push(tpNode);
int num = 1;
while (num < numNodes) {
while (tpNode.next != null && tpVisitedArray[tpNode.next.data]) {
tpNode = tpNode.next;
}
//回溯
if (tpNode.next == null) {
tpNode = (NeighborNode) tpStack.pop();
continue;
}
resString += tpNode.next.data;
tpStack.push(tpNode.next);
tpVisitedArray[tpNode.next.data] = true;
tpNode = headers[tpNode.next.data];
num++;
}
return resString;
}
// 深度优先遍历测试
public static void depthFirstTraversalTest() {
// Test an undirected graph.
int[][] tempMatrix = {{0, 1, 1, 0}, {1, 0, 0, 1}, {1, 0, 0, 0}, {0, 1, 0, 0}};
NeighborList tpNeighborList = new NeighborList(tempMatrix);
System.out.println(tpNeighborList);
String tempSequence = "";
try {
tempSequence = tpNeighborList.depthFirstTraversal(0);
} catch (Exception ee) {
System.out.println(ee);
}
System.out.println("The depth first order of visit: " + tempSequence);
}
public static void main(String[] args) {
int[][] tempMatrix = {{0, 1, 0, 0}, {0, 0, 0, 1}, {1, 0, 0, 0}, {0, 1, 1, 0}};
NeighborList tpList = new NeighborList(tempMatrix);
System.out.println(tpList);
breadthFirstTraversalTest();
depthFirstTraversalTest();
}
}
Day36: 邻连表
相当于图的压缩存储. 每一行数据用一个单链表存储。重写了广度优先遍历。可以发现, 使用队列的机制不变.。仅仅是把其中的 for 循环换成了 while, 避免检查不存在的边.。如果图很稀疏的话, 可以降低时间复杂度。
代码:
package DataStructure.graph;
import DataStructure.LinkedList;
import DataStructure.queue.CircleObjectQueue;
import DataStructure.stack.ObjectStack;
public class NeighborList {
class NeighborNode {
//图序号
int data;
//下一节点
NeighborNode next;
public NeighborNode(int data) {
this.data = data;
next = null;
}
}
//节点数量
int numNodes;
//每行的头节点
NeighborNode[] headers;
//构造函数
public NeighborList(int[][] paraMatrix) {
numNodes = paraMatrix.length;
NeighborNode tpNode;
headers = new NeighborNode[numNodes];
//链接上每个节点相邻接的节点
for (int i = 0; i < numNodes; i++) {
headers[i] = new NeighborNode(i);
tpNode = headers[i];
for (int j = 0; j < numNodes; j++) {
if (paraMatrix[i][j] == 0) {
continue;
}
tpNode.next = new NeighborNode(j);
tpNode = tpNode.next;
}
}
}
@Override
public String toString() {
String resString = "NeighborList: \n";
NeighborNode tpNode;
for (int i = 0; i < numNodes; i++) {
tpNode = headers[i];
while (tpNode.next != null) {
resString += tpNode.data + "->";
tpNode = tpNode.next;
}
resString += tpNode.data + "\n";
}
return resString;
}
//广度优先遍历
public String breadthFirstTraversal(int paraStartIndex) {
CircleObjectQueue tpQueue = new CircleObjectQueue();
String resString = "";
boolean[] tpVisitedArray = new boolean[numNodes];
tpVisitedArray[paraStartIndex] = true;
resString += paraStartIndex;
tpQueue.enqueue(paraStartIndex);
//根据节点去遍历
int tpIndex;
Integer tempInteger = (Integer) tpQueue.dequeue();
NeighborNode tpNode;
while (tempInteger != null) {
tpIndex = tempInteger.intValue();
tpNode = headers[tpIndex];
while (tpNode.next != null) {
tpNode = tpNode.next;
if (tpVisitedArray[tpNode.data]) {
continue;
}
tpQueue.enqueue(tpNode.data);
tpVisitedArray[tpNode.data] = true;
resString += tpNode.data;
}
tempInteger = (Integer) tpQueue.dequeue();
}
return resString;
}
// 广度优先遍历测试
public static void breadthFirstTraversalTest() {
//测试无向图
int[][] tempMatrix = {{0, 1, 1, 0}, {1, 0, 0, 1}, {1, 0, 0, 1}, {0, 1, 1, 0}};
NeighborList tpNeighborList = new NeighborList(tempMatrix);
System.out.println(tpNeighborList);
String tempSequence = "";
try {
tempSequence = tpNeighborList.breadthFirstTraversal(2);
} catch (Exception e) {
System.out.println(e);
}
System.out.println("The breadth first order of visit: " + tempSequence);
}
//深度优先遍历
public String depthFirstTraversal(int paraStartIndex) {
ObjectStack tpStack = new ObjectStack();
String resString = "";
boolean[] tpVisitedArray = new boolean[numNodes];
tpVisitedArray[paraStartIndex] = true;
NeighborNode tpNode = headers[paraStartIndex];
;
resString += paraStartIndex;
tpStack.push(tpNode);
int num = 1;
while (num < numNodes) {
while (tpNode.next != null && tpVisitedArray[tpNode.next.data]) {
tpNode = tpNode.next;
}
//回溯
if (tpNode.next == null) {
tpNode = (NeighborNode) tpStack.pop();
continue;
}
resString += tpNode.next.data;
tpStack.push(tpNode.next);
tpVisitedArray[tpNode.next.data] = true;
tpNode = headers[tpNode.next.data];
num++;
}
return resString;
}
//深度优先遍历测试
public static void depthFirstTraversalTest() {
//测试无向图
int[][] tempMatrix = {{0, 1, 1, 0}, {1, 0, 0, 1}, {1, 0, 0, 0}, {0, 1, 0, 0}};
NeighborList tpNeighborList = new NeighborList(tempMatrix);
System.out.println(tpNeighborList);
String tempSequence = "";
try {
tempSequence = tpNeighborList.depthFirstTraversal(0);
} catch (Exception ee) {
System.out.println(ee);
}
System.out.println("The depth first order of visit: " + tempSequence);
}
public static void main(String[] args) {
int[][] tempMatrix = {{0, 1, 0, 0}, {0, 0, 0, 1}, {1, 0, 0, 0}, {0, 1, 1, 0}};
NeighborList tpList = new NeighborList(tempMatrix);
System.out.println(tpList);
breadthFirstTraversalTest();
depthFirstTraversalTest();
}
}
Day37:十字链表
十字链表是为了便于求得图中顶点的度(出度和入度)而提出来的。它是综合邻接表和逆邻接表形式的一种链式存储结构。
在十字链表存储结构中,有向图中的顶点的结构如下所示:
其中data表示顶点的具体数据信息,而firstIn则表示指向以该顶点为弧头的第一个弧节点。而firstOut则表示指向以该顶点为弧尾的第一个弧节点。
代码:
package datastructure.graph;
public class OrthogonalList {
class OrthogonalNode {
//行数
int row;
//列数
int column;
//出节点
OrthogonalNode nextOut;
//入节点
OrthogonalNode nextIn;
public OrthogonalNode(int paraRow, int paraColumn) {
row = paraRow;
column = paraColumn;
nextOut = null;
nextIn = null;
}
}
//节点数
int numNodes;
//每行的初始节点
OrthogonalNode[] headers;
public OrthogonalList(int[][] paraMatrix) {
numNodes = paraMatrix.length;
// Step 1. 初始化
OrthogonalNode tempPreviousNode, tempNode;
headers = new OrthogonalNode[numNodes];
// Step 2. 链接出节点
for (int i = 0; i < numNodes; i++) {
headers[i] = new OrthogonalNode(i, -1);
tempPreviousNode = headers[i];
for (int j = 0; j < numNodes; j++) {
if (paraMatrix[i][j] == 0) {
continue;
}
tempNode = new OrthogonalNode(i, j);
tempPreviousNode.nextOut = tempNode;
tempPreviousNode = tempNode;
}
}
// Step 3. 链接入节点
OrthogonalNode[] tempColumnNodes = new OrthogonalNode[numNodes];
for (int i = 0; i < numNodes; i++) {
tempColumnNodes[i] = headers[i];
}
for (int i = 0; i < numNodes; i++) {
tempNode = headers[i].nextOut;
while (tempNode != null) {
tempColumnNodes[tempNode.column].nextIn = tempNode;
tempColumnNodes[tempNode.column] = tempNode;
tempNode = tempNode.nextOut;
}
}
}
public String toString() {
String resultString = "Out arcs: ";
OrthogonalNode tempNode;
for (int i = 0; i < numNodes; i++) {
tempNode = headers[i].nextOut;
while (tempNode != null) {
resultString += " (" + tempNode.row + ", " + tempNode.column + ")";
tempNode = tempNode.nextOut;
}
resultString += "\r\n";
}
resultString += "\r\nIn arcs: ";
for (int i = 0; i < numNodes; i++) {
tempNode = headers[i].nextIn;
while (tempNode != null) {
resultString += " (" + tempNode.row + ", " + tempNode.column + ")";
tempNode = tempNode.nextIn;
}
resultString += "\r\n";
}
return resultString;
}
public static void main(String args[]) {
int[][] tempMatrix = { { 0, 1, 0, 0 }, { 0, 0, 0, 1 }, { 1, 0, 0, 0 }, { 0, 1, 1, 0 } };
OrthogonalList tempList = new OrthogonalList(tempMatrix);
System.out.println("The data are:\r\n" + tempList);
}
}
Day38: Dijkstra 算法与 Prim 算法
迪杰斯特拉算法(Dijkstra算法)是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。
普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点,且其所有边的权值之和亦为最小。
代码:
package datastructure.graph;
import java.util.Arrays;
import matrix.IntMatrix;
public class Net {
//最大距离
public static final int MAX_DISTANCE = 10000;
//节点数
int numNodes;
//权重矩阵
IntMatrix weightMatrix;
public Net(int paraNumNodes) {
numNodes = paraNumNodes;
weightMatrix = new IntMatrix(numNodes, numNodes);
for (int i = 0; i < numNodes; i++) {
Arrays.fill(weightMatrix.getData()[i], MAX_DISTANCE);
}
}
public Net(int[][] paraMatrix) {
weightMatrix = new IntMatrix(paraMatrix);
numNodes = weightMatrix.getRows();
}
public String toString() {
String resultString = "This is the weight matrix of the graph.\r\n" + weightMatrix;
return resultString;
}
//The Dijkstra 算法: 目标节点到每个节点的最短路径.
public int[] dijkstra(int paraSource) {
// Step 1. 初始化
int[] tempDistanceArray = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
tempDistanceArray[i] = weightMatrix.getValue(paraSource, i);
}
int[] tempParentArray = new int[numNodes];
Arrays.fill(tempParentArray, paraSource);
// -1 表示无父节点
tempParentArray[paraSource] = -1;
// 以访问的节点跳过
boolean[] tempVisitedArray = new boolean[numNodes];
tempVisitedArray[paraSource] = true;
// Step 2. 主循环
int tempMinDistance;
int tempBestNode = -1;
for (int i = 0; i < numNodes - 1; i++) {
// Step 2.1 找出一个最佳节点
tempMinDistance = Integer.MAX_VALUE;
for (int j = 0; j < numNodes; j++) {
// 这个节点被访问.
if (tempVisitedArray[j]) {
continue;
}
if (tempMinDistance > tempDistanceArray[j]) {
tempMinDistance = tempDistanceArray[j];
tempBestNode = j;
}
}
tempVisitedArray[tempBestNode] = true;
// Step 2.2 准备下一轮
for (int j = 0; j < numNodes; j++) {
// 节点被访问
if (tempVisitedArray[j]) {
continue;
}
// 节点不能到达
if (weightMatrix.getValue(tempBestNode, j) >= MAX_DISTANCE) {
continue;
} /
if (tempDistanceArray[j] > tempDistanceArray[tempBestNode]
+ weightMatrix.getValue(tempBestNode, j)) {
// 修改距离
tempDistanceArray[j] = tempDistanceArray[tempBestNode]
+ weightMatrix.getValue(tempBestNode, j);
// 修改父节点
tempParentArray[j] = tempBestNode;
}
}
//测试
System.out.println("The distance to each node: " + Arrays.toString(tempDistanceArray));
System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));
}
// Step 3. 输出
System.out.println("Finally");
System.out.println("The distance to each node: " + Arrays.toString(tempDistanceArray));
System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));
return tempDistanceArray;
}
//普利姆算法
public int prim() {
// Step 1. 初始化
//任何节点都可以作为起始节点
int tempSource = 0;
int[] tempDistanceArray = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
tempDistanceArray[i] = weightMatrix.getValue(tempSource, i);
}
int[] tempParentArray = new int[numNodes];
Arrays.fill(tempParentArray, tempSource);
tempParentArray[tempSource] = -1;
boolean[] tempVisitedArray = new boolean[numNodes];
tempVisitedArray[tempSource] = true;
// Step 2. 主循环
int tempMinDistance;
int tempBestNode = -1;
for (int i = 0; i < numNodes - 1; i++) {
// Step 2.1 找出一个最佳节点
tempMinDistance = Integer.MAX_VALUE;
for (int j = 0; j < numNodes; j++) {
// 这个节点被访问.
if (tempVisitedArray[j]) {
continue;
}
if (tempMinDistance > tempDistanceArray[j]) {
tempMinDistance = tempDistanceArray[j];
tempBestNode = j;
}
}
tempVisitedArray[tempBestNode] = true;
// Step 2.2 准备下一轮
for (int j = 0; j < numNodes; j++) {
// 节点被访问
if (tempVisitedArray[j]) {
continue;
}
// 节点不能到达
if (weightMatrix.getValue(tempBestNode, j) >= MAX_DISTANCE) {
continue;
}
// Attention: the difference from the Dijkstra algorithm.
if (tempDistanceArray[j] > weightMatrix.getValue(tempBestNode, j)) {
// 改变距离
tempDistanceArray[j] = weightMatrix.getValue(tempBestNode, j);
// 改变父节点
tempParentArray[j] = tempBestNode;
}
}
// 测试
System.out.println(
"The selected distance for each node: " + Arrays.toString(tempDistanceArray));
System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));
}
int resultCost = 0;
for (int i = 0; i < numNodes; i++) {
resultCost += tempDistanceArray[i];
}
// Step 3. 输出
System.out.println("Finally");
System.out.println("The parent of each node: " + Arrays.toString(tempParentArray));
System.out.println("The total cost: " + resultCost);
return resultCost;
}
public static void main(String args[]) {
Net tempNet0 = new Net(3);
System.out.println(tempNet0);
int[][] tempMatrix1 = { { 0, 9, 3, 6 }, { 5, 0, 2, 4 }, { 3, 2, 0, 1 }, { 2, 8, 7, 0 } };
Net tempNet1 = new Net(tempMatrix1);
System.out.println(tempNet1);
tempNet1.dijkstra(1);
int[][] tempMatrix2 = { { 0, 7, MAX_DISTANCE, 5, MAX_DISTANCE }, { 7, 0, 8, 9, 7 },
{ MAX_DISTANCE, 8, 0, MAX_DISTANCE, 5 }, { 5, 9, MAX_DISTANCE, 0, 15, },
{ MAX_DISTANCE, 7, 5, 15, 0 } };
Net tempNet2 = new Net(tempMatrix2);
tempNet2.prim();
}/
}
Day39: 关键路径
拓扑排序(Topological Sorting)是一个有向无环图的所有顶点的线性序列。且该序列必须满足下面两个条件:每个顶点出现且只出现一次。;若存在一条从顶点 A 到顶点 B 的路径,那么在序列中顶点 A 出现在顶点 B 的前面。
关键路径是指设计中从输入到输出经过的延时最长的逻辑路径。
代码:
//关键路径
public boolean[] criticalPath() {
int tempValue;
// Step 1. 存储每个节点的度数
int[] tempInDegrees = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
for (int j = 0; j < numNodes; j++) {
if (weightMatrix.getValue(i, j) != -1) {
tempInDegrees[j]++;
} /
}
}
System.out.println("In-degree of nodes: " + Arrays.toString(tempInDegrees));
// Step 2. 拓扑排序
int[] tempEarliestTimeArray = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
// 该节点不能移除
if (tempInDegrees[i] > 0) {
continue;
}
System.out.println("Removing " + i);
for (int j = 0; j < numNodes; j++) {
if (weightMatrix.getValue(i, j) != -1) {
tempValue = tempEarliestTimeArray[i] + weightMatrix.getValue(i, j);
if (tempEarliestTimeArray[j] < tempValue) {
tempEarliestTimeArray[j] = tempValue;
}
tempInDegrees[j]--;
}
}
}
System.out.println("Earlest start time: " + Arrays.toString(tempEarliestTimeArray));
// Step 3. 每个节点的出度
int[] tempOutDegrees = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
for (int j = 0; j < numNodes; j++) {
if (weightMatrix.getValue(i, j) != -1) {
tempOutDegrees[i]++;
}
}
}
System.out.println("Out-degree of nodes: " + Arrays.toString(tempOutDegrees));
// Step 4. 逆向拓扑排序
int[] tempLatestTimeArray = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
tempLatestTimeArray[i] = tempEarliestTimeArray[numNodes - 1];
}
for (int i = numNodes - 1; i >= 0; i--) {
// 该节点不能移除
if (tempOutDegrees[i] > 0) {
continue;
}
System.out.println("Removing " + i);
for (int j = 0; j < numNodes; j++) {
if (weightMatrix.getValue(j, i) != -1) {
tempValue = tempLatestTimeArray[i] - weightMatrix.getValue(j, i);
if (tempLatestTimeArray[j] > tempValue) {
tempLatestTimeArray[j] = tempValue;
}
tempOutDegrees[j]--;
System.out.println("The out-degree of " + j + " decreases by 1.");
}
}
}
System.out.println("Latest start time: " + Arrays.toString(tempLatestTimeArray));
boolean[] resultCriticalArray = new boolean[numNodes];
for (int i = 0; i < numNodes; i++) {
if (tempEarliestTimeArray[i] == tempLatestTimeArray[i]) {
resultCriticalArray[i] = true;
}
}
System.out.println("Critical array: " + Arrays.toString(resultCriticalArray));
System.out.print("Critical nodes: ");
for (int i = 0; i < numNodes; i++) {
if (resultCriticalArray[i]) {
System.out.print(" " + i);
}
}
System.out.println();
return resultCriticalArray;
}
public static void main(String args[]) {
Net tempNet0 = new Net(3);
System.out.println(tempNet0);
int[][] tempMatrix1 = { { 0, 9, 3, 6 }, { 5, 0, 2, 4 }, { 3, 2, 0, 1 }, { 2, 8, 7, 0 } };
Net tempNet1 = new Net(tempMatrix1);
System.out.println(tempNet1);
// Dijkstra算法
tempNet1.dijkstra(1);
int[][] tempMatrix2 = { { 0, 7, MAX_DISTANCE, 5, MAX_DISTANCE }, { 7, 0, 8, 9, 7 },
{ MAX_DISTANCE, 8, 0, MAX_DISTANCE, 5 }, { 5, 9, MAX_DISTANCE, 0, 15, },
{ MAX_DISTANCE, 7, 5, 15, 0 } };
Net tempNet2 = new Net(tempMatrix2);
tempNet2.prim();
int[][] tempMatrix3 = { { -1, 3, 2, -1, -1, -1 }, { -1, -1, -1, 2, 3, -1 },
{ -1, -1, -1, 4, -1, 3 }, { -1, -1, -1, -1, -1, 2 }, { -1, -1, -1, -1, -1, 1 },
{ -1, -1, -1, -1, -1, -1 } };
Net tempNet3 = new Net(tempMatrix3);
System.out.println("-------critical path");
tempNet3.criticalPath();
}
Day 40:小结
1.复习了矩阵的创建与运算,学习了Exception 的抛出与捕获机制;利用 this 调用其它的构造方法可以减少冗余代码。
2.通过实际操作体会到矩阵在图的算法中的重要作用。
3.图的联通性问题可以用矩阵解决。
4.图的广度优先遍历和深度优先遍历与树的类似,可以对比理解学习。
5.通过学习图的 m 着色问题学会了回溯算法。
6.十字链表只能表示有向图。
7.邻接表既可以表示有向图又可以表示无向图。
8.学写了Dijkstra 算法和 Prim 算法,Dijkstra 算法需要有向图;Prim 算法需要无向图。
9.在编写关键路径时,拓扑排序发挥重要作用。
10.代码越来越多,需要加强应用和理解。