单链表允许从一个结点直接访问它的后继结点,所以, 找直接后继结点的时间复杂度是 O(1)。但是,要找某个结点的直接前驱结点,只能从表的头引用开始遍历各结点。如果某个结点的 Next 等于该结点,那么,这个结点就是该结点的直接前驱结点。也就是说,找直接前驱结点的时间复杂度是 O(n),n是单链表的长度。当然,我们也可以在结点的引用域中保存直接前驱结点的地址而不是直接后继结点的地址。这样,找直接前驱结点的时间复杂度只有 O(1),但找直接后继结点的时间复杂度是 O(n)。如果希望找直接前驱结点和直接后继结点的时间复杂度都是 O(1),那么,需要在结点中设两个引用域,一个保存直接前驱结点的地址,叫 prev,一个直接后继结点的地址,叫 next,这样的链表就是双向链表(Doubly Linked List)。

双链表节点类的实现如下所示:

public class DbNode<T>//双向链表结点类
    {
        private T data;
        private DbNode<T> prev;
        private DbNode<T> next;

        public DbNode(DbNode<T> p, T val)
        {
            next = p;
            data = val;
        }
        public DbNode(DbNode<T> p)
        {
            next = p;
        }
        public DbNode(T val)
        {
            next = null;
            data = val;
        }
        public DbNode()
        {
            next = null;
            data = default(T);
        }

        public T Data
        {
            get { return data; }
            set { data = value; }
        }
        public DbNode<T> Prev
        {
            get { return prev; }
            set { prev = value; }
        }
        public DbNode<T> Next
        {
            get { return next; }
            set { next = value; }
        }
    }

双链表接口的实现如下所示:

public interface ILinkList<T>//双向链表接口
    {

        void AddFirst(T t);

        void AddLast(T t);

        void Clear();

        int Count { get; }

        DbNode<T> Head { get; set; }

        DbNode<T> Tail { get; set; }

        void Insert(int index, T t);

        bool IsEmpty { get; }

        void RemoveAt(int index);

        void RemoveFirst();

        void RemoveLast();

        DbNode<T> this[int index] { get; }

    }

双链表的实现如下所示:

public class LinkList<T> : ILinkList<T>
    {
        private DbNode<T> head;
        private DbNode<T> tail;
        private int size;

        public DbNode<T> Head
        {
            get { return head; }
            set { head = value; }
        }
        public DbNode<T> Tail
        {
            get { return tail; }
            set { tail = value; }
        }

        public DbNode<T> this[int index]
        {
            get
            {
                if (head == null || index < 0 || index >= Count)
                {
                    return null;
                }
                int i = 0;
                DbNode<T> current = new DbNode<T>();
                if (i < size / 2)
                {
                    current = head;
                    while (true)
                    {
                        if (i == index) { break; }
                        current = current.Next;
                        i++;
                    }
                    return current;
                }
                else
                {
                    current = tail;
                    i = size;
                    while (true)
                    {
                        if (i == index) { break; }
                        current = current.Prev;
                        i--;
                    }
                    return current.Next;
                }
            }
        }

        public bool IsEmpty
        {
            get { return head == null; }
        }

        public void AddFirst(T t)
        {
            DbNode<T> node = new DbNode<T>();
            if (head == null)
            {
                head = node;
                tail = node;
                ++size;
                return;
            }
            node.Next = head;
            head.Prev = node;
            head = node;
            ++size;
        }

        public void AddLast(T t)
        {
            DbNode<T> node = new DbNode<T>();
            if (head == null)
            {
                head = node;
                tail = node;
                ++size;
                return;
            }
            tail.Next = node;
            node.Prev = tail;
            tail = node;
            ++size;
        }

        public void Clear()
        {
            head = null;
            tail = null;
            size = 0;
        }

        public int Count
        {
            get { return size; }
        }

        public void Insert(int index, T t)
        {
            if (index < 0 || index >= Count)
            {
                return;
            }
            if (IsEmpty && index > 0)
            {
                return;
            }
            if (IsEmpty)
            {
                AddFirst(t);
                return;
            }
            DbNode<T> current = head;
            DbNode<T> node = new DbNode<T>(t);
            int i = 0;
            while (true)
            {
                if (i == index) break;
                current = current.Next;
                i++;
            }
            current.Prev.Next = node;//此处很重要
            node.Prev = current.Prev;
            node.Next = current;
            current.Prev = node;
            size++;
        }

        public void RemoveAt(int index)
        {
            if (index < 0 || index >= Count)
            {
                return;
            }
            if (IsEmpty && index > 0)
            {
                return;
            }
            if (IsEmpty)
            {
                RemoveFirst();
                return;
            }
            if (index == size - 1)
            {
                RemoveLast();
                return;
            }
            DbNode<T> current = head;
            int i = 0;
            while (true)
            {
                if (i == index) break;
                current = current.Next;
                i++;
            }
            current.Prev.Next = current.Next;
            current.Next.Prev = current.Prev;
            size--;
        }

        public void RemoveFirst()
        {
            if (IsEmpty) { return; }
            if (size == 1) { Clear(); }
            head = head.Next;
            head.Prev = null;
            size--;
        }

        public void RemoveLast()
        {
            if (IsEmpty) { return; }
            if (size == 1) { Clear(); }
            tail = tail.Prev;
            tail.Next = null;
            size--;
        }
    }

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

  1. JAVA 链表操作:单链表和双链表

    主要讲述几点: 一.链表的简介 二.链表实现原理和必要性 三.单链表示例 四.双链表示例 一.链表的简介 链表是一种比较常用的数据结构,链表虽然保存比较复杂,但是在查询时候比较便捷,在多种计算机语言都 ...

  2. java实现双链表(差点没写吐系列...)

    刚才把单链表写完了,现在又把双链表写了,双链表和单链表的区别就是每个节点有prior和next两个指针,不同于单链表的一个next指针,而且,正是因为有这两个指针,所以双链表可以前后两个方向去移动指针 ...

  3. 数据结构图文解析之:数组、单链表、双链表介绍及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  4. C和指针 第十二章 使用结构和指针 双链表和语句提炼

    双链表中每个节点包含指向当前和之后节点的指针,插入节点到双链表中需要考虑四种情况: 1.插入到链表头部 2.插入到链表尾部 3.插入到空链表中 4.插入到链表内部 #include <stdio ...

  5. [C++11][数据结构]自己的双链表实现

    这个双链表,是我模仿stl的list制作的,只实现了一些基本功能,像merge,transfer这些就没有实现,用户可以用基本操作来自己做外部实现. 我没有选用stl的[begin,end)迭代器模式 ...

  6. Linux 底下使用C语言的 单链表 ,双链表,二叉树 读取文件,并排序

    直接上代码 单链表Linux读文件排序: 双链表Linux读取文件排序: 二叉树LinuX读取文件并排序:

  7. 再谈LRU双链表内存管理

    N年前我写了个双链表也发了博客,还添了代码.但是那个代码不但复杂,而且还有有问题的,一直懒得整理,放在空间误导别人.最近在写服务端,今天抽点空补一篇. 关于LRU网上随便搜,有过后端经验的人应该很多都 ...

  8. 数组、单链表和双链表介绍 以及 双向链表的C/C++/Java实现

    概要 线性表是一种线性结构,它是具有相同类型的n(n≥0)个数据元素组成的有限序列.本章先介绍线性表的几个基本组成部分:数组.单向链表.双向链表:随后给出双向链表的C.C++和Java三种语言的实现. ...

  9. C++ 双链表基本操作

    上一篇博客主要总结了单向链表,这次再总结一下双向链表. 1.概念 双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱.所以,从双向链表中的任意一个结点开始,都 ...

