原文:http://www.cnblogs.com/skywang12345/p/3561803.html#a33 没有C#版本的。。是不是很方。。不过图和说明很好,引用一下

双向链表

双向链表(双链表)是链表的一种。和单链表一样,双链表也是由节点组成,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。

双链表的示意图如下:

表头为空,表头的后继节点为"节点10"(数据为10的节点);"节点10"的后继节点是"节点20"(数据为10的节点),"节点20"的前继节点是"节点10";"节点20"的后继节点是"节点30","节点30"的前继节点是"节点20";...;末尾节点的后继节点是表头。

双链表删除节点

删除"节点30"
删除之前:"节点20"的后继节点为"节点30","节点30" 的前继节点为"节点20"。"节点30"的后继节点为"节点40","节点40" 的前继节点为"节点30"。
删除之后:"节点20"的后继节点为"节点40","节点40" 的前继节点为"节点20"。

双链表添加节点

在"节点10"与"节点20"之间添加"节点15"
添加之前:"节点10"的后继节点为"节点20","节点20" 的前继节点为"节点10"。
添加之后:"节点10"的后继节点为"节点15","节点15" 的前继节点为"节点10"。"节点15"的后继节点为"节点20","节点20" 的前继节点为"节点15"。

代码

  1. /// <summary>
  2. /// 双向链表节点
  3. /// </summary>
  4. /// <typeparam name="T"></typeparam>
  5. public class BdNode<T>
  6. {
  7. public T Data { set; get; }
  8. public BdNode<T> Next { set; get; }
  9. public BdNode<T> Prev { set; get; }
  10. public BdNode(T val, BdNode<T> prev, BdNode<T> next)
  11. {
  12. this.Data = val;
  13. this.Prev = prev;
  14. this.Next = next;
  15. }
  16. }

链表操作:

  1. public class DoubleLink<T>
  2. {
  3. //表头
  4. private readonly BdNode<T> _linkHead;
  5. //节点个数
  6. private int _size;
  7. public DoubleLink()
  8. {
  9. _linkHead = new BdNode<T>(default(T), null, null);//双向链表 表头为空
  10. _linkHead.Prev = _linkHead;
  11. _linkHead.Next = _linkHead;
  12. _size = ;
  13. }
  14. public int GetSize() => _size;
  15. public bool IsEmpty() => (_size == );
  16. //通过索引查找
  17. private BdNode<T> GetNode(int index)
  18. {
  19. if (index < || index >= _size)
  20. throw new IndexOutOfRangeException("索引溢出或者链表为空");
  21. if (index < _size / )//正向查找
  22. {
  23. BdNode<T> node = _linkHead.Next;
  24. for (int i = ; i < index; i++)
  25. node = node.Next;
  26. return node;
  27. }
  28. //反向查找
  29. BdNode<T> rnode = _linkHead.Prev;
  30. int rindex = _size - index - ;
  31. for (int i = ; i < rindex; i++)
  32. rnode = rnode.Prev;
  33. return rnode;
  34. }
  35. public T Get(int index) => GetNode(index).Data;
  36. public T GetFirst() => GetNode().Data;
  37. public T GetLast() => GetNode(_size - ).Data;
  38. // 将节点插入到第index位置之前
  39. public void Insert(int index, T t)
  40. {
  41. if (_size < || index >= _size)
  42. throw new Exception("没有可插入的点或者索引溢出了");
  43. if (index == )
  44. Append(_size, t);
  45. else
  46. {
  47. BdNode<T> inode = GetNode(index);
  48. BdNode<T> tnode = new BdNode<T>(t, inode.Prev, inode);
  49. inode.Prev.Next = tnode;
  50. inode.Prev = tnode;
  51. _size++;
  52. }
  53. }
  54. //追加到index位置之后
  55. public void Append(int index, T t)
  56. {
  57. BdNode<T> inode;
  58. if (index == )
  59. inode = _linkHead;
  60. else
  61. {
  62. index = index - ;
  63. if (index < )
  64. throw new IndexOutOfRangeException("位置不存在");
  65. inode = GetNode(index);
  66. }
  67. BdNode<T> tnode = new BdNode<T>(t, inode, inode.Next);
  68. inode.Next.Prev = tnode;
  69. inode.Next = tnode;
  70. _size++;
  71. }
  72. public void Del(int index)
  73. {
  74. BdNode<T> inode = GetNode(index);
  75. inode.Prev.Next = inode.Next;
  76. inode.Next.Prev = inode.Prev;
  77. _size--;
  78. }
  79. public void DelFirst() => Del();
  80. public void DelLast() => Del(_size - );
  81. public void ShowAll()
  82. {
  83. Console.WriteLine("******************* 链表数据如下 *******************");
  84. for (int i = ; i < _size; i++)
  85. Console.WriteLine("(" + i + ")=" + Get(i));
  86. Console.WriteLine("******************* 链表数据展示完毕 *******************\n");
  87. }
  88. }

