十字链表简介与实现(Java)

十字链表简介与实现(Java)

结构

十字链表存储有向图(网)的方式与邻接表有一些相同,都以图(网)中各顶点为首元节点建立多条链表,同时为了便于管理,还将所有链表的首元节点存储到同一数组(或链表)中。

其中,建立个各个链表中用于存储顶点的首元节点结构如图 1 所示:

十字链表中首元节点结构示意图
图1

从图 1 可以看出,首元节点中有一个数据域和两个指针域(分别用 firstin 和 firstout 表示):
firstin 指针用于连接以当前顶点为弧头的其他顶点构成的链表;
firstout 指针用于连接以当前顶点为弧尾的其他顶点构成的链表;
data 用于存储该顶点中的数据;
由此可以看出,十字链表实质上就是为每个顶点建立两个链表,分别存储以该顶点为弧头的所有顶点和以该顶点为弧尾的所有顶点。

注意,存储图的十字链表中,各链表中首元节点与其他节点的结构并不相同,图 1 所示仅是十字链表中首元节点的结构,链表中其他普通节点的结构如图 2 所示:

十字链表中普通节点的结构示意图
图2

从图 2 中可以看出,十字链表中普通节点的存储分为 5 部分内容,它们各自的作用是:
tailvex 用于存储以首元节点为弧尾的顶点位于数组中的位置下标;
headvex 用于存储以首元节点为弧头的顶点位于数组中的位置下标;
hlink 指针:用于链接下一个存储以首元节点为弧头的顶点的节点;
tlink 指针:用于链接下一个存储以首元节点为弧尾的顶点的节点;
info 指针:用于存储与该顶点相关的信息,例如量顶点之间的权值;

比如说,用十字链表存储图 3a) 中的有向图,存储状态如图 3b) 所示:

十字链表存储有向图示意图
图 3

拿图 3 中的顶点 V1 来说,通过构建好的十字链表得知,以该顶点为弧头的顶点只有存储在数组中第 3 位置的 V4(因此该顶点的入度为 1),而以该顶点为弧尾的顶点有两个,分别为存储数组第 1 位置的 V2 和第 2 位置的 V3(因此该顶点的出度为 2)。

对于图 3 各个链表中节点来说,由于表示的都是该顶点的出度或者入度,因此没有先后次序之分。

实现

package test;
public class OListDG {
    int vlen; // 顶点个数
    int elen; // 边个数
    VertexNode[] vertexNodeList; // 顶点数组
    EdgeNode edgeNode;
 
    /**
     * 构造函数
     * @param vexs
     * @param edges
     */
    public OListDG(char[] vexs, char[][] edges) {
        vlen = vexs.length;
        elen = edges.length;
 
        // 初始化顶点,建立顶点表
        vertexNodeList = new VertexNode[vlen];
        for (int i = 0; i < vlen; i++) {
            vertexNodeList[i] = new VertexNode();
            vertexNodeList[i].vertex = vexs[i];
            vertexNodeList[i].firstIn = null;
            vertexNodeList[i].firstOut = null;
        }
 
        // 初始化边,利用头插法建立十字链表
        for (int i = 0; i < elen; i++) {
            EdgeNode edgeNode_1 = new EdgeNode();
            EdgeNode edgeNode_2 = new EdgeNode();
            int vi = getPosition(edges[i][0], vexs);
            int vj = getPosition(edges[i][1], vexs);
             
            edgeNode_1.tailvex = vi;
            edgeNode_1.headvex = vj;
            edgeNode_1.taillink = vertexNodeList[vi].firstOut;
            vertexNodeList[vi].firstOut = edgeNode_1;
            
            edgeNode_2.tailvex = vi;
            edgeNode_2.headvex = vj;
            edgeNode_2.headlink = vertexNodeList[vj].firstIn;
            vertexNodeList[vj].firstIn = edgeNode_2;
 
        }
    }
 
    /**
     *  功能:顶点表结点结构
     *  参数:vertex --> 顶点域,存储顶点信息
     *       firstIn --> 入边表头指针,指向该顶点的入边表中第一个结点
     *       firstOut --> 出边表头指针,指向该顶点的出边表中第一个结点
     */
    private class VertexNode {
        char vertex; 
        EdgeNode firstIn;
        EdgeNode firstOut; 
    }
 