随机推荐

  1. 纯CSS tooltip 提示

    一般的tooltip,使用超链接的title,或者是css+javascript生成. 如果页面布局合理,样式结构清晰,可以使用纯CSS的提示. demo如下: a.tooltip { positio ...

  2. uva 820(最大流)

    最大流的裸题,直接贴了模板. #include <cstdio> #include <iostream> #include <sstream> #include & ...

  3. Codeforces Round #380 (Div. 1, Rated, Based on Technocup 2017 - Elimination Round 2)

    http://codeforces.com/contest/737 A: 题目大意: 有n辆车,每辆车有一个价钱ci和油箱容量vi.在x轴上,起点为0,终点为s,中途有k个加油站,坐标分别是pi,到每 ...

  4. 解析txt文本,dom4j工具输出为xml文档

    有如下一个ttl.txt文本文档,每一行用空格隔开的三段分别代表主谓宾, 要将它们输出为xml格式文档 工具:dom4j,jar包导入MyEclipse的Java Project工程 代码如下: pa ...

  5. nginx 安装与配置

    centos7环境下nginx的安装  版本 0.85 tar zxvf nginx.tar.gz cd nginx ./configure // ./configure --help 查看编译选项 ...

  6. python学习08——类

    笨办法学python第42节,这节讲的是类,程序沿用上一节中一个游戏,不同的是这一节用了类的方法. 其中改动的代码主要如下 原来的最后几句用了这样的代码: ROOMS = { 'death':deat ...

  7. Spring(2)

    Spring中的IOC和DI容器的概述 IOC(Inversion of control):其思想是反转资源获取的方向,传统的资源查找方式要求组件向容器发出请求查找资源作为回应,容器适时的返回资源 而 ...

  8. 尝试利用CentOS环境安装LiteSpeed WEB服务环境的过程

    对于普通的网站搭建的环境虚拟主机就足够使用,不过近期公司的网站需要上线VPS主机,于是采用到LNMP(http://lnmp.org/)一键包安装的,运行还是比较好的,这不最近我也开始尝试接触VPS方 ...

  9. DotNetBar for Windows Forms 12.7.0.10_冰河之刃重打包版原创发布-带官方示例程序版

    关于 DotNetBar for Windows Forms 12.7.0.10_冰河之刃重打包版 --------------------11.8.0.8_冰河之刃重打包版------------- ...

  10. hihoCoder#1094

    刚开始学习C语言,准备在做hiho的题目的过程中来学习,在此进行记录,如果代码中有错误或者不当的地方还请指正. 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 Littl ...