单链表允许从一个结点直接访问它的后继结点,所以, 找直接后继结点的时间复杂度是 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. IT求职中,笔试、面试的算法准备

    PS:此文章为转载,源地址:http://www.newsmth.net/nForum/#!article/CoderInterview/849     作者应该是在美国进行的笔试面试,感觉面试的的公 ...

  2. ios基础篇(二十五)—— Animation动画(UIView、CoreAnimation)

    Animation主要分为两类: 1.UIView属性动画 2.CoreAnimation动画 一.UIView属性动画 UIKit直接将动画集成到UIView类中,实现简单动画的创建过程.UIVie ...

  3. Java8之——简洁优雅的Lambda表达式

    Java8发布之后,Lambda表达式,Stream等等之类的字眼边慢慢出现在我们字眼.就像是Java7出现了之后,大家看到了“钻石语法”,看到了try-with-resource等等.面对这些新东西 ...

  4. JAVA基础----java中E,T,?的区别?

    http://825635381.iteye.com/blog/2017650 遇到<A>,<B>,<K,V>等,是用到了java中的泛型. 一般使用<T&g ...

  5. centos下在线安装mysql

    1 首先查看是否有安装过,如果已经安装过,就不必再安装了 yum list installed mysql* rpm -qa | grep mysql* 2 查看有没有安装包: yum list my ...

  6. C# ADO.NET 连接Sybase 数据库

    using Sybase.Data.AseClient;//反编译修改后的DLL public class SybaseHelper { public AseConnection con; publi ...

  7. CentOS安装crontab及使用方法(汇总多人博客并实践确认无误)

    安装centOS: yum -y install vixie-cron --该软件包是cron的主程序 yum -y install crontabs--该软件包用来安装.卸载或者列举需要cron来守 ...

  8. Get the current user permission level on a list item with ecmascript 分类: Sharepoint 2015-07-14 14:13 7人阅读 评论(0) 收藏

    To Check current users permissions using Ecmascript\Javascript client object model SharePoint 2010. ...

  9. Delphi: 有关Form处理 :需要调用的时候进行调用。

    if not Assigned(frmAppServer) then frmAppServer := TfrmAppServer.Create(Application); frmAppServer.S ...

  10. ibatis入门教程

    转载自  http://www.cnblogs.com/ycxyyzw/archive/2012/10/13/2722567.html iBatis 简介: iBatis 是apache 的一个开源项 ...