最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#數(shù)據(jù)結(jié)構(gòu)之雙向鏈表(DbLinkList)實(shí)例詳解

 更新時(shí)間:2015年11月27日 14:22:52   作者:Jimmy.Yang  
這篇文章主要介紹了C#數(shù)據(jù)結(jié)構(gòu)之雙向鏈表(DbLinkList),結(jié)合實(shí)例形式較為詳細(xì)的講解了雙向鏈表的概念及C#實(shí)現(xiàn)雙向鏈表的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下

本文實(shí)例講述了C#數(shù)據(jù)結(jié)構(gòu)之雙向鏈表(DbLinkList)。分享給大家供大家參考,具體如下:

這是繼上一篇《C#數(shù)據(jù)結(jié)構(gòu)之單鏈表(LinkList)實(shí)例詳解》的繼續(xù),對(duì)于雙向鏈接,節(jié)點(diǎn)上除了Next屬性外,還要有Prev屬性用來指向前一個(gè)節(jié)點(diǎn),DbNode定義如下:

namespace 線性表
{
  public class DbNode<T>
  {
    private T data;
    private DbNode<T> prev;
    private DbNode<T> next;
    public DbNode(T data, DbNode<T> next,DbNode<T> prev)
    {
      this.data = data;
      this.next = next;
      this.prev = prev;
    }
    public DbNode(T data, DbNode<T> next) 
    {
      this.data = data;
      this.next = next;
      this.prev = null;
    }
    public DbNode(DbNode<T> next) 
    {
      this.data = default(T);
      this.next = next;
      this.prev = null;
    }
    public DbNode(T data) 
    {
      this.data = data;
      this.next = null;
      this.prev = null;
    }
    public DbNode() 
    {
      data = default(T);
      next = null;
      prev = null;
    }
    public T Data 
    {
      set { this.data = value; }
      get { return this.data; }
    }
    public DbNode<T> Prev 
    {
      get { return prev; }
      set { prev = value; }
    }
    public DbNode<T> Next 
    {
      get { return next; }
      set { next = value; }
    }
  }
}

雙鏈表的插入操作要稍微復(fù)雜一點(diǎn),示意圖如下:

同樣對(duì)于刪除操作,也要額外處理prev指向

完整實(shí)現(xiàn)DbLinkList<T>:

