国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C# > 正文

C#數據結構之單鏈表(LinkList)實例詳解

2020-01-24 01:21:33
字體:
來源:轉載
供稿:網友

本文實例講述了C#數據結構之單鏈表(LinkList)實現方法。分享給大家供大家參考,具體如下:

這里我們來看下“單鏈表(LinkList)”。在上一篇《C#數據結構之順序表(SeqList)實例詳解》的最后,我們指出了:順序表要求開辟一組連續的內存空間,而且插入/刪除元素時,為了保證元素的順序性,必須對后面的元素進行移動。如果你的應用中需要頻繁對元素進行插入/刪除,那么開銷會很大。

而鏈表結構正好相反,先來看下結構:

每個元素至少具有二個屬性:data和next。data用來存放數據,而next用來指出它后面的元素是誰(有點“指針”的意思)。

鏈表中的元素,通常也稱為節點Node,下面是泛型版本的Node.cs

namespace 線性表{  public class Node<T>  {    private T data;    private Node<T> next;    public Node(T val, Node<T> p)     {      data = val;      next = p;    }    public Node(Node<T> p)     {      next = p;    }    public Node(T val)     {      data = val;      next = null;    }    public Node()     {      data = default(T);      next = null;    }    public T Data     {      get { return data; }      set { data = value; }    }    public Node<T> Next     {      get { return next; }      set { next = value; }    }  }}

鏈表在存儲上并不要求所有元素按順序存儲,因為用節點的next就能找到下一個節點,這好象一根“用珠子串成的鏈子”,要找到其中的某一顆珠子,只要從第一顆節點(通常稱為Head節點)開始,不斷根據next指向找到下一個,直到找到需要的節點為止。

鏈表中需要有一個Head節點做為開始,這跟順序表有所不同,下面是單鏈表的實現:

