C#实现双向链表
原文: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"。
代码
/// <summary>
/// 双向链表节点
/// </summary>
/// <typeparam name="T"></typeparam>
public class BdNode<T>
{
public T Data { set; get; }
public BdNode<T> Next { set; get; }
public BdNode<T> Prev { set; get; }
public BdNode(T val, BdNode<T> prev, BdNode<T> next)
{
this.Data = val;
this.Prev = prev;
this.Next = next;
}
}
链表操作:
public class DoubleLink<T>
{
//表头
private readonly BdNode<T> _linkHead;
//节点个数
private int _size;
public DoubleLink()
{
_linkHead = new BdNode<T>(default(T), null, null);//双向链表 表头为空
_linkHead.Prev = _linkHead;
_linkHead.Next = _linkHead;
_size = ;
}
public int GetSize() => _size;
public bool IsEmpty() => (_size == );
//通过索引查找
private BdNode<T> GetNode(int index)
{
if (index < || index >= _size)
throw new IndexOutOfRangeException("索引溢出或者链表为空");
if (index < _size / )//正向查找
{
BdNode<T> node = _linkHead.Next;
for (int i = ; i < index; i++)
node = node.Next;
return node;
}
//反向查找
BdNode<T> rnode = _linkHead.Prev;
int rindex = _size - index - ;
for (int i = ; i < rindex; i++)
rnode = rnode.Prev;
return rnode;
}
public T Get(int index) => GetNode(index).Data;
public T GetFirst() => GetNode().Data;
public T GetLast() => GetNode(_size - ).Data;
// 将节点插入到第index位置之前
public void Insert(int index, T t)
{
if (_size < || index >= _size)
throw new Exception("没有可插入的点或者索引溢出了");
if (index == )
Append(_size, t);
else
{
BdNode<T> inode = GetNode(index);
BdNode<T> tnode = new BdNode<T>(t, inode.Prev, inode);
inode.Prev.Next = tnode;
inode.Prev = tnode;
_size++;
}
}
//追加到index位置之后
public void Append(int index, T t)
{
BdNode<T> inode;
if (index == )
inode = _linkHead;
else
{
index = index - ;
if (index < )
throw new IndexOutOfRangeException("位置不存在");
inode = GetNode(index);
}
BdNode<T> tnode = new BdNode<T>(t, inode, inode.Next);
inode.Next.Prev = tnode;
inode.Next = tnode;
_size++;
}
public void Del(int index)
{
BdNode<T> inode = GetNode(index);
inode.Prev.Next = inode.Next;
inode.Next.Prev = inode.Prev;
_size--;
}
public void DelFirst() => Del();
public void DelLast() => Del(_size - );
public void ShowAll()
{
Console.WriteLine("******************* 链表数据如下 *******************");
for (int i = ; i < _size; i++)
Console.WriteLine("(" + i + ")=" + Get(i));
Console.WriteLine("******************* 链表数据展示完毕 *******************\n");
}
}
测试:
DoubleLink<int> dlink = new DoubleLink<int>();// 创建双向链表
Console.WriteLine("将 20 插入到表头之后");
dlink.Append(, );
dlink.ShowAll();
Console.WriteLine("将 40 插入到表头之后");
dlink.Append(, );
dlink.ShowAll();
Console.WriteLine("将 10 插入到表头之前");
dlink.Insert(, );
dlink.ShowAll();
Console.WriteLine("将 30 插入到第一个位置之前");
dlink.Insert(, );
dlink.ShowAll();
Console.WriteLine("展示第一个:" + dlink.GetFirst());
Console.WriteLine("删除第一个");
dlink.DelFirst();
Console.WriteLine("展示第一个:" + dlink.GetFirst());
Console.WriteLine("展示最后一个:" + dlink.GetLast());
Console.WriteLine("删除最后一个");
dlink.DelLast();
Console.WriteLine("展示最后一个:" + dlink.GetLast());
dlink.ShowAll();
Console.ReadKey();
C#实现双向链表的更多相关文章
- 学习Redis你必须了解的数据结构——双向链表(JavaScript实现)
本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明原文链接 http://www.cnblogs.com/tdws/ 下午分享了JavaScript实现单向链表,晚上就来补充下双向链表吧.对链表 ...
- 双向链表、双向循环链表的JS实现
关于链表简介.单链表.单向循环链表.JS中的使用以及扩充方法: 单链表.循环链表的JS实现 关于四种链表的完整封装: https://github.com/zhuwq585/Data-Structu ...
- 剑指Offer面试题:25.二叉搜索树与双向链表
一.题目:二叉搜索树与双向链表 题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向.比如输入下图中左边的二叉搜索树,则输出转换之后的 ...
- Linux 内核数据结构:Linux 双向链表
Linux 内核提供一套双向链表的实现,你可以在 include/linux/list.h 中找到.我们以双向链表着手开始介绍 Linux 内核中的数据结构 ,因为这个是在 Linux 内核中使用最为 ...
- Linux 内核数据结构:双向链表
Linux 内核提供一套双向链表的实现,你可以在 include/linux/list.h 中找到.我们以双向链表着手开始介绍 Linux 内核中的数据结构 ,因为这个是在 Linux 内核中使用最为 ...
- 线性表-双向链表(LinkedList)
双向链表:如图1-3 所示,会把当前header拆分开,重新插入一个Entry<E>. LinkedList源码 0.首先这个类中的两个变量 private transient Entry ...
- Shuffling Machine和双向链表
1. 双向链表 https://github.com/BodhiXing/Data_Structure 2. Shuffling Machine https://pta.patest.cn/pta/t ...
- MS - 1 - 把二元查找树转变成排序的双向链表
## 1. 把二元查找树转变成排序的双向链表 ## ### 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表. ### 要求不能创建任何新的结点,只调整指针的指向. 10 ...
- javascript中的链表结构—双向链表
1.概念 上一个文章里我们已经了解到链表结构,链表的特点是长度不固定,不用担心插入新元素的时候新增位置的问题.插入一个元素的时候,只要找到插入点就可以了,不需要整体移动整个结构. 这里我们了解一下双向 ...
- Java自己实现双向链表LinkList
/** * <p> * Node 双向链表实体类 * <p> * * @author <a href="mailto:yangkj@corp.21cn.com& ...
随机推荐
- 初步理解require.js模块化编程
初步理解require.js模块化编程 一.Javascript模块化编程 目前,通行的Javascript模块规范共有两种:CommonJS和AMD. 1.commonjs 2009年,美国程序员R ...
- 浅谈移动端中的视口(viewport)
在 PC 端,视口指的是浏览器的可视区域,其宽度和浏览器窗口的宽度保持一致.在 CSS 标准文档中,视口也被称为初始包含块,它是所有 CSS 百分比宽度推算的根源,给 CSS 布局限制了一个最大宽度. ...
- var a =10 与 a = 10的区别
学习文章------汤姆大叔-变量对象 总结笔记 变量特点: ①变量声明可以存储在变量对象中.②变量不能直接用delete删除. var a =10 与 a = 10的区别: ①a = 10只是为全局 ...
- Python入门-内置函数二
看到标题你也能猜到今天要说大概内容是什么了,没错,昨天没有说完的部分再给大家说说(有一些重合的部分),内置函数的内容比较多,并且工作中经常用到的却不太多,很多都是不太常用的,所以我就着重说一些比较常用 ...
- Linux-学习笔记(PHP向)<一>
Linux常用命令 使用PHP服务器端脚本编程语言进行网站开发,需要在lamp环境下进行,Linux作为”四剑客”之一是有必要了解熟悉的,而Linux系统并不像windows操作系统那样,以图形化的界 ...
- Java BeanUtils 组件 使用
1. BeanUtils组件 1.1 简介 程序中对javabean的操作很频繁, 所以apache提供了一套开源的api,方便对javabean的操作!即BeanUtils组件. BeanUtils ...
- 批量删除微博的js代码
清空微博,网上找了一段js代码,试了下,还行. var fileref=document.createElement('script') fileref.setAttribute("type ...
- linux 获取当前程序路径
const std::string strCfgName = "logger_import_db.conf" ;bool fGetCfgFileName(std::string&a ...
- *p++、*++p、(*p)++区别
关于数组指针的谜题 假设 p 是指向数组 arr 中第 n 个元素的指针,那么 *p++.*++p.(*p)++ 分别是什么意思呢? *p++ 等价于 *(p++),表示先取得第 n 个元素的值,再将 ...
- 三、docker学习笔记——安装postgresql
1.docker pull postgres 2.docker run --name postgres -e POSTGRES_PASSWORD=123456 -p 5432:5432 -d post ...