1、简介

链表是一种非常基础的数据结构之一,我们在日常开发种都会接触到或者是接触到相同类型的链表数据结构.所以本文会使用C#算法来实现一个简单的链表数据结构,并实现其中几个简单的api以供使用.

2、概述

链表是一种递归的数据结构,他或者为null,或者是指向像一个节点的(node)的引用,该节点含有一个泛型的元素(当然可以是非泛型的,但是为了充分利用C#的优势,切让链表更具有灵活性,这里使用泛型)和指向另一个链表的引用.

3、实战 单向链表

如下图,因为下一个节点对象没有保持上个节点的引用,所以这种链表称之为单向链表

实现代码如下,这边我使用了迭代器模式,方便节点的单向遍历,因为没有使用MS提供的标准的迭代器接口,所以无法使用foreach遍历.

    /// <summary>/// C#链表实现/// </summary>public class LinkedList{static void Main(string[] args){//生成对应的Node节点var nodeFirst = new Node<string>();var nodeSecond = new Node<string>();var nodeThird = new Node<string>();//构造节点内容nodeFirst.Item = "one";nodeSecond.Item = "two";nodeThird.Item = "three";//链接节点nodeFirst.NodeItem = nodeSecond;nodeSecond.NodeItem = nodeThird;//注:这里nodeThird的NodeItem指向nullvar nodeEnumerator = nodeFirst.GetEnumerator();while (nodeEnumerator.MoveNext()){Console.Write($"当前节点元素内容:{nodeEnumerator.CurrentItem}");//这里如果当前节点的下一个节点不为空,则让当前节点变为下一个节点if (nodeEnumerator.SetNext())Console.WriteLine($"下一个节点内容:{nodeEnumerator.CurrentNode.Item}");elseConsole.WriteLine($"链表遍历结束,下一个节点内容为null");}Console.ReadKey();}/// <summary>/// 节点对象,使用迭代器模式,实现链表的遍历/// </summary>/// <typeparam name="T"></typeparam>public class Node<T> : ILinkedListEnumerable<T>{public T Item { get; set; }public Node<T> NodeItem { get; set; }public ILinedListEnumerator<T> GetEnumerator(){return new NodeEnumerator<T>(this);}}private class NodeEnumerator<T> : ILinedListEnumerator<T>{public Node<T> CurrentNode { get; set; }public NodeEnumerator(Node<T> node){CurrentNode = node;}public T CurrentItem => CurrentNode.Item;public bool MoveNext(){if (CurrentNode!=null)return true;return false;}public bool SetNext(){if (CurrentNode.NodeItem != null){CurrentNode = CurrentNode.NodeItem;return true;}else {CurrentNode = null;return false;}}/// <summary>/// 当迭代器内部存在非托管资源时,用于释放资源/// </summary>public void Dispose(){throw new NotImplementedException();}}/// <summary>/// 链表迭代器接口约束/// </summary>/// <typeparam name="T"></typeparam>public interface ILinkedListEnumerable<T>{ILinedListEnumerator<T> GetEnumerator();}/// <summary>/// 链表单个迭代器/// </summary>/// <typeparam name="T"></typeparam>public interface ILinedListEnumerator<T> : IDisposable{/// <summary>/// 当前迭代器元素/// </summary>Node<T> CurrentNode { get; }/// <summary>/// 当前迭代器元素内容/// </summary>T CurrentItem { get; }/// <summary>/// 是否可以进行下一步遍历操作/// </summary>/// <returns></returns>bool MoveNext();/// <summary>/// 遍历完当前链表元素,使其指向下一个元素/// </summary>bool SetNext();}}

4、实战 双向链表

双向链表的应用场景很多,比如Redis的List就是使用双向链表实现的.这种形式的链表更加的灵活.

修改代码如下:

    /// <summary>/// C#链表实现/// </summary>public class LinkedList{static void Main(string[] args){//生成对应的Node节点var nodeFirst = new Node<string>();var nodeSecond = new Node<string>();var nodeThird = new Node<string>();//构造节点内容nodeFirst.Item = "one";nodeSecond.Item = "two";nodeThird.Item = "three";//链接节点nodeFirst.NextNode = nodeSecond;nodeSecond.NextNode = nodeThird;//注:这里nodeThird的NextNode指向nullvar nodeEnumerator = nodeFirst.GetEnumerator();while (nodeEnumerator.MoveNext()){//输出当前节点的内容Console.Write($"当前节点元素内容:{nodeEnumerator.CurrentItem}     ");//输出上一个节点的内容Console.Write($"上一个节点元素内容:{nodeEnumerator.PreviousNode?.Item??"没有上一个节点"}     ");//这里如果当前节点的下一个节点不为空,则让当前节点变为下一个节点if (nodeEnumerator.SetNext())Console.WriteLine($"下一个节点内容:{nodeEnumerator.CurrentNode.Item}");elseConsole.WriteLine($"链表遍历结束,下一个节点内容为null");}Console.ReadKey();}/// <summary>/// 节点对象,使用迭代器模式,实现链表的遍历/// </summary>/// <typeparam name="T"></typeparam>public class Node<T> : ILinkedListEnumerable<T>{public T Item { get; set; }public Node<T> NextNode { get; set; }public ILinedListEnumerator<T> GetEnumerator(){return new NodeEnumerator<T>(this);}}private class NodeEnumerator<T> : ILinedListEnumerator<T>{public Node<T> PreviousNode { get; set; }public Node<T> CurrentNode { get; set; }public NodeEnumerator(Node<T> node){CurrentNode = node;}public T CurrentItem => CurrentNode.Item;public bool MoveNext(){if (CurrentNode!=null)return true;return false;}public bool SetNext(){if (CurrentNode.NextNode != null){PreviousNode = CurrentNode;CurrentNode = CurrentNode.NextNode;return true;}else {CurrentNode = null;return false;}}/// <summary>/// 当迭代器内部存在非托管资源时,用于释放资源/// </summary>public void Dispose(){throw new NotImplementedException();}}/// <summary>/// 链表迭代器接口约束/// </summary>/// <typeparam name="T"></typeparam>public interface ILinkedListEnumerable<T>{ILinedListEnumerator<T> GetEnumerator();}/// <summary>/// 链表单个迭代器/// </summary>/// <typeparam name="T"></typeparam>public interface ILinedListEnumerator<T> : IDisposable{/// <summary>/// 上一个迭代器元素/// </summary>Node<T> PreviousNode { get; }/// <summary>/// 当前迭代器元素/// </summary>Node<T> CurrentNode { get; }/// <summary>/// 当前迭代器元素内容/// </summary>T CurrentItem { get; }/// <summary>/// 是否可以进行下一步遍历操作/// </summary>/// <returns></returns>bool MoveNext();/// <summary>/// 遍历完当前链表元素,使其指向下一个元素/// </summary>bool SetNext();}}

5、通过双向链表实现反向遍历

如果没有实现链表的双向功能,实现反向遍历的功能是不可能,实际上Redis的List是实现了这个功能的,所以这里我也实现下,tip:目前为止,所以的遍历都是先进先出的,类似于队列,所以如果实现了反向遍历,从而该双向链表同时也支持了先进后出的功能,类似于栈,为了分离正向和反向这个遍历过程,所以我实现了两个迭代器,分别为正向迭代器和反向迭代器.

代码如下:

    /// <summary>/// C#链表实现/// </summary>public class LinkedList{static void Main(string[] args){//生成对应的Node节点var nodeFirst = new Node<string>();var nodeSecond = new Node<string>();var nodeThird = new Node<string>();//构造节点内容nodeFirst.Item = "one";nodeSecond.Item = "two";nodeThird.Item = "three";//链接节点nodeFirst.NextNode = nodeSecond;nodeSecond.NextNode = nodeThird;nodeSecond.PreviousNode = nodeFirst;nodeThird.PreviousNode = nodeSecond;//注:这里nodeThird的NextNode指向nullvar nodeEnumerator = nodeThird.GetNodeReverseEnumerator();while (nodeEnumerator.MoveNext()){//输出当前节点的内容Console.Write($"当前节点元素内容:{nodeEnumerator.CurrentItem}     ");//输出上一个节点的内容Console.Write($"上一个节点元素内容:{nodeEnumerator.PreviousNode?.Item ?? "没有上一个节点"}     ");//这里如果当前节点的下一个节点不为空,则让当前节点变为下一个节点if (nodeEnumerator.SetNext())Console.WriteLine($"下一个节点内容:{nodeEnumerator?.CurrentNode.Item}");elseConsole.WriteLine($"链表遍历结束,下一个节点内容为null");}Console.ReadKey();}/// <summary>/// 节点对象,使用迭代器模式,实现链表的遍历/// </summary>/// <typeparam name="T"></typeparam>public class Node<T> : ILinkedListEnumerable<T>{public T Item { get; set; }public Node<T> PreviousNode { get; set; }public Node<T> NextNode { get; set; }/// <summary>/// 获取正向迭代器/// </summary>/// <returns></returns>public ILinedListEnumerator<T> GetEnumerator(){return new NodeEnumerator<T>(this);}/// <summary>/// 获取反向迭代器/// </summary>/// <returns></returns>public ILinedListEnumerator<T> GetNodeReverseEnumerator(){return new NodeReverseEnumerator<T>(this);}}/// <summary>/// 正向迭代器/// </summary>/// <typeparam name="T"></typeparam>private class NodeEnumerator<T> : ILinedListEnumerator<T>{public Node<T> PreviousNode { get; set; }public Node<T> CurrentNode { get; set; }public NodeEnumerator(Node<T> node){CurrentNode = node;}public T CurrentItem => CurrentNode.Item;public bool MoveNext(){if (PreviousNode != null)return true;return false;}public bool SetNext(){if (CurrentNode.PreviousNode != null){PreviousNode = CurrentNode;CurrentNode = CurrentNode.PreviousNode;return true;}else {CurrentNode = null;return false;}}/// <summary>/// 当迭代器内部存在非托管资源时,用于释放资源/// </summary>public void Dispose(){throw new NotImplementedException();}}/// <summary>/// 反向迭代器/// </summary>private class NodeReverseEnumerator<T>: ILinedListEnumerator<T>{public Node<T> PreviousNode { get; set; }public Node<T> CurrentNode { get; set; }public NodeReverseEnumerator(Node<T> node){CurrentNode = node;}public T CurrentItem => CurrentNode.Item;public bool MoveNext(){if (CurrentNode != null)return true;return false;}public bool SetNext(){if (CurrentNode.PreviousNode != null){PreviousNode = CurrentNode;CurrentNode = CurrentNode.PreviousNode;return true;}else{CurrentNode = null;return false;}}/// <summary>/// 当迭代器内部存在非托管资源时,用于释放资源/// </summary>public void Dispose(){throw new NotImplementedException();}}/// <summary>/// 链表迭代器接口约束/// </summary>/// <typeparam name="T"></typeparam>public interface ILinkedListEnumerable<T>{/// <summary>/// 正向迭代器/// </summary>/// <returns></returns>ILinedListEnumerator<T> GetEnumerator();/// <summary>/// 反向迭代器/// </summary>/// <returns></returns>ILinedListEnumerator<T> GetNodeReverseEnumerator();}/// <summary>/// 链表单个迭代器/// </summary>/// <typeparam name="T"></typeparam>public interface ILinedListEnumerator<T> : IDisposable{/// <summary>/// 上一个迭代器元素/// </summary>Node<T> PreviousNode { get; }/// <summary>/// 当前迭代器元素/// </summary>Node<T> CurrentNode { get; }/// <summary>/// 当前迭代器元素内容/// </summary>T CurrentItem { get; }/// <summary>/// 是否可以进行下一步遍历操作/// </summary>/// <returns></returns>bool MoveNext();/// <summary>/// 遍历完当前链表元素,使其指向下一个元素/// </summary>bool SetNext();}}

转载于:https://www.cnblogs.com/GreenLeaves/p/10261808.html

C# 算法之链表、双向链表以及正向反向遍历实现相关推荐

  1. 数据结构与算法之双向链表(增删改查、有序增、正向遍历、反向遍历)

    双向链表 1.什么是双向链表: 每个节点都有前一个节点的位置和后一个节点的位置 2.为什么要用双向链表: 和单向链表比, 双向链表可以正反向的遍历, 而且可以自我删除节点. 单链表只能单向遍历, 并且 ...

  2. 数据结构与算法:链表

    前言 本文主要讲解链表,包括单向链表,双向链表,环形单链表,约瑟夫问题 数据结构与算法文章列表 数据结构与算法文章列表: 点击此处跳转查看 目录 (一)链表(Linked List)介绍 链表是有序的 ...

  3. JavaScript实现链表reverseTraversal反向遍历算法(附完整源码)

    JavaScript实现链表reverseTraversal反向遍历算法(附完整源码) reverseTraversal.js完整源代码 reverseTraversal.js完整源代码 functi ...

  4. c++模板类(链表),实现正向反向找到链表中最大值,并比较时间差异

    问题描述 实现链表容器模板类,利用模板实现找到公司中工资最高的员工的工资,实现正向反向查找,并且比较两种方法的时间差异. 代码实现 公司类Company.h #ifndef COMPCONT_H #d ...

  5. 数据结构与算法——单链表、双向链表

    目录 ​编辑 特点: 一.单链表 1.增加数据到链表尾部 2.增加数据到链表指定位置 思路: 代码实现: 3.修改单链表数据 3.单链表数据删除 4.单链表相关面试题 二.双向链表 1.双向链表遍历 ...

  6. Java数据结构与算法 day02 链表

    文章目录 第三章 链表 单链表介绍和内存布局 单链表创建和遍历的分析实现 添加(创建)过程 遍历过程 代码实现 单链表按顺序插入节点 单链表节点的修改 单链表节点的删除和小结 单链表面试题 新浪面试题 ...

  7. 谷歌大脑提出对智能体进行「正向-反向」强化学习训练,加速训练过程

    原文来源:arXiv 作者:Ashley D. Edwards.Laura Downs.James C. Davidson 「雷克世界」编译:嗯~是阿童木呀.KABUDA.EVA 在强化学习问题中,关 ...

  8. 数据结构与算法--复杂链表的复制

    复杂链表的复制 题目:实现一个函数complexListNode 复制一个复杂链表.在链表中,每个节点除了有一个next指针指向下一个节点,还有另外一个before节点,before节点指向链表中任意 ...

  9. C语言随笔小算法:创建双向链表

    C语言随笔小算法:创建双向链表 双向链表两个指针域!head定住,tail移动! 代码: #include "stdlib.h" #include "stdio.h&qu ...

最新文章

  1. vue中怎么清空tab选项卡的缓存_vue Tab切换以及缓存页面处理的几种方式
  2. html5计数器,CSS 计数器(counter)
  3. 95-872-064-源码-CEP-CepOperator源码
  4. (CF#257)B. Jzzhu and Sequences
  5. C语言测试:想成为嵌入式程序员应知道的0x10个基本问题
  6. 长跑常用必知的关键字及100条跑步的建议
  7. Multisim破解教程
  8. 怎么样利用栅格数据分类后的结果以行政区域统计各个地类的面积
  9. excel不同文件表格批量加表头vba_用Excel VBA实现多文件夹内文件加入表头 遍历文件...
  10. win2003企业版sp2序列号
  11. 【联盛德W806上手笔记】六、7816/UART 控制器
  12. 开机找不到硬盘的原因
  13. 树莓派3B安装影音系统OSMC
  14. EasyExcel导出数据到Excel,浏览器提供下载
  15. table内容超长自动隐藏,鼠标放置后浮动显示全部内容
  16. 学习USART自闭实录(stm32F411RE)Stm32cubemx
  17. 中地恒达振弦信号采集仪MCU采集模块
  18. 浅谈城市大脑与智慧城市发展趋势
  19. Java制作二级导航菜单_纯CSS实现超简单的二级下拉导航菜单代码
  20. win7下安装纯净版XP

热门文章

  1. Mybatis Generator 逆向生成器
  2. Vijos CoVH之再破难关(搜索+hash)
  3. paip.性能跟踪profile原理与架构与本质-- python扫带java php
  4. Maigo的KM算法讲解
  5. 传输层协议的UDP和TCP
  6. Linux下SVN创建新的项目
  7. c语言case语句块,JavaScript使用Switch语句来选择将要执行的代码块
  8. python acme_Python Hashlib模块 · Seacme Huang
  9. python数据库连接池neo4j_在python中操作neo4j数据库的方法
  10. mysql自定义函数重载_python pyMysql 自定义异常 函数重载