using System;using System.Text;namespace 線性表{  public class LinkList<T> : IListDS<T>  {    private Node<T> head;    public Node<T> Head    {      get { return head; }      set { head = value; }    }    public LinkList()    {      head = null;    }    /// <summary>    /// 類索引器    /// </summary>    /// <param name="index"></param>    /// <returns></returns>    public T this[int index]     {      get      {        return this.GetItemAt(index);      }    }    /// <summary>    /// 返回單鏈表的長度    /// </summary>    /// <returns></returns>    public int Count()    {      Node<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)    {      Node<T> d = new Node<T>(item);      Node<T> n = new Node<T>();      if (head == null)      {        head = d;        return;      }      n = head;      while (n.Next != null)      {        n = n.Next;      }      n.Next = d;    }    //前插    public void InsertBefore(T item, int i)    {      if (IsEmpty() || i < 0)      {        Console.WriteLine("List is empty or Position is error!");        return;      }      //在最開頭插入      if (i == 0)      {        Node<T> q = new Node<T>(item);        q.Next = Head;//把"頭"改成第二個元素        head = q;//把自己設置為"頭"        return;      }      Node<T> n = head;      Node<T> d = new Node<T>();      int j = 0;      //找到位置i的前一個元素d      while (n.Next != null && j < i)      {        d = n;        n = n.Next;        j++;      }      if (n.Next == null) //說明是在最后節點插入(即追加)      {        Node<T> q = new Node<T>(item);        n.Next = q;        q.Next = null;      }      else      {        if (j == i)        {          Node<T> q = new Node<T>(item);          d.Next = q;          q.Next = n;        }      }    }    /// <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)      {        Node<T> q = new Node<T>(item);        q.Next = head.Next;        head.Next = q;        return;      }      Node<T> p = head;      int j = 0;      while (p != null && j < i)      {        p = p.Next;        j++;      }      if (j == i)      {        Node<T> q = new Node<T>(item);        q.Next = p.Next;        p.Next = q;      }      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);      }      Node<T> q = new Node<T>();      if (i == 0)      {        q = head;        head = head.Next;        return q.Data;      }      Node<T> p = head;      int j = 0;      while (p.Next != null && j < i)      {        j++;        q = p;        p = p.Next;      }      if (j == i)      {        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);      }      Node<T> p = new Node<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;      }      Node<T> p = new Node<T>();      p = head;      int i = 0;      while (!p.Data.Equals(value) && p.Next != null)      {        p = p.Next;        i++;      }      return i;    }    /// <summary>    /// 元素反轉    /// </summary>    public void Reverse()    {      LinkList<T> result = new LinkList<T>();      Node<T> t = this.head;      result.Head = new Node<T>(t.Data);      t = t.Next;      //(把當前鏈接的元素從head開始遍歷,逐個插入到另一個空鏈表中,這樣得到的新鏈表正好元素順序跟原鏈表是相反的)      while (t!=null)      {                result.InsertBefore(t.Data, 0);        t = t.Next;      }      this.head = result.head;//將原鏈表直接掛到"反轉后的鏈表"上      result = null;//顯式清空原鏈表的引用,以便讓GC能直接回收    }    public override string ToString()    {      StringBuilder sb = new StringBuilder();      Node<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(',');    }  }}

下面是單鏈表插入和刪除的算法圖解:

可以看到:鏈表在元素插入/刪除時,無需對后面的元素進行移動,只需要修改自身以及相鄰節點的next指向即可,所以插入/刪除元素的開銷要比順序表小得多。但是也應該注意到,其它操作比如:查找元素,反轉倒置鏈表等,有可能需要遍歷整個鏈表中的所有元素。

測試代碼片斷:

Console.WriteLine("-------------------------------------");Console.WriteLine("單鏈表測試開始...");LinkList<string> link = new LinkList<string>();link.Head = new Node<string>("x");link.InsertBefore("w", 0);link.InsertBefore("v", 0);link.Append("y");link.InsertBefore("z", link.Count());Console.WriteLine(link.Count());//5Console.WriteLine(link.ToString());//v,w,x,y,zConsole.WriteLine(link[1]);//wConsole.WriteLine(link[0]);//vConsole.WriteLine(link[4]);//zConsole.WriteLine(link.IndexOf("z"));//4Console.WriteLine(link.RemoveAt(2));//xConsole.WriteLine(link.ToString());//v,w,y,zlink.InsertBefore("x", 2);Console.WriteLine(link.ToString());//v,w,x,y,zConsole.WriteLine(link.GetItemAt(2));//xlink.Reverse();Console.WriteLine(link.ToString());//z,y,x,w,vlink.InsertAfter("1", 0);link.InsertAfter("2", 1);link.InsertAfter("6", 5);link.InsertAfter("8", 7);link.InsertAfter("A", 10);//Position is error!Console.WriteLine(link.ToString()); //z,1,2,y,x,w,6,v,8

至于具體在實際應用中應該選用順序表 or 鏈表,主要是看:對于元素插入/刪除的頻繁程度以及對于內存分配的苛刻程度。 如果不要求一開始就分配一組連續的內存區域,可以根據元素的增加而自動加大內存的使用量,或者插入/刪除的次數很多,那么建議使用鏈表,反之用順序表。

最后指出:可以給節點再添加一個prev元素,用于指出前一個節點是誰,即同時有next和prev二個指向,這種改進后的鏈表稱為“雙向鏈表”,它有助于某些情況下減少遍歷循環的次數,本文中的這種僅有一個next指向的鏈表,稱為“單鏈表”。

希望本文所述對大家C#程序設計有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 新竹县| 稻城县| 淮北市| 望都县| 榕江县| 大城县| 家居| 墨脱县| 沙雅县| 玉屏| 宜都市| 荔浦县| 奇台县| 连山| 湖北省| 定西市| 定西市| 理塘县| 九台市| 哈巴河县| 木兰县| 古浪县| 承德县| 玉田县| 鸡西市| 法库县| 吉木萨尔县| 台州市| 东方市| 铜鼓县| 衡阳市| 邹城市| 桐乡市| 裕民县| 乐昌市| 聊城市| 平南县| 重庆市| 调兵山市| 宣化县| 周宁县|