测试:

  1. DoubleLink<int> dlink = new DoubleLink<int>();// 创建双向链表
  2. Console.WriteLine("将 20 插入到表头之后");
  3. dlink.Append(, );
  4. dlink.ShowAll();
  5. Console.WriteLine("将 40 插入到表头之后");
  6. dlink.Append(, );
  7. dlink.ShowAll();
  8. Console.WriteLine("将 10 插入到表头之前");
  9. dlink.Insert(, );
  10. dlink.ShowAll();
  11. Console.WriteLine("将 30 插入到第一个位置之前");
  12. dlink.Insert(, );
  13. dlink.ShowAll();
  14. Console.WriteLine("展示第一个:" + dlink.GetFirst());
  15. Console.WriteLine("删除第一个");
  16. dlink.DelFirst();
  17. Console.WriteLine("展示第一个:" + dlink.GetFirst());
  18. Console.WriteLine("展示最后一个:" + dlink.GetLast());
  19. Console.WriteLine("删除最后一个");
  20. dlink.DelLast();
  21. Console.WriteLine("展示最后一个:" + dlink.GetLast());
  22. dlink.ShowAll();
  23. Console.ReadKey();

C#实现双向链表的更多相关文章

  1. 学习Redis你必须了解的数据结构——双向链表(JavaScript实现)

    本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文链接 http://www.cnblogs.com/tdws/ 下午分享了JavaScript实现单向链表,晚上就来补充下双向链表吧.对链表 ...

  2. 双向链表、双向循环链表的JS实现

    关于链表简介.单链表.单向循环链表.JS中的使用以及扩充方法:  单链表.循环链表的JS实现 关于四种链表的完整封装: https://github.com/zhuwq585/Data-Structu ...

  3. 剑指Offer面试题:25.二叉搜索树与双向链表

    一.题目:二叉搜索树与双向链表 题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向.比如输入下图中左边的二叉搜索树,则输出转换之后的 ...

  4. Linux 内核数据结构:Linux 双向链表

    Linux 内核提供一套双向链表的实现,你可以在 include/linux/list.h 中找到.我们以双向链表着手开始介绍 Linux 内核中的数据结构 ,因为这个是在 Linux 内核中使用最为 ...

  5. Linux 内核数据结构:双向链表

    Linux 内核提供一套双向链表的实现,你可以在 include/linux/list.h 中找到.我们以双向链表着手开始介绍 Linux 内核中的数据结构 ,因为这个是在 Linux 内核中使用最为 ...

  6. 线性表-双向链表(LinkedList)

    双向链表:如图1-3 所示,会把当前header拆分开,重新插入一个Entry<E>. LinkedList源码 0.首先这个类中的两个变量 private transient Entry ...

  7. Shuffling Machine和双向链表

    1. 双向链表 https://github.com/BodhiXing/Data_Structure 2. Shuffling Machine https://pta.patest.cn/pta/t ...

  8. MS - 1 - 把二元查找树转变成排序的双向链表

    ## 1. 把二元查找树转变成排序的双向链表 ## ### 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表. ### 要求不能创建任何新的结点,只调整指针的指向. 10       ...

  9. javascript中的链表结构—双向链表

    1.概念 上一个文章里我们已经了解到链表结构,链表的特点是长度不固定,不用担心插入新元素的时候新增位置的问题.插入一个元素的时候,只要找到插入点就可以了,不需要整体移动整个结构. 这里我们了解一下双向 ...

  10. Java自己实现双向链表LinkList

    /** * <p> * Node 双向链表实体类 * <p> * * @author <a href="mailto:yangkj@corp.21cn.com& ...

随机推荐

  1. c语言结构体可以直接赋值

    结构体直接赋值的实现 下面是一个实例: #include <stdio.h> struct Foo { char a; int b; double c; }foo1, foo2; //de ...

  2. 【转】B树、B-树、B+树、B*树、红黑树、 二叉排序树、trie树Double Array 字典查找树简介

    B  树 即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: ...

  3. git使用笔记 bitbucket基本操作

    实现目标: 1.将本地已经存在的项目文件保存到 bitbucket.org 2.从 bitbucket.org 检出代码库到本地 操作笔记: 1.首先在bitbucket.org创建一个代码库,并得到 ...

  4. 【Machine Learning】决策树之简介(1)

    Content 1.decision tree representation 2.ID3:a top down learning algorithm 3.expressiveness of data ...

  5. EF多实体对应单表

    1.EF多实体对应单表 适用场景:单数据库表,表数据有较长用字段,有不常用或者大数据字段. 2.建表语句 CREATE TABLE [Chapter2].[Photograph]( ,) primar ...

  6. HBuilder自定义格式化代码

    对于代码格式到底为两个空格还是四个空格,可能大家喜欢的都不同,如果你是在使用HBuilder编辑器,那么恭喜你,这两种代码格式你可以轻易的更换.下面贴步骤 1.打开工具—>选项 2.选择HBui ...

  7. strace for Android

    使用strace for Android跟踪系统调用过程方便后续的so文件分析 http://benno.id.au/blog/2007/11/18/android-runtime-stracehtt ...

  8. Hadoop HA集群的搭建

    HA 集群搭建的难度主要在于配置文件的编写, 心细,心细,心细! ha模式下,secondary namenode节点不存在... 集群部署节点角色的规划(7节点)------------------ ...

  9. OutputStream-InputStream-FileOutputStream-FileInputStream-BufferedOutputStream-BufferedInputStream-四种复制方式-单层文件夹复制

    字节流两套:         java.lang.Object--java.io.OutputStream--java.io.FileOutputStream         java.lang.Ob ...

  10. Hyperledger Fabric 1.0 学习搭建 (一)--- 基础环境搭建

    1: 环境构建在本文中用到的宿主机环境是Centos ,版本为Centos.x86_64 7.2, 一定要用7版本以上, 要不然会安装出错. 通过Docker 容器来运行Fabric的节点,版本为v1 ...