數據結構-雙向鏈表&雙向循環鏈表

借圖:http://www.cnblogs.com/skywang12345/p/3561803.html#a33

雙向鏈表

雙向鏈表(雙鏈表)是鏈表的一種。和單鏈表同樣,雙鏈表也是由節點組成,它的每一個數據結點中都有兩個指針,分別指向直接後繼和直接前驅。html

 

 

 實現:接口ide

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _001_線性表
{
    interface IListDS<T>
    {
        int GetLength();
        void Clear();
        bool IsEmpty();
        void Add(T item);
        void Insert(T item, int index);
        T Delete(int index);
        T this[int index] { get; }
        T GetEle(int index);
        int Locate(T value);

    }
}
View Code

雙向節點:oop

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace _001_線性表
{
    /// <summary>
    /// 雙向節點
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class DbNode<T>
    {
        private T data;
        private DbNode<T> prev;
        private DbNode<T> next;

        public DbNode(T val,DbNode<T> p,DbNode<T> n)
      {
          this.data = val;
          this.prev = p;
          this.next = n;
      }
        public DbNode(DbNode<T> p)
        {
            next = p;
        }
        public DbNode(T val)
        {
            data = val;
            next = null;
            prev = null;
        }
        public DbNode()
        {
            data = default(T);
            next = null;
            prev = null;
        }
        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 void SetNode(DbNode<T> pre,DbNode<T> next)
        {
            this.prev = pre;
            this.next = next;
        }



    }
}
View Code

雙向鏈表:this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace _001_線性表
{
    /// <summary>
    /// 雙向鏈表
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class DoubleLink<T>:IListDS<T>
    {
        #region IListDS<T> 成員

        private DbNode<T> _linkHead;
        public DoubleLink()
        {
            _linkHead = null;
        }
       
        public int GetLength()
        {
            if (IsEmpty()) return 0;
            DbNode<T> temp = _linkHead;
            int length = 1;
            while (temp.Next != null)
            {
                 length++;
                 temp = temp.Next;
            }
            return length;
        }

        public void Clear()
        {
            _linkHead = null;
        }

        public bool IsEmpty()
        {
            return _linkHead == null;
        }

        /// <summary>
        /// 在雙向鏈表的尾端添加一個新數據
        /// </summary>
        /// <param name="item"></param>
        public void Add(T item)
        {
            DbNode<T> newNode = new DbNode<T>(item);
            if (IsEmpty())
            {
                _linkHead = newNode;
            }
            else
            {
                DbNode<T> preNode = GetListItem(this.GetLength() - 1);
                newNode.Prev = newNode;
                preNode.Next = newNode.Prev;
                newNode.Prev = preNode;
            }
        }

        /// <summary>
        /// 獲取指定位置的雙向鏈表項目,頭項從0開始
        /// </summary>
        public DbNode<T> GetListItem(int index)
        {
            if (index < 0)
                throw new Exception("索引不能小於0");
            if (index > this.GetLength() - 1)
                throw new Exception("索引超出列表總長度");
            DbNode<T> temp = _linkHead;
            for (int i = 0; i < index; i++)
            {
                temp = temp.Next;
            }
            return temp;
        }

        /// <summary>
        /// 在雙向鏈表指定的位置插入一個新項
        /// </summary>
        public void Insert(T item, int index)
        {
            if (index < 0)
                throw new Exception("插入位置不能小於0");
            if (index > this.GetLength() + 1)
                throw new Exception("插入位置超出鏈表長度");
            DbNode<T> newNode = new DbNode<T>(item);
            if (index == 0)
            {
                newNode.Next = _linkHead;
                _linkHead = newNode;
            }
            else
            {
                DbNode<T> preNode = GetListItem(index - 1); //要插入位置前面的節點
                DbNode<T> atfNode = GetListItem(index);//要插入位置後面的節點
                preNode.Next = new DbNode<T>(item, preNode, atfNode);
            }
        }


        /// <summary>
        /// 刪除指定位置的雙向鏈表項
        /// </summary>
        /// <param name="index"></param>
        public T Delete(int index)
        {
            if (index < 0)
                throw new Exception("刪除位置不能小於0");
            if (index > this.GetLength() - 1)
                throw new Exception("插入位置超出鏈表長度");

            T data = default(T);
            if (index == 0)
            {
                data = _linkHead.Data;
                _linkHead = _linkHead.Next;
                if(!IsEmpty())
                    this._linkHead.Prev = null;
            }
            else
            {
                DbNode<T> DelNode = GetListItem(index); //取到要刪除的節點
                data = DelNode.Data;
                DbNode<T> preNode = DelNode.Prev;
                DbNode<T> nextNode = DelNode.Next;
                preNode.Next = nextNode;
                nextNode.Prev = preNode;
            }
            return data;
        }

        public T this[int index]
        {
            get { return GetEle(index); }
        }

        public T GetEle(int index)
        {
            DbNode<T> temp = _linkHead;
            for (int i = 0; i < index; i++)
            {
                temp = temp.Next;
            }
            return temp.Data;
        }

        public int Locate(T value)
        {
            DbNode<T> temp = _linkHead;
            if (IsEmpty())
            {
                return -1;
            }
            else
            {
                int index = 0;
                while (true)
                {
                    if (!temp.Data.Equals(value))
                    {
                        if (temp.Next != null)
                        {
                            index++;
                            temp = temp.Next;
                        }
                        else
                        {
                            break;
                        }
                    }
                    else
                    {
                        return index;
                    }
                }
                return -1;
            }
        }
        #endregion
    }
}

 

雙向循環鏈表

從雙向鏈表中的任意一個結點開始,均可以很方便地訪問它的前驅結點和後繼結點。通常咱們都構造雙向循環鏈表。spa

