单链表允许从一个结点直接访问它的后继结点,所以, 找直接后继结点的时间复杂度是 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. ArcGIS Engine控件运行许可(转)

    ArcGIS Engine控件运行许可   Runtime绑定: 在ArcGIS Engine10.0中,许可方式发生了一定的变化,ArcGis10有一个新的要求---runtime绑定.就是在任何A ...

  2. C语言实现四则运算

    学生:宋丹丹 张潇裕 #include<iostream>#include<ctime>using namespace std;void main(){ int x1,x2,a ...

  3. Gerald's Hexagon

    Gerald's Hexagon Gerald got a very curious hexagon for his birthday. The boy found out that all the ...

  4. 将centos7打造成桌面系统

    前言以下所有操作默认在root权限下执行,桌面环境是kde,使用gnome的也可以参考一下.我收集的以下要用到的一些安装包,360网盘http://yunpan.cn/csMhBAp92vTgN 提取 ...

  5. SQL SERVER 2008

    sql server 2008 r2 下载安装教程 sql server 2008 是微软公司开发的一套数据库管理系统.是目前大型数据库中常用数据库之一.性能稳定,功能强大,是面向中大型企业的一款数据 ...

  6. python date

    三天前 datetime.datetime.now() - datetime.timedelta(days=3)

  7. Java代理模式/静态代理/动态代理

    代理模式:即Proxy Pattern,常用的设计模式之一.代理模式的主要作用是为其他对象提供一种代理以控制对这个对象的访问. 代理概念 :为某个对象提供一个代理,以控制对这个对象的访问. 代理类和委 ...

  8. SQL Server 2012提供的OFFSET/FETCH NEXT与Row_Number()对比测试 [T]

    SQL Server 2008中SQL应用系列--目录索引 前些天看到一篇文章<SQL Server 2012 - Server side paging demo using OFFSET/FE ...

  9. JavaScript Array对象sort() 方法小结

    sort() 方法用于对数组的元素进行排序. 语法arrayObject.sort(sortfunction) 参数sortfunction 可选.规定排序顺序.必须是函数. 返回值对数组的引用.请注 ...

  10. 前端面试题之Html和CSS

    又到了毕业季,很多小伙伴们都到了找工作的时候了,好多小伙伴问我有前端的面试题么?答:没有. 呃呃… … 小伙伴本宝宝真的没有骗你们,我从毕业到现在一直在一家公司没有换过,所以手里压根没有面试题.我们公 ...