using System;
using System.Text;
namespace 線性表
{
  public class DbLinkList<T> : IListDS<T>
  {
    private DbNode<T> head;
    public DbNode<T> Head
    {
      get { return head; }
      set { head = value; }
    }
    public DbLinkList()
    {
      head = null;
    }
    /// <summary>
    /// 類索引器
    /// </summary>
    /// <param name="index"></param>
    /// <returns></returns>
    public T this[int index] 
    {
      get
      {
        return this.GetItemAt(index);
      }
    }
    /// <summary>
    /// 返回單鏈表的長(zhǎng)度
    /// </summary>
    /// <returns></returns>
    public int Count()
    {
      DbNode<T> p = head;
      int len = 0;
      while (p != null)
      {
        len++;
        p = p.Next;
      }
      return len;
    }
    /// <summary>
    /// 清空
    /// </summary>
    public void Clear()
    {
      head = null;
    }
    /// <summary>
    /// 是否為空
    /// </summary>
    /// <returns></returns>
    public bool IsEmpty()
    {
      return head == null;
    }
    /// <summary>
    /// 在最后附加元素
    /// </summary>
    /// <param name="item"></param>
    public void Append(T item)
    {
      DbNode<T> d = new DbNode<T>(item);
      DbNode<T> n = new DbNode<T>();
      if (head == null)
      {
        head = d;
        return;
      }
      n = head;
      while (n.Next != null)
      {
        n = n.Next;
      }
      n.Next = d;
      d.Prev = n;
    }
    //前插
    public void InsertBefore(T item, int i)
    {
      if (IsEmpty() || i < 0)
      {
        Console.WriteLine("List is empty or Position is error!");
        return;
      }
      //在最開頭插入
      if (i == 0)
      {
        DbNode<T> q = new DbNode<T>(item);
        q.Next = head;//把"頭"改成第二個(gè)元素
        head.Prev = q;
        head = q;//把自己設(shè)置為"頭"
        return;
      }
      DbNode<T> n = head;
      DbNode<T> d = new DbNode<T>();
      int j = 0;
      //找到位置i的前一個(gè)元素d
      while (n.Next != null && j < i)
      {
        d = n;
        n = n.Next;
        j++;
      }
      if (n.Next == null) //說明是在最后節(jié)點(diǎn)插入(即追加)
      {
        DbNode<T> q = new DbNode<T>(item);
        n.Next = q;
        q.Prev = n;
        q.Next = null;
      }
      else
      {
        if (j == i)
        {
          DbNode<T> q = new DbNode<T>(item);
          d.Next = q;
          q.Prev = d;
          q.Next = n;
          n.Prev = q;
        }
      }
    }
    /// <summary>
    /// 在位置i后插入元素item
    /// </summary>
    /// <param name="item"></param>
    /// <param name="i"></param>
    public void InsertAfter(T item, int i)
    {
      if (IsEmpty() || i < 0)
      {
        Console.WriteLine("List is empty or Position is error!");
        return;
      }
      if (i == 0)
      {
        DbNode<T> q = new DbNode<T>(item);
        q.Next = head.Next;
        head.Next.Prev = q;
        head.Next = q;
        q.Prev = head;
        return;
      }
      DbNode<T> p = head;
      int j = 0;
      while (p != null && j < i)
      {
        p = p.Next;
        j++;
      }
      if (j == i)
      {
        DbNode<T> q = new DbNode<T>(item);
        q.Next = p.Next;
        if (p.Next != null)
        {
          p.Next.Prev = q;
        }
        p.Next = q;
        q.Prev = p;
      }
      else      
      {
        Console.WriteLine("Position is error!");
      }
    }
    /// <summary>
    /// 刪除位置i的元素
    /// </summary>
    /// <param name="i"></param>
    /// <returns></returns>
    public T RemoveAt(int i)
    {
      if (IsEmpty() || i < 0)
      {
        Console.WriteLine("Link is empty or Position is error!");
        return default(T);
      }
      DbNode<T> q = new DbNode<T>();
      if (i == 0)
      {
        q = head;
        head = head.Next;
        head.Prev = null;
        return q.Data;
      }
      DbNode<T> p = head;
      int j = 0;
      while (p.Next != null && j < i)
      {
        j++;
        q = p;
        p = p.Next;
      }
      if (j == i)
      {
        p.Next.Prev = q;
        q.Next = p.Next;        
        return p.Data;
      }
      else
      {
        Console.WriteLine("The node is not exist!");
        return default(T);
      }
    }
    /// <summary>
    /// 獲取指定位置的元素
    /// </summary>
    /// <param name="i"></param>
    /// <returns></returns>
    public T GetItemAt(int i)
    {
      if (IsEmpty())
      {
        Console.WriteLine("List is empty!");
        return default(T);
      }
      DbNode<T> p = new DbNode<T>();
      p = head;
      if (i == 0) 
      { 
        return p.Data; 
      }
      int j = 0;
      while (p.Next != null && j < i)
      {
        j++;
        p = p.Next;
      }
      if (j == i)
      {
        return p.Data;
      }
      else
      {
        Console.WriteLine("The node is not exist!");
        return default(T);
      }
    }
    //按元素值查找索引
    public int IndexOf(T value)
    {
      if (IsEmpty())
      {
        Console.WriteLine("List is Empty!");
        return -1;
      }
      DbNode<T> p = new DbNode<T>();
      p = head;
      int i = 0;
      while (!p.Data.Equals(value) && p.Next != null)
      {
        p = p.Next;
        i++;
      }
      return i;
    }
    /// <summary>
    /// 元素反轉(zhuǎn)
    /// </summary>
    public void Reverse()
    {
      DbLinkList<T> result = new DbLinkList<T>();
      DbNode<T> t = this.head;
      result.Head = new DbNode<T>(t.Data);
      t = t.Next;
      //(把當(dāng)前鏈接的元素從head開始遍歷,逐個(gè)插入到另一個(gè)空鏈表中,這樣得到的新鏈表正好元素順序跟原鏈表是相反的)
      while (t!=null)
      {        
        result.InsertBefore(t.Data, 0);
        t = t.Next;
      }
      this.head = result.head;//將原鏈表直接掛到"反轉(zhuǎn)后的鏈表"上
      result = null;//顯式清空原鏈表的引用,以便讓GC能直接回收
    }
    //得到某個(gè)指定的節(jié)點(diǎn)(為了下面測(cè)試從后向前遍歷)
    private DbNode<T> GetNodeAt(int i){
      if (IsEmpty())
      {
        Console.WriteLine("List is empty!");
        return null;
      }
      DbNode<T> p = new DbNode<T>();
      p = head;
      if (i == 0)
      {
        return p;
      }
      int j = 0;
      while (p.Next != null && j < i)
      {
        j++;
        p = p.Next;
      }
      if (j == i)
      {
        return p;
      }
      else
      {
        Console.WriteLine("The node is not exist!");
        return null;
      }
    }
    /// <summary>
    /// 測(cè)試用prev屬性從后面開始遍歷
    /// </summary>
    /// <returns></returns>
    public string TestPrevErgodic() 
    {
      DbNode<T> tail = GetNodeAt(Count() - 1);
      StringBuilder sb = new StringBuilder();
      sb.Append(tail.Data.ToString() + ",");
      while (tail.Prev != null)
      {
        sb.Append(tail.Prev.Data.ToString() + ",");
        tail = tail.Prev;
      }
      return sb.ToString().TrimEnd(',');      
    }
    public override string ToString()
    {
      StringBuilder sb = new StringBuilder();
      DbNode<T> n = this.head;
      sb.Append(n.Data.ToString() + ",");
      while (n.Next != null)
      {
        sb.Append(n.Next.Data.ToString() + ",");
        n = n.Next;
      }
      return sb.ToString().TrimEnd(',');
    }
  }
}

