原博文:minfanphd
任务计划
第31天:整数矩阵及其运算
有关矩阵在1到10天的时候就已经接触过了,本次的工作量主要是将矩阵的一些运算给加进去了。
在java中this()代表的是调用无参构造函数,若括号里有值则调用的是相应的构造函数。
package matrix;
import java.util.Arrays;
/**
* @description:
* @author: Qing Zhang
* @time: 2021/6/11
*/
public class IntMatrix {
//数据
int[][] data;
/**
* @Description: 构造函数
* @Param: [paraRows, paraColumns]
* @return:
*/
public IntMatrix(int paraRows, int paraColumns) {
data = new int[paraRows][paraColumns];
}
/**
* @Description: 第二个构造函数
* @Param: [paraMatrix]
* @return:
*/
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];
}
}
}
/**
* @Description: 第三个构造函数
* @Param: [paraMatrix]
* @return:
*/
public IntMatrix(IntMatrix paraMatrix) {
this(paraMatrix.getData());
}
/**
* @Description: 获取单位矩阵
* @Param: [paraRows]
* @return: matrix.IntMatrix
*/
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;
}
@Override
public String toString() {
return Arrays.deepToString(data);
}
/**
* @Description: 获取自己的数据
* @Param: []
* @return: int[][]
*/
public int[][] getData() {
return data;
}
/**
* @Description: 获取矩阵行
* @Param: []
* @return: int
*/
public int getRows() {
return data.length;
}
/**
* @Description: 获取矩阵列
* @Param: []
* @return: int
*/
public int getColumns() {
return data[0].length;
}
/**
* @Description: 设置某个位置的值
* @Param: [paraRow, paraColumn, paraValue]
* @return: void
*/
public void setValue(int paraRow, int paraColumn, int paraValue) {
data[paraRow][paraColumn] = paraValue;
}
/**
* @Description: 获取某个位置的值
* @Param: [paraRow, paraColumn]
* @return: int
*/
public int getValue(int paraRow, int paraColumn) {
return data[paraRow][paraColumn];
}
/**
* @Description: 矩阵相加
* @Param: [paraMatrix]
* @return: void
*/
public void add(IntMatrix paraMatrix) throws Exception {
//第一步是将目标矩阵的数据获取出来
int[][] tempData = paraMatrix.getData();
//第二部看两个矩阵大小是否匹配
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 + ".");
}
//第三步将两个矩阵的数据相加
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[0].length; j++) {
data[i][j] += tempData[i][j];
}
}
}
/**
* @Description: 两个给定的矩阵相加
* @Param: [paraMatrix1, paraMatrix2]
* @return: matrix.IntMatrix
*/
public static IntMatrix add(IntMatrix paraMatrix1, IntMatrix paraMatrix2) throws Exception {
//将第一个矩阵复制出来
IntMatrix resultMatrix = new IntMatrix(paraMatrix1);
//加上第二个矩阵
resultMatrix.add(paraMatrix2);
return resultMatrix;
}
/**
* @Description: 矩阵相乘
* @Param: [paraMatrix1, paraMatrix2]
* @return: matrix.IntMatrix
*/
public static IntMatrix multiply(IntMatrix paraMatrix1, IntMatrix paraMatrix2)
throws Exception {
//第一步匹配矩阵大小
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 + ".");
}
//第二步分配空间.
int[][] resultData = new int[tempData1.length][tempData2[0].length];
//第三步矩阵相乘
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];
}
}
}
//构造目标矩阵
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 = new IntMatrix(IntMatrix.multiply(tempMatrix1, tempMatrix1));
} catch (Exception e) {
System.out.println(e);
}
System.out.println("The square matrix is: " + tempMatrix2);
IntMatrix tempMatrix3 = new IntMatrix(tempMatrix2);
try {
tempMatrix3.add(tempMatrix1);
} catch (Exception e) {
System.out.println(e);
}
System.out.println("The connectivity matrix is: " + tempMatrix3);
}
}
第32天:图的连通性检测
检测原理:令邻接矩阵为 A A A,若 A + A 2 + A 3 + ⋯ + A ( n − 1 ) A+A^2+A^3+\dots+A^{(n-1)} A+A2+A3+⋯+A(n−1)不存在非零元素(不考虑对角线),则为连通,否则不连通。
package DataStructure.graph;
import matrix.IntMatrix;
/**
* @description:图
* @author: Qing Zhang
* @time: 2021/6/11
*/
public class Graph {
//连通矩阵
IntMatrix connectivityMatrix;
/**
* @Description: 第一个构造函数
* @Param: [paraNumNodes]
* @return:
*/
public Graph(int paraNumNodes) {
connectivityMatrix = new IntMatrix(paraNumNodes, paraNumNodes);
}
/**
* @Description: 第二个构造函数
* @Param: [paraMatrix]
* @return:
*/
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;
}
/**
* @Description: 判断连通性
* @Param: []
* @return: boolean
*/
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;
}
/**
* @Description: 测试
* @Param: []
* @return: void
*/
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();
}
}
第33天:图的广度优先遍历
从给定的点位置开始往后该点所在的行读取,将该行中的节点依次读入队列,往下依次读出再读入即可。
/**
* @Description: 广度优先遍历
* @Param: [paraStartIndex]
* @return: java.lang.String
*/
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(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(i);
}
tempInteger = (Integer)tempQueue.dequeue();
}
return resultString;
}
/**
* @Description: 测试广度优先遍历
* @Param: []
* @return: void
*/
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(0);
} catch (Exception e) {
System.out.println(e);
}
System.out.println("The breadth first order of visit: " + tempSequence);
}
第34天:图的深度优先遍历
利用栈去进行深度优先遍历,这里需要用到回溯,因此相比于广度优先遍历会更有难度一些,但是理清思路之后还是很容易的。关键在于理解邻接矩阵相关的概念。
/**
* @Description: 深度遍历
* @Param: [paraStartIndex]
* @return: java.lang.String
*/
public String depthFirstTraversal(int paraStartIndex) {
ObjectStack tempStack = new ObjectStack();
String resultString = "";
int tempNumNodes = connectivityMatrix.getRows();
boolean[] tempVisitedArray = new boolean[tempNumNodes];
tempVisitedArray[paraStartIndex] = true;
tempVisitedArray[paraStartIndex] = true;
resultString += paraStartIndex;
tempStack.push(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(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;
}
/**
* @Description: 深度遍历测试
* @Param: []
* @return: void
*/
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 e) {
System.out.println(e);
}
System.out.println("The depth first order of visit: " + tempSequence);
}
第35天:图的 m 着色问题
问题描述:
给定无向连通图G。图中每条边连接的2个顶点着不同颜色。求出所有着色的方案使得上述条件满足。颜色数量由自己设置。
//图的m着色
/**
* @Description: 着色
* @Param: [paraNumColors]
* @return: void
*/
public void coloring(int paraNumColors) {
//初始化
int tpNumNodes = connectivityMatrix.getColumns();
int[] tpColorScheme = new int[tpNumNodes];
Arrays.fill(tpColorScheme, -1);
coloring(paraNumColors, 0, tpColorScheme);
}
/**
* @Description: 着色。输出所有可能的方式
* @Param: [paraNumColors(颜色数量), paraCurNumNodes, paraCurColoring]
* @return: void
*/
private void coloring(int paraNumColors, int paraCurNumNodes, int[] paraCurColoring) {
int tpNumNodes = connectivityMatrix.getColumns();
System.out.println("coloring: paraNumColors = " + paraNumColors + ", paraCurrentNumNodes = "
+ paraCurNumNodes + ", paraCurrentColoring" + Arrays.toString(paraCurColoring));
//说明已经完成了所有节点的颜色分配
if (paraCurNumNodes >= tpNumNodes) {
System.out.println("Find one:" + Arrays.toString(paraCurColoring));
return;
}
//尝试所有可能的颜色
for (int i = 0; i < paraNumColors; i++) {
paraCurColoring[paraCurNumNodes] = i;
if (!colorConflict(paraCurNumNodes + 1, paraCurColoring)) {
coloring(paraNumColors, paraCurNumNodes + 1, paraCurColoring);
}
}
}
/**
* @Description: 着色是否冲突。只将当前节点与相连接的节点比较
* @Param: [paraCurNumNodes, paraCurColoring]
* @return: boolean
*/
private boolean colorConflict(int paraCurNumNodes, int[] paraCurColoring) {
for (int i = 0; i < paraCurNumNodes - 1; i++) {
//先判断当前节点与哪些节点相连接
if (connectivityMatrix.getValue(paraCurNumNodes - 1, i) == 0) {
continue;
}
//若连接,则判断它们的颜色是否相同
if (paraCurColoring[paraCurNumNodes - 1] == paraCurColoring[i]) {
return true;
}
}
return false;
}
/**
* @Description: 着色测试
* @Param: []
* @return: void
*/
public static void coloringTest() {
int[][] tempMatrix = { { 0, 1, 1, 0 }, { 1, 0, 0, 1 }, { 1, 0, 0, 0 }, { 0, 1, 0, 0 } };
Graph tempGraph = new Graph(tempMatrix);
tempGraph.coloring(3);
}
第36天:邻连表
package DataStructure.graph;
import DataStructure.LinkedList;
import DataStructure.queue.CircleObjectQueue;
import DataStructure.stack.ObjectStack;
/**
* @description:邻接表
* @author: Qing Zhang
* @time: 2021/6/17
*/
public class NeighborList {
class NeighborNode {
//图序号
int data;
//下一节点
NeighborNode next;
public NeighborNode(int data) {
this.data = data;
next = null;
}
}
//节点数量
int numNodes;
//每行的头节点
NeighborNode[] headers;
/**
* @Description: 构造函数
* @Param: [paraMatrix]
* @return:
*/
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;
}
/**
* @Description: 广度优先遍历
* @Param: [paraStartIndex]
* @return: java.lang.String
*/
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;
}
/**
* @Description: 广度优先遍历测试
* @Param: []
* @return: void
*/
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);
}
/**
* @Description: 深度优先遍历
* @Param: [paraStartIndex]
* @return: java.lang.String
*/
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;
}
/**
* @Description: 深度优先遍历测试
* @Param: []
* @return: void
*/
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();
}
}
第37天:十字链表
十字链表是为了便于求得图中顶点的度(出度和入度)而提出来的。它是综合邻接表和逆邻接表形式的一种链式存储结构。其中实现此种数据结构的难点主要在于链接上入节点。
package DataStructure.graph;
/**
* @description:十字链表
* @author: Qing Zhang
* @time: 2021/6/15
*/
public class OrthogonalList {
class OrthogonalNode {
//行数
int row;
//列数
int column;
//出节点
OrthogonalNode nextOut;
//入节点
OrthogonalNode nextIn;
public OrthogonalNode(int row, int column) {
this.row = row;
this.column = column;
nextIn = null;
nextOut = null;
}
}
//节点的数量
int numNodes;
//每行的起始节点
OrthogonalNode[] headers;
public OrthogonalList(int[][] paraMatrix) {
numNodes = paraMatrix.length;
//第一步初始化。头节点中数据是无特殊意义的
OrthogonalNode tpPreNode, tpNode;
headers = new OrthogonalNode[numNodes];
//第二步链接出节点
for (int i = 0; i < numNodes; i++) {
headers[i] = new OrthogonalNode(i, -1);
tpPreNode = headers[i];
for (int j = 0; j < numNodes; j++) {
if (paraMatrix[i][j] == 0) {
continue;
}
tpNode = new OrthogonalNode(i, j);
tpPreNode.nextOut = tpNode;
tpPreNode = tpNode;
}
}
//第三步链接入节点
OrthogonalNode[] tpColumnNodes = new OrthogonalNode[numNodes];
for (int i = 0; i < numNodes; i++) {
tpColumnNodes[i] = headers[i];
}
for (int i = 0; i < numNodes; i++) {
tpNode = headers[i].nextOut;
while(tpNode!=null){
tpColumnNodes[tpNode.column].nextIn = tpNode;
tpColumnNodes[tpNode.column] = tpNode;
tpNode = tpNode.nextOut;
}
}
}
public String toString() {
String resultString = "Out arcs: \n";
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: \n";
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);
}
}
第38天:Dijkstra 算法与 Prim 算法
Dijkstra:求单源最短路径
Prim:求最小生成树
package DataStructure.graph;
import matrix.IntMatrix;
import java.util.Arrays;
/**
* @description:加权图
* @author: Qing Zhang
* @time: 2021/6/15
*/
public class Net {
//最大距离
public static final int MAX_DISTANCE = 10000;
//节点数量
int numNodes;
IntMatrix weightMatrix;
/**
* @Description: 构造函数
* @Param: [paraNumNodes]
* @return:
*/
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);
}
}
/**
* @Description: 构造函数
* @Param: [paraMatrix]
* @return:
*/
public Net(int[][] paraMatrix) {
weightMatrix = new IntMatrix(paraMatrix);
numNodes = weightMatrix.getRows();
}
@Override
public String toString() {
String resultString = "This is the weight matrix of the graph.\r\n" + weightMatrix;
return resultString;
}
/**
* @Description: 单源最短路径
* @Param: [paraSource(目标节点到每个节点的最短路径)]
* @return: int[]
*/
public int[] shortestPath(int paraSource) {
//初始化
int[] tpDistanceArray = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
tpDistanceArray[i] = weightMatrix.getValue(paraSource, i);
}
int[] tpParentArray = new int[numNodes];
Arrays.fill(tpParentArray, paraSource);
// -1 视为无父节点
tpParentArray[paraSource] = -1;
//已被访问的节点
boolean[] tpVistedArray = new boolean[numNodes];
//表示自己直接跳过
tpVistedArray[paraSource] = true;
//循环找
int tpMinDistance;
int tpBestNode = -1;
for (int i = 0; i < numNodes - 1; i++) {
//找到最优的下一节点
tpMinDistance = Integer.MAX_VALUE;
for (int j = 0; j < numNodes; j++) {
if (tpVistedArray[j]) {
continue;
}
//与每个节点作比较找到最优节点
if (tpMinDistance > tpDistanceArray[j]) {
tpMinDistance = tpDistanceArray[j];
tpBestNode = j;
}
}
tpVistedArray[tpBestNode] = true;
for (int j = 0; j < numNodes; j++) {
if (tpVistedArray[j]) {
continue;
}
//该情况为当前节点未连接到另一节点
if (weightMatrix.getValue(tpBestNode, j) >= MAX_DISTANCE) {
continue;
}
if (tpDistanceArray[j] > tpDistanceArray[tpBestNode]
+ weightMatrix.getValue(tpBestNode, j)) {
tpDistanceArray[j] = tpDistanceArray[tpBestNode]
+ weightMatrix.getValue(tpBestNode, j);
//改变父节点
tpParentArray[j] = tpBestNode;
}
}
//仅作测试
System.out.println("The distance to each node: " + Arrays.toString(tpDistanceArray));
System.out.println("The parent of each node: " + Arrays.toString(tpParentArray));
}
//输出
System.out.println("Finally");
System.out.println("The distance to each node: " + Arrays.toString(tpDistanceArray));
System.out.println("The parent of each node: " + Arrays.toString(tpParentArray));
return tpDistanceArray;
}
/**
* @Description: 普利姆算法
* @Param: []
* @return: int
*/
public int prim() {
//初始化
//任何节点都可以作为起始节点
int tpSource = 0;
int[] tpDistanceArray = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
tpDistanceArray[i] = weightMatrix.getValue(tpSource, i);
}
int[] tpParentArray = new int[numNodes];
Arrays.fill(tpParentArray, tpSource);
tpParentArray[tpSource] = -1;
boolean[] tpVisitedArray = new boolean[numNodes];
tpVisitedArray[tpSource] = true;
int tpMinDistance;
int tpBestNode = -1;
for (int i = 0; i < numNodes - 1; i++) {
tpMinDistance = Integer.MAX_VALUE;
for (int j = 0; j < numNodes; j++) {
if (tpVisitedArray[j]) {
continue;
}
if (tpMinDistance > tpDistanceArray[j]) {
tpMinDistance = tpDistanceArray[j];
tpBestNode = j;
}
}
tpVisitedArray[tpBestNode] = true;
for (int j = 0; j < numNodes; j++) {
if (tpVisitedArray[j]) {
continue;
}
//该情况为当前节点未连接到另一节点
if (weightMatrix.getValue(tpBestNode, j) >= MAX_DISTANCE) {
continue;
}
if (tpDistanceArray[j] > weightMatrix.getValue(tpBestNode, j)) {
tpDistanceArray[j] = weightMatrix.getValue(tpBestNode, j);
//改变父节点
tpParentArray[j] = tpBestNode;
}
}
System.out.println(
"The selected distance for each node: " + Arrays.toString(tpDistanceArray));
System.out.println("The parent of each node: " + Arrays.toString(tpParentArray));
}
int resCost = 0;
for (int i = 0; i < numNodes; i++) {
resCost += tpDistanceArray[i];
}
System.out.println("Finally");
System.out.println("The parent of each node: " + Arrays.toString(tpParentArray));
System.out.println("The total cost: " + resCost);
return resCost;
}
public static void main(String[] args) {
Net tempNet = new Net(3);
System.out.println(tempNet);
int[][] tempMatrix = { { 0, 9, 3, 6 }, { 5, 0, 2, 4 }, { 3, 2, 0, 1 }, { 2, 8, 7, 0 } };
tempNet = new Net(tempMatrix);
System.out.println(tempNet);
tempNet.shortestPath(1);
tempNet.prim();
}
}
第39天:关键路径
在今天中主要需要理解拓扑排序和关键路径的概念,其中拓扑排序是完成关键路径计算的重要一环。
拓扑排序:拓扑排序是对有向无环图的顶点的一种排序,它使得若存在一条从顶点A到顶点B的路径,则在排序中顶点B出现在顶点A的后面。
关键路径:我的理解是完成整个工程的最短时间序列。
代码中的难点主要在于求最早开始时间和最迟开始时间,但是将这两个数据求出来后就可以直接判断关键路径中的关键活动。
/**
* @Description: 关键路径
* 由0开始,目标为最后一个节点
* @Param: []
* @return: boolean[]
*/
public boolean[] criticalPath() {
int tpValue;
//存储每个节点的入度
int[] tpInDegrees = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
for (int j = 0; j < numNodes; j++) {
if (weightMatrix.getValue(i, j) != -1) {
tpInDegrees[j]++;
}
}
}
System.out.println("In-degree of nodes: " + Arrays.toString(tpInDegrees));
//拓扑排序
//每个节点的最早开始时间
int[] tpEarliestTimeArray = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
//这里的节点不能被移除
if (tpInDegrees[i] > 0) {
continue;
}
System.out.println("Removing " + i);
for (int j = 0; j < numNodes; j++) {
//将当前每个节点之前的关键路径长度计算出来
if (weightMatrix.getValue(i, j) != -1) {
tpValue = tpEarliestTimeArray[i] + weightMatrix.getValue(i, j);
if (tpEarliestTimeArray[j] < tpValue) {
tpEarliestTimeArray[j] = tpValue;
}
//移除节点后减去相应的入度
tpInDegrees[j]--;
}
}
}
System.out.println("Earlest start time: " + Arrays.toString(tpEarliestTimeArray));
//每个节点的出度
int[] tpOutDegrees = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
for (int j = 0; j < numNodes; j++) {
if (weightMatrix.getValue(i, j) != -1) {
tpOutDegrees[i]++;
}
}
}
System.out.println("Out-degree of nodes: " + Arrays.toString(tpOutDegrees));
//反转拓扑排序
//每个节点的最晚开始时间
int[] tpLatestTimeArray = new int[numNodes];
for (int i = 0; i < numNodes; i++) {
//注意!!!
tpLatestTimeArray[i] = tpEarliestTimeArray[numNodes - 1];
}
System.out.println("tpLatestTimeArray: " + Arrays.toString(tpLatestTimeArray));
for (int i = numNodes - 1; i >= 0; i--) {
if (tpOutDegrees[i] > 0) {
continue;
}
System.out.println("Removing " + i);
//计算最迟开始时间
//
for (int j = 0; j < numNodes; j++) {
if (weightMatrix.getValue(j, i) != -1) {
tpValue = tpLatestTimeArray[i] - weightMatrix.getValue(j, i);
if (tpLatestTimeArray[j] > tpValue) {
tpLatestTimeArray[j] = tpValue;
}
tpOutDegrees[j]--;
System.out.println("The out-degree of " + j + " decreases by 1.");
}
}
}
System.out.println("Latest start time: " + Arrays.toString(tpLatestTimeArray));
//如果最早开始时间==最迟开始时间,则表明该节点为关键路径中的一员
boolean[] resultCriticalArray = new boolean[numNodes];
for (int i = 0; i < numNodes; i++) {
if (tpEarliestTimeArray[i] == tpLatestTimeArray[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 tempNet = new Net(3);
System.out.println(tempNet);
int[][] tempMatrix = {{0, 9, 3, 6}, {5, 0, 2, 4}, {3, 2, 0, 1}, {2, 8, 7, 0}};
tempNet = new Net(tempMatrix);
System.out.println(tempNet);
tempNet.shortestPath(1);
tempNet.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();
}
第40天:小结
- 了解了在java中使用 this() 的含义。
- 再次复习了图的相关知识,之前对这些知识都是去理解,但并未通过代码将其实现出来。
- 从这十天的了解发现矩阵在算法中的重要作用。
- 了解了有关图的一个经典问题,图的m着色问题。
- 邻接矩阵可以表示无向图和有向图。
- 邻接表可以表示无向图和有向图。
- 十字链表只能表示有向图。
- 再次复习了Dijkstra和Prim算法,前者主要是用来求单源最短路径,后者主要是求最小生成树,处理对象都是带权值边的图,前者主要是计算出两个节点的最短路径,后者主要是将所有节点连接起来,使边最少,且边的权值之和也为最小。
- 关键路径的算法中,拓扑排序尤为重要,当然其中的最早发生时间和最迟发生时间的求取方式可能稍微有点难理解,但仔细品味即可理解其中的奥妙。
- 最后这十天可以明显感受到代码量提升了很多,因此需要细细去理会其中算法设计的原理,即为什么要去这么编写代码,同时保持好奇,才能将这其中的代码理解透彻。