基于C#实现十字链表

上一篇我们看了矩阵的顺序存储,这篇我们再看看一种链式存储方法“十字链表”,当然目的都是一样,压缩空间。

一、概念

既然要用链表节点来模拟矩阵中的非零元素,肯定需要如下 5 个元素(row,col,val,down,right),其中:

row:矩阵中的行。
col:矩阵中的列。
val:矩阵中的值。
right:指向右侧的一个非零元素。
down:指向下侧的一个非零元素。

image.png
现在我们知道单个节点该如何表示了,那么矩阵中同行的非零元素的表示不就是一个单链表吗?比如如下:
image.png
那么进一步来说一个多行的非零元素的表示不就是多个单链表吗,是的,这里我把单链表做成循环链表,我们来看看如何用十字链表来表示稀疏矩阵。
image.png
从上面的十字链表中要注意两个问题:
第一:这里有一个填充色的节点,是十字链表中的总结点,它是记录该矩阵中的(row,col,value)和一个指向下一个头节点的 next 指针。
第二:每个链表都有一个头指针,总结点用 next 指针将它们贯穿起来。

二、操作

2.1、数据结构

刚才也说了,十字链表的总结点有一个 next 指针,而其他非零节点没有,所以为了方便,我们用一个 Unit 类包装起来。

 #region 单一节点/// <summary>/// 单一节点/// </summary>public class Node{//行号public int rows;//列号public int cols;//向下的指针域public Node down;//向右的指针域public Node right;//单元值(头指针的next和val)public Unit unit;}#endregion#region 统一“表头节点”和“非零节点”/// <summary>/// 统一“表头节点”和“非零节点”/// </summary>public class Unit{//表头节点的next域public Node next;//非零元素的值public int value;}#endregion

2.2、初始化

这一步,我们初始化总结点,并且用 next 指针将每个单链表的头节点链接成单链表(也就是上图中十字链表的第一行)

#region 十字链表中的“行数,列数,非零元素个数”/// <summary>/// 十字链表中的“行数,列数,非零元素个数”/// </summary>/// <param name="rows"></param>/// <param name="cols"></param>/// <param name="count"></param>public void Init(int rows, int cols, int count){var len = Math.Max(rows, cols) + 1;//从下标1开始算起nodes = new Node[len];//十字链表的总头节点nodes[0] = new Node();nodes[0].rows = rows;nodes[0].cols = cols;nodes[0].unit = new Unit(){value = count,next = null,};//down和right都指向自身nodes[0].right = nodes[0];nodes[0].down = nodes[0];var temp = nodes[0];//初始化多条链表的头结点for (int i = 1; i < len; i++){nodes[i] = new Node();nodes[i].rows = 0;nodes[i].cols = 0;nodes[i].unit = new Unit(){value = 0,next = temp.unit.next};//给上一个节点的next域赋值temp.unit.next = nodes[i];//将当前节点作为下一次循环的上一个节点temp = nodes[i];nodes[i].right = nodes[i];nodes[i].down = nodes[i];}}#endregion

2.3、插入节点

根据插入节点的 row 和 col 将节点插入到十字链表中指定的位置即可。

#region 插入十字链表中/// <summary>/// 插入十字链表中/// </summary>/// <param name="nums">矩阵</param>/// <param name="rows">矩阵的行数</param>/// <param name="cols">矩阵的列数</param>/// <param name="count">非0元素个数</param>/// <returns></returns>public Node[] Insert(int[,] nums, int rows, int cols, int count){//初始化操作Init(rows, cols, count);//插入操作for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){//直插入"非0元素"if (nums[i, j] != 0){var node = new Node();node.rows = i + 1;node.cols = j + 1;node.unit = new Unit(){value = nums[i, j]};node.right = node;node.down = node;InsertNode(node);}}}return nodes;}#endregion

2.4、打印链表

我们只要遍历每行链表的 right 指针即可。

#region 打印十字链表/// <summary>/// 打印十字链表/// </summary>/// <param name="nodes"></param>public void Print(Node[] nodes){var head = nodes[0];//遍历每一行的rightfor (int i = 1; i < head.rows + 1; i++){var p = nodes[i];while (p.right != nodes[i]){Console.WriteLine("({0},{1})\tval => {2}",p.right.rows,p.right.cols,p.right.unit.value);//指向下一个节点p = p.right;}}}#endregion

