单链表允许从一个结点直接访问它的后继结点,所以, 找直接后继结点的时间复杂度是 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. Excel函数汇总:

    /** *D1—要查找的目标值 *G:G—查找的单元格范围,G:G表示G列 *1—查找第一个匹配 *FALSE—找到结果即返回 */ VLOOKUP(D1,G:G,1,FALSE):返回查找到的单元格 ...

  2. (转)Tomcat数据源连接池加密

    文章来源 :http://my.oschina.net/cimu/blog/164757 我们在使用Tomcat数据库连接池的时候都是明文存储数据库用户名和密码的,例如: <Resource n ...

  3. CentOS6.5 下安装 texlive2015 并设置 ctex 中文套装

    0 卸载旧版本的 texlive 0.1 卸载 texlive2007 如果系统没有安装过texlive,则跳过第0步. 可以在终端中使用如下命令查询本机已经安装的tex和latex版本: [She@ ...

  4. Leetcode 详解(ReverseWords)

    Leetcode里面关于字符串的一些问题,描述如下: Given an input string, reverse the string word by word. For example,Given ...

  5. php生成图片缩略图,支持png透明

    注:此功能依赖GD2图形库 PHP生成缩略图类   <?php /* * desc: Resize Image(png, jpg, gif) * author: 十年后的卢哥哥(http://w ...

  6. 【 2013 Multi-University Training Contest 8 】

    HDU 4678 Mine 对于每个空白区域,求SG值. 最后异或起来等于0,先手必败. #pragma comment(linker,"/STACK:102400000,102400000 ...

  7. HDU--杭电--1026--Ignatius and the Princess I--广搜--直接暴力0MS,优先队列的一边站

    别人都是广搜+优先队列,我没空临时学,所以就直接自己暴力了 Ignatius and the Princess I Time Limit: 2000/1000 MS (Java/Others)     ...

  8. 简易线程池Thread Pool

    1. 基本思路 写了个简易的线程池,基本的思路是: 有1个调度线程,负责维护WorkItem队列.管理线程(是否要增加工作线程).调度(把工作项赋给工作线程)等 线程数量随WorkItem的量动态调整 ...

  9. StormNimbus集群保证CAP流程

    Nimbus启动时,检查当前本地是不是有所有的topology的代码,同时去申请获取leader锁,如果某台nimbus节点成为了集群的leader,会再去检查一次当前本地的代码是不是包含所有活动状态 ...

  10. memcpy函数用法

    memcpy函数用法 .分类: VC++ VC++ mfc matlab 2011-12-01 19:17 14538人阅读 评论(0) 收藏 举报 null 原型:extern void *memc ...