測(cè)試代碼片段:

Console.WriteLine("-------------------------------------");
Console.WriteLine("雙鏈表測(cè)試開始...");
DbLinkList<string> dblink = new DbLinkList<string>();
dblink.Head = new DbNode<string>("x");
dblink.InsertBefore("w", 0);
dblink.InsertBefore("v", 0);
dblink.Append("y");
dblink.InsertBefore("z", dblink.Count());
Console.WriteLine(dblink.Count());//5
Console.WriteLine(dblink.ToString());//v,w,x,y,z
Console.WriteLine(dblink[1]);//w
Console.WriteLine(dblink[0]);//v
Console.WriteLine(dblink[4]);//z
Console.WriteLine(dblink.IndexOf("z"));//4
Console.WriteLine(dblink.RemoveAt(2));//x
Console.WriteLine(dblink.ToString());//v,w,y,z
dblink.InsertBefore("x", 2);
Console.WriteLine(dblink.ToString());//v,w,x,y,z
Console.WriteLine(dblink.GetItemAt(2));//x
dblink.Reverse();
Console.WriteLine(dblink.ToString());//z,y,x,w,v
dblink.InsertAfter("1", 0);
dblink.InsertAfter("2", 1);
dblink.InsertAfter("6", 5);
dblink.InsertAfter("8", 7);
dblink.InsertAfter("A", 10);//Position is error!
Console.WriteLine(dblink.ToString()); //z,1,2,y,x,w,6,v,8 
string _tail = dblink.GetItemAt(dblink.Count()-1);
Console.WriteLine(_tail);
Console.WriteLine(dblink.TestPrevErgodic());//8
Console.ReadKey(); //8,v,6,w,x,y,2,1,z

