图的存储之十字链表

对于有向图来说,邻接表是有缺陷的。关心了出度问题,要获取入度就必须要遍历整个图才能知道。在这里我们将要介绍十字链表。

1.知识点讲解

我们需要重新定义表结点结构如下图:

其中 firstin 表示边表头指针,指向该顶点的入边表中第一个结点,firstout 表示出边表的表头指针,指向该顶点的出边表中的第一个结点。

重新定义边表结点如下图:

其中 tailvex 是指弧起点在顶点表的下标,headvex 是指弧终点在顶点表中的下标,headlink 是指入边表指针域,指向终点相同的下一条边,taillink 是边表指针域,指向起点相同的下一条边。如果是网,可以再加一个 weight 域来存储权值。

如下图 A,顶点依然存入一个数组{V0,V1,V2,V3}。以顶点 V0 来说,firstout 指向出边表中的第一个结点 V3。所以 V0 边结点 的 headvex = 3,而 tailvex 其实就是当前结点 V0 的下标0,由于 V0 只有一个出边顶点,所以 headlink 和 taillink 都是空。

 

 我们重点讲解一下蓝色箭头的含义,他其实此图的逆邻接表的表示。对于 V0 来说,它有两个顶点V1 和 V2 的入边。因此 V0 的 firstin 指向顶点 V1 的边表结点中 headvex  为 0 的结点,就是①。接着由入边结点的 headlink 指向下一个入边顶点 V2,如②。对于 V1,有一个入边顶点 V2,所以它的 firstin 指向 V2 的边表结点中 headvex 为1的结点,如图中的③。顶点 V2 和 V3 也是同样有一个入边顶点,④和⑤。

十字链表的好处就是把邻接表和逆邻接表整合在了一起,这样既容易找到以 Vi 为尾的弧,也容易找到以 Vi 为头的弧,因而容易求得顶点的入度和出度。它除了复杂一点外,创建图算法的时间复杂度是和邻接表相同的,因此在有向图的应用中,十字链表是非常好的数据结构模型。

2.代码实现

这是测试图:

代码:

/**
 * 
 */
package datastructure.graph;

	 /**
	 ****************************
 	 * TODO
 	 * @author Chen Fan
 	 * @version 1.0
 	 * time 2022年1月23日
 	 ****************************
 	 */
public class OrthogonalList {
	// 内部结点
	class OrthogonalNode{
		// 行索引
		int row;
		// 列索引
		int column;
		// 下一个出结点
		OrthogonalNode nextOutNode;
		// 下一个入结点
		OrthogonalNode nextInNode;
		// 构造方法
		public OrthogonalNode(int paraRow, int paraColumn) {
			row = paraRow;
			column = paraColumn;
			nextInNode = null;
			nextOutNode = null;
		} // Of OrthogonalNode
	} // Of class OrthogonalNode
	
	// 结点的数目,可能是多余的,因为结点数始终等于headers.length
	int numNodes;
	
	// 每一行的表头
	OrthogonalNode[] headers;
	// 十字链表的构造方法
	public OrthogonalList(int[][] paraMatrix) {
		numNodes = paraMatrix.length;
		
		// 第一步:初始化十字链表,表头的数据域没有意义
		OrthogonalNode tempPreViousNode,tempNode;
		
		headers = new OrthogonalNode[numNodes];
		
		// 第二步:链接外部结点
		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;
				} // Of if
				
			// 创建一个新结点
			tempNode = new OrthogonalNode(i, j);
			
			// link
			tempPreViousNode.nextOutNode = tempNode;
			tempPreViousNode = tempNode;
			} // Of for j
		} // Of for i
		
		// 第三步:链接入结点,这一步更难
		OrthogonalNode[] tempColumnNodes = new OrthogonalNode[numNodes];
		for (int i = 0; i < numNodes; i++) {
			// 复制一遍表头数组
			tempColumnNodes[i] = headers[i];				
		} // Of for i
		
		for(int i = 0;i < numNodes;i++) {
			tempNode = headers[i].nextOutNode; // 表头第一个出结点
			while(tempNode != null) {
				// tempNode.column 列索引,就是回到入结点的位置,给它的入结点设置引用tempNode
				tempColumnNodes[tempNode.column].nextInNode = tempNode;
				tempColumnNodes[tempNode.column] = tempNode;
				
				tempNode = tempNode.nextOutNode;
			} // Of while 
		} // Of for i
	} // Of constructor
	
	public String toString() {
		String resultString = "Out arce: \n";
		
		OrthogonalNode tempNode;
		for (int i = 0; i < numNodes; i++) {
			tempNode = headers[i].nextOutNode;
			
			while(tempNode != null) {
				resultString +="(" + tempNode.row + "," + tempNode.column +")";
				tempNode = tempNode.nextOutNode;
			} // Of while
			resultString += "\r\n";
		} // Of for i
		
		resultString += "\r\n In arcs: \n";
		for (int i = 0; i < numNodes; i++) {
			tempNode = headers[i].nextInNode;
			while(tempNode != null) {
				resultString += " (" + tempNode.row + "," + tempNode.column + ")";
				tempNode = tempNode.nextInNode;
			} // Of while
			resultString += "\r\n";
		}// Of for i
		return resultString;
	} // Of toString
	
	// 测试程序入口
	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);
	}// Of main
}

代码需要讲解的在评论区留言哦!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值