持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情
接昨天内容 对十字链表做了梳理 今天对十字链表构造进行代码分析
代码分析
昨天我们讨论到数组的引用:
a数组引用地址 [I@3339ad8e
a数组引用地址 [I@3339ad8e
看数据赋值的内容:
所以让数组b直接指向数组a,(我们就可以理解为将a数组起个别名b,他们指向的是同一个对象,这就类似c语言中的指针)所以当b=a实际上是将a的引用地址赋值给b,所以b改动a也会随之改动。
在代码中这里的tempColumnNodes和headers数组就是引用传递,当修改tempColumnNodes时,headers也会随之改动
OrthogonalNode[] tempColumnNodes = new OrthogonalNode[numNodes];
for (int i = 0; i < numNodes; i++) {
tempColumnNodes[i] = headers[i];
}
十字链表的构造 我觉得十字链表的初始化比之前邻接矩阵和邻接表的初始化都更难,相比领接表容易找到出度,逆邻接表容易找到入度。十字链表即能很容易找到入度也很容易找到出度,所以他的数据结构也复杂一些。结合上面的知识和代码,可以将十字链表的初始化分为两部分,先初始化他的出度的链接,再初始化他入度的链接。
对于初始化出度的链接,判断出度是否为0,可以借助矩阵paraMatrix[i][j] == 0,i行j列表示i是否指向j(即是否以i顶点为弧尾)
对于初始化入度的链接,是遍历每一个头节点所链接的弧节点,使每个弧节点的第三个域去链接弧头相同的节点,其中第一个链接的一定是从头节点出发,其中弧节点的第二个域(即代码中的column)代表的是头节点的位置。如代码中的tempColumnNodes[tempNode.column].nextIn。
链接一个节点后要及时移动位置。感觉这段代码用语言不好描述,一定要图上模拟才更容易理解。
public OrthogonalList(int[][] paraMatrix) {
numNodes = paraMatrix.length;
//Step 1. Initialize. The data in the headers are not meaningful.
OrthogonalNode tempPreviousNode, tempNode;
headers = new OrthogonalNode[numNodes];
//Step 2. Link to its out nodes.
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;
}
}
//Step3. Link to its in nodes. This step is harder.
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;
}
}
}
测试:
程序运行的结果:
The data are:
(0, 1)
(1, 3)
(2, 0)
(3, 1) (3, 2)
In arcs: (2, 0)
(0, 1) (3, 1)
(3, 2)
(1, 3)
总结:
十字链表我感觉比之前的存储结构都复杂,也花了一些时间去理解,在理解十字链表的过程中,画图很重要,如果直接去看代码可能会很吃力,在今天的代码中对节点入度的初始化,只用了几行代码就实现了,但理解时我还是结合图去理解。