雙鏈表的示意圖以下:指針

表頭爲空,表頭的後繼節點爲"節點10"(數據爲10的節點);"節點10"的後繼節點是"節點20"(數據爲10的節點),"節點20"的前繼節點是"節點10";"節點20"的後繼節點是"節點30","節點30"的前繼節點是"節點20";...;末尾節點的後繼節點是表頭。code

雙鏈表刪除節點

刪除"節點30"
刪除以前:"節點20"的後繼節點爲"節點30","節點30" 的前繼節點爲"節點20"。"節點30"的後繼節點爲"節點40","節點40" 的前繼節點爲"節點30"。
刪除以後:"節點20"的後繼節點爲"節點40","節點40" 的前繼節點爲"節點20"。htm

 雙鏈表添加節點

 

在"節點10"與"節點20"之間添加"節點15"
添加以前:"節點10"的後繼節點爲"節點20","節點20" 的前繼節點爲"節點10"。
添加以後:"節點10"的後繼節點爲"節點15","節點15" 的前繼節點爲"節點10"。"節點15"的後繼節點爲"節點20","節點20" 的前繼節點爲"節點15"。blog

實現:索引

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace _001_線性表
{
    /// <summary>
    /// 雙向循環鏈表
    /// </summary>
    /// <typeparam name="T"></typeparam>
    class DoubleLoopLink<T> : IListDS<T>
    {
        private DbNode<T> _linkHead;
        public T this[int index] =>GetEle(index);

        public void Add(T item)
        {
            DbNode<T> newNode = new DbNode<T>(item, null, null);
            if (IsEmpty())
            {
                _linkHead = newNode;
                _linkHead.Prev = _linkHead;
                _linkHead.Next = _linkHead;
            }
            else
            {
                DbNode<T> preNode = _linkHead;
                while (preNode.Next != _linkHead)
                {
                    preNode = preNode.Next;
                }
                preNode.Next = newNode;//鏈表的尾部 的後指針  指向新的節點
                newNode.SetNode(preNode, _linkHead);     
                _linkHead.Prev = newNode; //頭部的 前指針 指向 新的尾部
            }
        }
        
        public void Clear()
        {
            _linkHead = null;
        }

        public T Delete(int index)
        {
            T data = default(T);
            if (IsEmpty())
                throw new Exception("鏈表爲空,沒有可清除的項");
            if (index < 0 || index > this.GetLength() - 1)
                throw new Exception("給定索引超出鏈表長度");

            DbNode<T> preNode = _linkHead;
            if (index == 0)
            {
                while (preNode.Next != _linkHead)
                {
                    preNode = preNode.Next;
                }
                this._linkHead = _linkHead.Next;
                this._linkHead.Prev = preNode;
                data = preNode.Next.Data;
                preNode.Next = this._linkHead;
            }
            else
            {
                for (int i = 1; i < index - 1; i++)
                {
                    preNode = preNode.Next;
                }
                //看圖比較好理解
                DbNode<T> aftNode = preNode.Next.Next; //要刪除的節點  後面的節點
                preNode.Next = aftNode;//要刪除節點的前面節點 的後指針 指向  要刪除的節點  後面的節點
                aftNode.Prev = preNode; //要刪除的節點 前面的節點  指向  要刪除節點的前面節點    
            }
            return data;
        }

        public T GetEle(int index)
        {
            DbNode<T> temp = _linkHead;
            for (int i = 0; i < index; i++)
            {
                temp = temp.Next;
            }
            return temp.Data;
        }

        public int GetLength()
        {
            if (IsEmpty()) return 0;
            DbNode<T> temp = _linkHead;
            int length = 1;
            while (temp.Next != _linkHead)
            {
                length++;
                temp = temp.Next;
            }
            return length;
        }
        /// <summary>
        /// 插入
        /// </summary>
        /// <param name="item"></param>
        /// <param name="index"></param>
        public void Insert(T item, int index)
        {
            if (IsEmpty())
                throw new Exception("數據鏈表爲空");
            if (index < 0 || index > this.GetLength())
                throw new Exception("給定索引超出鏈表長度");

            DbNode<T> newNode = new DbNode<T>(item);
            DbNode<T> preNode = _linkHead;
            if (index == 0) //等於零  先找到 鏈表中 head的前一個節點 這個節點鏈接 head
            {
                while (preNode.Next != _linkHead)
                {
                    preNode = preNode.Next;
                }
                preNode.Next = newNode;
                newNode.SetNode(preNode, _linkHead);
                _linkHead.Prev = newNode;
                return;
            }
            else
            {
                for (int i = 1; i < index - 1; i++)
                {
                    preNode = preNode.Next;
                }
                //preNode要插入位置的前節點
                DbNode<T> atfNode = preNode.Next;//要插入節點的後節點
                preNode.Next = newNode; //後指針 連上新節點
                newNode.SetNode(preNode,atfNode);
                atfNode.Prev = newNode;//要插入節點的後節點 連上 新節點
            }
        }
        public bool IsEmpty()
        {
            return _linkHead == null;
        }

        public int Locate(T value)
        {
            if (IsEmpty())
                throw new Exception("鏈表爲空");
            DbNode<T> preNode = _linkHead;
            int index = 0;
            while (true)
            {
                if (!preNode.Data.Equals(value))
                {
                    if (preNode.Next != _linkHead)
                    {
                        index++;
                        preNode = preNode.Next;
                    }
                    else
                    {
                        break;
                    }
                }
                else
                {
                    return index;
                }
            }
            return -1;
        }
    }
}
View Code

 

基本的鏈表大概就是這樣了。