    /**
     *  功能:边表结点
     *  参数:tailvex --> 弧起点在顶点表的下标
     *        headvex --> 弧终点在顶点表的下标
     *        headlink --> 入边表指针域,指向终点相同的下一条边
     *        taillink --> 边表指针域,指向起点相同的下一条边
     */
    private class EdgeNode {
    	int tailvex;
    	int headvex;
    	EdgeNode headlink;
    	EdgeNode taillink;
    }
 
    /**
     *  功能:返回ch位置
     */
    private int getPosition(char ch, char[] vexs) {
        for (int i = 0; i < vlen; i++)
            if (vexs[i] == ch)
                return i;
        return -1;
    }
 
    /**
     *  功能:打印邻接表和逆邻接表
     */
    public void print() {
        System.out.printf("AdjList:\n");
        for (int i = 0; i < vlen; i++) {
            System.out.print(vertexNodeList[i].vertex + "-->");
            if (vertexNodeList[i].firstOut != null) {
                EdgeNode mEdgeNode = new EdgeNode();
                mEdgeNode = vertexNodeList[i].firstOut;
                System.out.print(mEdgeNode.headvex);
                while (mEdgeNode.taillink != null) {
                    mEdgeNode = mEdgeNode.taillink;
                    System.out.print(mEdgeNode.headvex);
                }
                System.out.print("\n");
            } else {
                System.out.print("\n");
            }
        }
        
        System.out.print("----------\n");
        
        System.out.printf("InvAdjList:\n");
        for (int i = 0; i < vlen; i++) {
            System.out.print(vertexNodeList[i].vertex + "<--");
            if (vertexNodeList[i].firstIn != null) {
                EdgeNode mEdgeNode = new EdgeNode();
                mEdgeNode = vertexNodeList[i].firstIn;
                System.out.print(mEdgeNode.tailvex);
                while (mEdgeNode.headlink != null) {
                    mEdgeNode = mEdgeNode.headlink;
                    System.out.print(mEdgeNode.tailvex);
                }
                System.out.print("\n");
            } else {
                System.out.print("\n");
            }
        }
    }
 
    /**
     * 主函数
     */
    public static void main(String args[]) {
    	// 顶点数组
        char[] vexs = {
            'A', 'B', 'C', 'D'
        };
        // 边数组
        char[][] edges = new char[][] {
            {
                'A', 'B'
            }, {
                'A', 'C'
            }, {
                'A', 'D'
            }, {
                'B', 'D'
            }, {
                'C', 'D'
            }
        };
 
        OListDG listUDG = new OListDG(vexs, edges);
        listUDG.print();
    }
}
以下是Java实现稀疏矩阵十字链表储存的示例代码: ```java //定义节点类 class OLNode { int row, col; int val; OLNode right, down; } //定义十字链表类 class CrossList { int rows, cols, nums; OLNode[] rowHeads, colHeads; //构造函数 public CrossList(int[][] matrix) { rows = matrix.length; cols = matrix[0].length; rowHeads = new OLNode[rows]; colHeads = new OLNode[cols]; //初始化行列头节点 for (int i = 0; i < rows; i++) { rowHeads[i] = new OLNode(); rowHeads[i].row = i; rowHeads[i].right = rowHeads[i]; } for (int j = 0; j < cols; j++) { colHeads[j] = new OLNode(); colHeads[j].col = j; colHeads[j].down = colHeads[j]; } //遍历矩阵,创建节点并插入十字链表 for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (matrix[i][j] != 0) { OLNode node = new OLNode(); node.row = i; node.col = j; node.val = matrix[i][j]; //插入行链表 OLNode p = rowHeads[i]; while (p.right != rowHeads[i] && p.right.col < j) { p = p.right; } node.right = p.right; p.right = node; //插入列链表 p = colHeads[j]; while (p.down != colHeads[j] && p.down.row < i) { p = p.down; } node.down = p.down; p.down = node; nums++; } } } } //打印十字链表 public void print() { for (int i = 0; i < rows; i++) { OLNode p = rowHeads[i].right; for (int j = 0; j < cols; j++) { if (p != rowHeads[i] && p.col == j) { System.out.print(p.val + " "); p = p.right; } else { System.out.print("0 "); } } System.out.println(); } } } //测试代码 public class Main { public static void main(String[] args) { int[][] matrix = {{1, 0, 0, 0}, {0, 2, 0, 0}, {0, 0, 3, 0}, {0, 0, 0, 4}}; CrossList crossList = new CrossList(matrix); crossList.print(); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值