當(dāng)然從上面的測(cè)試代碼中,似乎并不能看出雙鏈表的優(yōu)點(diǎn),雙鏈表的好處在于,如果需要在鏈表中,需要通過某個(gè)節(jié)點(diǎn)得到它的前驅(qū)節(jié)點(diǎn)時(shí),雙鏈表直接用prev屬性就能找到;而單鏈表要做到這一點(diǎn),必須再次從Head節(jié)點(diǎn)開始一個(gè)一個(gè)用Next向下找,這樣時(shí)間復(fù)雜度從O(n)降到O(1),顯然更有效率。

注:如果把雙鏈表再做一下改造,讓頭尾接起來,即Head的Prev屬性指向最后一個(gè)節(jié)點(diǎn)(就叫做Tail吧),同時(shí)把Tail節(jié)點(diǎn)的Next屬性指向Head節(jié)點(diǎn),就形成了所謂的“循環(huán)雙向鏈表

當(dāng)然,這樣的結(jié)構(gòu)可以在鏈表中再增加一個(gè)Tail節(jié)點(diǎn)屬性,在做元素插入或刪除時(shí),可以循環(huán)到底以更新尾節(jié)點(diǎn)Tail(當(dāng)然這樣會(huì)給插入/刪除元素帶來一些額外的開銷),但是卻可以給GetItemAt(int i)方法帶來優(yōu)化的空間,比如要查找的元素在前半段時(shí),可以從Head開始用next向后找;反之,如果要找的元素在后半段,則可以從Tail節(jié)點(diǎn)用prev屬性向前找。

注:.Net中微軟已經(jīng)給出了一個(gè)內(nèi)置的雙向鏈表System.Collections.Generic.LinkedList<T>,在了解雙鏈表的原理后,建議大家直接系統(tǒng)內(nèi)置的鏈表。

希望本文所述對(duì)大家C#程序設(shè)計(jì)有所幫助。

相關(guān)文章

  • c# 實(shí)現(xiàn)子窗口關(guān)閉父窗口也關(guān)閉的方法

    c# 實(shí)現(xiàn)子窗口關(guān)閉父窗口也關(guān)閉的方法

    下面小編就為大家?guī)硪黄猚# 實(shí)現(xiàn)子窗口關(guān)閉父窗口也關(guān)閉的方法。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-01-01
  • C#實(shí)現(xiàn)文件分割和合并的示例詳解

    C#實(shí)現(xiàn)文件分割和合并的示例詳解

    這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)文件分割和合并的功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • C#操作數(shù)據(jù)庫中存取圖片文件的方法

    C#操作數(shù)據(jù)庫中存取圖片文件的方法

    這篇文章主要介紹了C#操作數(shù)據(jù)庫中存取圖片文件的方法,以實(shí)例形式分析了C#將圖片存入數(shù)據(jù)庫及從數(shù)據(jù)庫讀取圖片文件的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-10-10
  • C#控件編程之文本框(TextBox)的使用

    C#控件編程之文本框(TextBox)的使用

    這篇文章主要介紹了C#控件編程之文本框(TextBox)的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • C#使用二分查找法判斷指定字符的方法

    C#使用二分查找法判斷指定字符的方法

    這篇文章主要介紹了C#使用二分查找法判斷指定字符的方法,結(jié)合實(shí)例形式分析了C#二分查找法進(jìn)行字符串查找的定義與使用技巧,需要的朋友可以參考下
    2016-06-06
  • Unity實(shí)現(xiàn)3D射箭小游戲

    Unity實(shí)現(xiàn)3D射箭小游戲

    這篇文章主要為大家詳細(xì)介紹了Unity實(shí)現(xiàn)3D射箭小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-04-04
  • 最新評(píng)論

    静海县| 康马县| 锦屏县| 涿鹿县| 伽师县| 禹城市| 晋城| 昆明市| 临湘市| 兖州市| 黑龙江省| 资源县| 义马市| 南宫市| 精河县| 塘沽区| 景德镇市| 西贡区| 山东| 获嘉县| 武宣县| 银川市| 安吉县| 宜章县| 改则县| 易门县| 美姑县| 万年县| 石首市| 额济纳旗| 绥滨县| 和硕县| 田阳县| 沭阳县| 新沂市| 墨江| 汉源县| 三门县| 理塘县| 洮南市| 育儿|