2.5、总的代码:

 using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Diagnostics;using System.Threading;using System.IO;namespace ConsoleApplication2{public class Program{public static void Main(){Crosslist crosslist = new Crosslist();int[,] nums = {{2,0,4 },{0,3,0 },{0,0,9 }};var nodes = crosslist.Insert(nums, 3, 3, 4);crosslist.Print(nodes);Console.Read();}}/// <summary>/// 十字链表/// </summary>public class Crosslist{#region 单一节点/// <summary>/// 单一节点/// </summary>public class Node{//行号public int rows;//列号public int cols;//向下的指针域public Node down;//向右的指针域public Node right;//单元值(头指针的next和val)public Unit unit;}#endregion#region 统一“表头节点”和“非零节点”/// <summary>/// 统一“表头节点”和“非零节点”/// </summary>public class Unit{//表头节点的next域public Node next;//非零元素的值public int value;}#endregionNode[] nodes;#region 十字链表中的“行数,列数,非零元素个数”/// <summary>/// 十字链表中的“行数,列数,非零元素个数”/// </summary>/// <param name="rows"></param>/// <param name="cols"></param>/// <param name="count"></param>public void Init(int rows, int cols, int count){var len = Math.Max(rows, cols) + 1;//从下标1开始算起nodes = new Node[len];//十字链表的总头节点nodes[0] = new Node();nodes[0].rows = rows;nodes[0].cols = cols;nodes[0].unit = new Unit(){value = count,next = null,};//down和right都指向自身nodes[0].right = nodes[0];nodes[0].down = nodes[0];var temp = nodes[0];//初始化多条链表的头结点for (int i = 1; i < len; i++){nodes[i] = new Node();nodes[i].rows = 0;nodes[i].cols = 0;nodes[i].unit = new Unit(){value = 0,next = temp.unit.next};//给上一个节点的next域赋值temp.unit.next = nodes[i];//将当前节点作为下一次循环的上一个节点temp = nodes[i];nodes[i].right = nodes[i];nodes[i].down = nodes[i];}}#endregion#region 在指定的“行,列”上插入节点/// <summary>/// 在指定的“行,列”上插入节点/// </summary>/// <param name="node"></param>/// <returns></returns>public void InsertNode(Node node){//先定位行Node pnode = nodes[node.rows];//在指定的“行”中找,一直找到该行最后一个节点(right指针指向自己的为止)while (pnode.right != nodes[node.rows] && pnode.right.cols < node.cols)pnode = pnode.right;//将最后一个节点的right指向插入节点的right,以此达到是循环链表node.right = pnode.right;//将插入节点给最后一个节点的right指针上pnode.right = node;//再定位列pnode = nodes[node.cols];//同理while (pnode.down != nodes[node.cols] && pnode.down.rows < node.rows){pnode = pnode.down;}node.down = pnode.down;pnode.down = node;}#endregion#region 插入十字链表中/// <summary>/// 插入十字链表中/// </summary>/// <param name="nums">矩阵</param>/// <param name="rows">矩阵的行数</param>/// <param name="cols">矩阵的列数</param>/// <param name="count">非0元素个数</param>/// <returns></returns>public Node[] Insert(int[,] nums, int rows, int cols, int count){//初始化操作Init(rows, cols, count);//插入操作for (int i = 0; i < rows; i++){for (int j = 0; j < cols; j++){//直插入"非0元素"if (nums[i, j] != 0){var node = new Node();node.rows = i + 1;node.cols = j + 1;node.unit = new Unit(){value = nums[i, j]};node.right = node;node.down = node;InsertNode(node);}}}return nodes;}#endregion#region 打印十字链表/// <summary>/// 打印十字链表/// </summary>/// <param name="nodes"></param>public void Print(Node[] nodes){var head = nodes[0];//遍历每一行的rightfor (int i = 1; i < head.rows + 1; i++){var p = nodes[i];while (p.right != nodes[i]){Console.WriteLine("({0},{1})\tval => {2}",p.right.rows,p.right.cols,p.right.unit.value);//指向下一个节点p = p.right;}}}#endregion}}

image.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/173629.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

初识数据结构

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 熬过了我们不想要的生活&#xf…

麒麟V10服务器搭建FTP服务

概念 1.1介绍 FTP&#xff1a;File transfer protocol 文件传输协议 1.2原理 默认采用被动模式 被动模式FTP 为了解决服务器发起到客户的连接的问题&#xff0c;人们开发了一种不同的FTP连接方式。这就是所谓的被 动方式&#xff0c;或者叫做PASV&#xff0c;当客户端通…

Vue路由器(详细教程)

路由&#xff1a; 1.理解&#xff1a;一个路由(route)就是一组映射关系&#xff08;key-value)&#xff0c;多个路由需要路由器&#xff08;router&#xff09;进行管理。 2.前端路由&#xff1a;key是路径&#xff0c;value是组件。 1、先安装vue-router路由 npm i vue-route…

车载通信架构 —— 传统车内通信网络LIN总线(低成本覆盖低速场景)

车载通信架构 —— 传统车内通信网络LIN总线(低成本覆盖低速场景) 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是…

redisserver一闪而过 redis闪退解决版本

1.进入Redis根目录 2.输入redis-server 或 redis-server.exe redis.windows.conf 启动redis命令&#xff0c;看是否成功。 执 一闪而过的问题 可能是因为已启动或者其他问题&#xff0c;需要重启 先输入redis-cli.exe再输入shutdown再输入redis-server.exe redis.windows.c…

扩散模型实战(十二):使用调度器DDIM反转来优化图像编辑

推荐阅读列表&#xff1a; 扩散模型实战&#xff08;一&#xff09;&#xff1a;基本原理介绍 扩散模型实战&#xff08;二&#xff09;&#xff1a;扩散模型的发展 扩散模型实战&#xff08;三&#xff09;&#xff1a;扩散模型的应用 扩散模型实战&#xff08;四&#xff…

计算机毕业设计|基于SpringBoot+MyBatis框架的电脑商城的设计与实现(用户上传头像+用户收货管理)

计算机毕业设计|基于SpringBootMyBatis框架的电脑商城的设计与实现&#xff08;用户上传头像&#xff09; 该项目分析着重于设计和实现基于SpringBootMyBatis框架的电脑商城。首先&#xff0c;通过深入分析项目所需数据&#xff0c;包括用户、商品、商品类别、收藏、订单、购物…

NX二次开发UF_CURVE_ask_parameterization 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_ask_parameterization Defined in: uf_curve.h int UF_CURVE_ask_parameterization(tag_t object, double param_range [ 2 ] , int * periodicity ) overview 概述 Retu…

国产Ai大模型和chtgpt3.5的比较

下面是针对国产大模型&#xff0c;腾讯混元&#xff0c;百度文心一言&#xff0c;阿里通义千问和chatgpt的比较&#xff0c;最基础的对一篇文章的单词书进行统计&#xff0c;只有文心一言和chatgpt回答差不多&#xff0c;阿里和腾讯差太多了

深度学习中的注意力机制:原理、应用与实践

深度学习中的注意力机制&#xff1a;原理、应用与实践 摘要&#xff1a; 本文将深入探讨深度学习中的注意力机制&#xff0c;包括其原理、应用领域和实践方法。我们将通过详细的解析和代码示例&#xff0c;帮助读者更好地理解和应用注意力机制&#xff0c;从而提升深度学习模…

Vue快速实践总结 · 下篇

文章目录 组件间通信方式父 --> 子通信props插槽 子 --> 父通信&#xff08;自定义事件&#xff09;任意组件通信全局事件总线消息订阅与发布 Vuex工作原理运行环境简单使用GettersmapState与mapGettersmapActions与mapMutations模块化 命名空间 VueRouter路由的作用与分…

OpenWrt Lan口上网设置

LAN口上网设置 连接上openwrt&#xff0c;我用的 倍控N5105&#xff0c;eth0&#xff0c;看到Openwrt的IP是10.0.0.1 在 网络 -> 网口配置 -> 设置好 WAN 口和 LAN 口 初次使用经常重置 openwrt 所以我设置的是 静态IP模式 - 网络 -> 防火墙 -> 常规设置 ->…

7.私信列表 + 发送列表

目录 1.私信列表 1.1 数据访问层 1.2 业务层 1.3 表现层 1.4 私信详情 2.发送列表 2.1 数据访问层 2.2 业务层 2.3 表现层 2.4 设置已读状态 1.私信列表 私信列表&#xff1a;查询当前用户的会话列表&#xff0c;每个会话只显示一条最新的私信、支持分页列表私信详情…

苹果cms搭建教程附带免费模板

准备工作: 一台服务器域名源码安装好NGINX+PHP7.0+MYSQL5.5 安装php7.0的扩展,fileinfo和 sg11,不安装网站会搭建失败。 两个扩展都全部安装好了之后 点击-服务-重载配置 这样我们的网站环境就配置完成啦 下载苹果cms 苹果cms程序github链接:选择mac10!下载即可 http…

部署Jenkins

一、介绍 Jenkins 、Jenkins概念 Jenkins是一个功能强大的应用程序&#xff0c;允许持续集成和持续交付项目&#xff0c;无论用的是什么平台。这是一个免费的源代码&#xff0c;可以处理任何类型的构建或持续集成。集成Jenkins可以用于一些测试和部署技术。Jenkins是一种软件允…

自建CA实战之 《0x02 Nginx 配置 https双向认证》

自建CA实战之 《0x02 Nginx 配置 https双向认证》 上一章节我们已经实现了Nginx上配置https单向认证&#xff0c;主要场景为客户端验证服务端的身份&#xff0c;但是服务端不验证客户端的身份。 本章节我们将实现Nginx上配置https双向认证&#xff0c;主要场景为客户端验证服…

基于单片机仿指针显示的电子时钟设计

**单片机设计介绍&#xff0c; 基于51单片机超声波测距汽车避障系统 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机仿指针显示的电子时钟是一种利用单片机控制器和LED或LCD显示屏幕来模拟传统时钟指针的显示效果的设计…

PubMedBERT:生物医学自然语言处理领域的特定预训练模型

今年大语言模型的快速发展导致像BERT这样的模型都可以称作“小”模型了。Kaggle LLM比赛LLM Science Exam 的第四名就只用了deberta&#xff0c;这可以说是一个非常好的成绩了。所以说在特定的领域或者需求中&#xff0c;大语言模型并不一定就是最优的解决方案&#xff0c;“小…

01:编译lua及C调用

我们今天在windows平台编译lua&#xff0c;生成 lua动态库,lua.exe&#xff0c;luac.exe 我把这个目录上传到giee&#xff0c;使用下面命令获取它: git clone gitgitee.com:jameschenbo/lua_c_application.git 或者直接访问:访问网页 目录结构如下&#xff1a; build.cmd 是…

【离散数学】——期末刷题题库(一阶逻辑基本概念)

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…