线性表

来源:互联网 发布:怪物猎人x中文数据库 编辑:程序博客网 时间:2024/06/01 10:24

数据间存在三种基本关系:

<1>  线性关系。

<2>  树形关系。

<3>  网状关系。

 

一: 线性表

      1 概念:

                 线性表也就是关系户中最简单的一种关系,一对一。

                  如:学生学号的集合就是一个线性表。

     

      2 特征:

                 ① 有且只有一个“首元素“。

                 ② 有且只有一个“末元素”。

                 ③ 除“末元素”外,其余元素均有唯一的后继元素。

                 ④ 除“首元素”外,其余元素均有唯一的前驱元素。

     

     3 存储划分:

                  ① 如果把线性表用“顺序存储”,那么就是“顺序表”。

                  ② 如果把线性表用“链式存储”,那么就是“链表”。

     

     4  常用操作:添加,删除,插入,查找,遍历,统计。

 

今天主要就说说“线性表”的“顺序存储”。

 

那么下面就简单的浅析一下这个操作的原理和复杂度。

     <1> 初始化顺序表:  

                           这个操作其实还是蛮简单的,设置length=0,也就是O(1)的时间。

     <2> 求顺序表长度:  

                           这个不解释,O(1)的时间。

     <3> 添加节点:      

                           因为是顺序表,所以添加的节点直接会放到数组的末尾,时间也是O(1)的。

     <4> 插入节点:

                           这个还是有点小麻烦的,主要也就是说分两种情况:

                                    ①:当插入节点在数组的最后,那么这个“插入”其实就是”添加“操作,时间当然是O(1)。

                                    ②:当插入节点在数组的开头,那就悲催了,被插入节点的后续元素都要向后移动一位,

                                            也就让整个数组一阵痉挛,效率低下可想而知,时间复杂度退化为O(n)。

      <5> 删除节点:      

                             这个跟“插入”的道理是一样的,也要分两个情况,

                                     ①:当删除的元素在数组的最后,不用移位,谢天谢地,时间为O(1)。

                                     ②: 当删除的元素在数组的开头,删除节点处的元素都要统统向前移位,同样也是一阵痉挛,

                                               时间复杂度也退化为O(n)。

      <6> 按序号查找节点:

                               大家都知道,顺序表的存储地址是连续的,所以第N个元素地址公式为:(N-1)X 数据存储长度。

                                        哈哈,这就是顺序表得瑟的地方,查找的时间复杂度为O(1)。

      <7> 按关键字查找:  

                                 嗯,这个在日常开发中用的最多的,那么就避免不了将key的值在我们的list中查找,前期也说过,

                                        最快的查找是O(1),当然他是用空间来换取时间的,最慢的查找是O(n),那么这里我们就一个for

                                        循环搞定,时间复杂度为O(n)。

 

说了这么多,目的就是预先评估算法的执行效率,给我们带来一手的参考资料,做到真正的运筹帷幄,决胜千里之外。

这也是我们学习算法的目的,到时候不会让我们说tnd,程序歇菜了,我也歇菜了。


好,现在是上代码时间。

[java] view plaincopy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5.   
  6. namespace SeqList  
  7. {  
  8.     public class Program  
  9.     {  
  10.         static void Main(string[] args)  
  11.         {  
  12.             SeqList seq = new SeqList();  
  13.             SeqListType<Student> list = new SeqListType<Student>();  
  14.             Console.WriteLine("\n********************** 添加二条数据 ************************\n");  
  15.             seq.SeqListAdd<Student>(list, new Student() { ID = "1", Name = "一线码农", Age = 23 });  
  16.             seq.SeqListAdd<Student>(list, new Student() { ID = "3", Name = "huangxincheng520", Age = 23 });  
  17.             Console.WriteLine("添加成功");  
  18.             //展示数据  
  19.             Display(list);  
  20.             Console.WriteLine("\n********************** 正在搜索Name=“一线码农”的实体 ************************\n");  
  21.             var student = seq.SeqListFindByKey<Student, string>(list, "一线码农", s => s.Name);  
  22.             Console.WriteLine("\n********************** 展示一下数据 ************************\n");  
  23.             if (student != null)  
  24.                 Console.WriteLine("ID:" + student.ID + ",Name:" + student.Name + ",Age:" + student.Age);  
  25.             else  
  26.                 Console.WriteLine("对不起,数据未能检索到。");  
  27.             Console.WriteLine("\n********************** 插入一条数据 ************************\n");  
  28.             seq.SeqListInsert(list, 1new Student() { ID = "2", Name = "博客园", Age = 40 });  
  29.             Console.WriteLine("插入成功");  
  30.             //展示一下  
  31.             Display(list);  
  32.             Console.WriteLine("\n********************** 删除一条数据 ************************\n");  
  33.             seq.SeqListDelete(list, 0);  
  34.             Console.WriteLine("删除成功");  
  35.             //展示一下数据  
  36.             Display(list);  
  37.             Console.Read();  
  38.         }  
  39.   
  40.         ///<summary>  
  41. /// 展示输出结果  
  42. ///</summary>  
  43.         static void Display(SeqListType<Student> list)  
  44.         {  
  45.             Console.WriteLine("\n********************** 展示一下数据 ************************\n");  
  46.             if (list == null || list.ListLen == 0)  
  47.             {  
  48.                 Console.WriteLine("呜呜,没有数据");  
  49.                 return;  
  50.             }  
  51.             for (int i = 0; i < list.ListLen; i++)  
  52.             {  
  53.                 Console.WriteLine("ID:" + list.ListData[i].ID + ",Name:" + list.ListData[i].Name + ",Age:" + list.ListData[i].Age);  
  54.             }  
  55.         }  
  56.     }  
  57.   
  58.     #region 学生的数据结构  
  59.     ///<summary>  
  60. /// 学生的数据结构  
  61. ///</summary>  
  62.     public class Student  
  63.     {  
  64.         public string ID { get; set; }  
  65.         public string Name { get; set; }  
  66.         public int Age { get; set; }  
  67.     }  
  68.     #endregion  
  69.   
  70.     #region 定义一个顺序表的存储结构  
  71.     ///<summary>  
  72. /// 定义一个顺序表的存储结构  
  73. ///</summary>  
  74.     public class SeqListType<T>  
  75.     {  
  76.         private const int maxSize = 100;  
  77.         public int MaxSize { get { return maxSize; } }  
  78.         //数据为100个存储空间  
  79.         public T[] ListData = new T[maxSize];  
  80.         public int ListLen { get; set; }  
  81.     }  
  82.     #endregion  
  83.   
  84.     #region 顺序表的相关操作  
  85.     ///<summary>  
  86. ///顺序表的相关操作  
  87. ///</summary>  
  88.     public class SeqList  
  89.     {  
  90.         #region 顺序表初始化  
  91.         ///<summary>  
  92. /// 顺序表初始化  
  93. ///</summary>  
  94. ///<param name="t"></param>  
  95.         public void SeqListInit<T>(SeqListType<T> t)  
  96.         {  
  97.             t.ListLen = 0;  
  98.         }  
  99.         #endregion  
  100.   
  101.         #region 顺序表的长度  
  102.         ///<summary>  
  103. /// 顺序表的长度  
  104. ///</summary>  
  105. ///<param name="t"></param>  
  106. ///<returns></returns>  
  107.         public int SeqListLen<T>(SeqListType<T> t)  
  108.         {  
  109.             return t.ListLen;  
  110.         }  
  111.         #endregion  
  112.   
  113.         #region 顺序表的添加  
  114.         ///<summary>  
  115. ///顺序表的添加  
  116. ///</summary>  
  117. ///<param name="t"></param>  
  118. ///<returns></returns>  
  119.         public bool SeqListAdd<T>(SeqListType<T> t, T data)  
  120.         {  
  121.             //防止数组溢出  
  122.             if (t.ListLen == t.MaxSize)  
  123.                 return false;  
  124.             t.ListData[t.ListLen++] = data;  
  125.             return true;  
  126.         }  
  127.         #endregion  
  128.   
  129.         #region 顺序表的插入操作  
  130.         ///<summary>  
  131. /// 顺序表的插入操作  
  132. ///</summary>  
  133. ///<param name="t"></param>  
  134. ///<param name="n"></param>  
  135. ///<param name="data"></param>  
  136. ///<returns></returns>  
  137.         public bool SeqListInsert<T>(SeqListType<T> t, int n, T data)  
  138.         {  
  139.             //首先判断n是否合法  
  140.             if (n < 0 || n > t.MaxSize - 1)  
  141.                 return false;  
  142.             //说明数组已满,不能进行插入操作  
  143.             if (t.ListLen == t.MaxSize)  
  144.                 return false;  
  145.             //需要将插入点的数组数字依次向后移动  
  146.             for (int i = t.ListLen - 1; i >= n; i--)  
  147.             {  
  148.                 t.ListData[i + 1] = t.ListData[i];  
  149.             }  
  150.   
  151.             //最后将data插入到腾出来的位置  
  152.             t.ListData[n] = data;  
  153.             t.ListLen++;  
  154.             return true;  
  155.         }  
  156.         #endregion  
  157.   
  158.         #region 顺序表的删除操作  
  159.         ///<summary>  
  160. /// 顺序表的删除操作  
  161. ///</summary>  
  162. ///<param name="t"></param>  
  163. ///<param name="n"></param>  
  164. ///<returns></returns>  
  165.         public bool SeqListDelete<T>(SeqListType<T> t, int n)  
  166.         {  
  167.             //判断删除位置是否非法  
  168.             if (n < 0 || n > t.ListLen - 1)  
  169.                 return false;  
  170.             //判断数组是否已满  
  171.             if (t.ListLen == t.MaxSize)  
  172.                 return false;  
  173.             //将n处后的元素向前移位  
  174.             for (int i = n; i < t.ListLen; i++)  
  175.                 t.ListData[i] = t.ListData[i + 1];  
  176.             //去掉数组最后一个元素  
  177.             --t.ListLen;  
  178.             return true;  
  179.         }  
  180.         #endregion  
  181.   
  182.         #region 顺序表的按序号查找  
  183.         ///<summary>  
  184. /// 顺序表的按序号查找  
  185. ///</summary>  
  186. ///<param name="t"></param>  
  187. ///<param name="n"></param>  
  188. ///<returns></returns>  
  189.         public T SeqListFindByNum<T>(SeqListType<T> t, int n)  
  190.         {  
  191.             if (n < 0 || n > t.ListLen - 1)  
  192.                 return default(T);  
  193.             return t.ListData[n];  
  194.         }  
  195.         #endregion  
  196.   
  197.         #region  顺序表的关键字查找  
  198.         ///<summary>  
  199. /// 顺序表的关键字查找  
  200. ///</summary>  
  201. ///<typeparam name="T"></typeparam>  
  202. ///<typeparam name="W"></typeparam>  
  203. ///<param name="t"></param>  
  204. ///<param name="key"></param>  
  205. ///<param name="where"></param>  
  206. ///<returns></returns>  
  207.         public T SeqListFindByKey<T, W>(SeqListType<T> t, string key, Func<T, W> where) where W : IComparable  
  208.         {  
  209.   
  210.             for (int i = 0; i < t.ListLen; i++)  
  211.             {  
  212.                 if (where(t.ListData[i]).CompareTo(key) == 0)  
  213.                 {  
  214.                     return t.ListData[i];  
  215.                 }  
  216.             }  
  217.             return default(T);  
  218.         }  
  219.         #endregion  
  220.     }  
  221.     #endregion  
  222. }  


运行结果:




通过实验,大家也知道,如果我每次向

顺序表的头部插入元素,都会引起痉挛,效率比较低下,第二点我们用顺序存储时,容

易受到长度的限制,反之就会造成空间资源的浪费。

 

二:链表

      对于顺序表存在的若干问题,链表都给出了相应的解决方案。

1. 概念:其实链表的“每个节点”都包含一个”数据域“和”指针域“。

            ”数据域“中包含当前的数据。

            ”指针域“中包含下一个节点的指针。

            ”头指针”也就是head,指向头结点数据。

            “末节点“作为单向链表,因为是最后一个节点,通常设置指针域为null。

代码段如下:


 1     #region 链表节点的数据结构 2 /// <summary> 3 /// 链表节点的数据结构 4 /// </summary> 5     public class Node<T> 6     { 7/// <summary> 8 /// 节点的数据域 9 /// </summary>10         public T data;11 12 /// <summary>13 /// 节点的指针域14 /// </summary>15         public Node<T> next;16     }17     #endregion

2.常用操作:

    链表的常用操作一般有:

           ①添加节点到链接尾,②添加节点到链表头,③插入节点。

           ④删除节点,⑤按关键字查找节点,⑥取链表长度。

   

<1> 添加节点到链接尾:

          前面已经说过,链表是采用指针来指向下一个元素,所以说要想找到链表最后一个节点,

       必须从头指针开始一步一步向后找,少不了一个for循环,所以时间复杂度为O(N)。

 

代码段如下:


 1 #region 将节点添加到链表的末尾 2         /// <summary> 3 /// 将节点添加到链表的末尾 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 /// <param name="head"></param> 7 /// <param name="data"></param> 8 /// <returns></returns> 9         public Node<T> ChainListAddEnd<T>(Node<T> head, T data)10         {11             Node<T> node = new Node<T>();12 13             node.data = data;14             node.next = null;15 16             ///说明是一个空链表17             if (head == null)18             {19                 head = node;20                 return head;21             }22 23             //获取当前链表的最后一个节点24             ChainListGetLast(head).next = node;25 26             return head;27         }28 #endregion29 #region 得到当前链表的最后一个节点30         /// <summary>31 /// 得到当前链表的最后一个节点32 /// </summary>33 /// <typeparam name="T"></typeparam>34 /// <param name="head"></param>35 /// <returns></returns>36         public Node<T> ChainListGetLast<T>(Node<T> head)37         {38             if (head.next == null)39                 return head;40             return ChainListGetLast(head.next);41         }42         #endregion

 

<2> 添加节点到链表头:

          大家现在都知道,链表是采用指针指向的,要想将元素插入链表头,其实还是很简单的,

      思想就是:① 将head的next指针给新增节点的next。②将整个新增节点给head的next。

      所以可以看出,此种添加的时间复杂度为O(1)。

 

效果图:

代码段如下:


 1#region 将节点添加到链表的开头 2 /// <summary> 3 /// 将节点添加到链表的开头 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 /// <param name="chainList"></param> 7 /// <param name="data"></param> 8 /// <returns></returns> 9         public Node<T> ChainListAddFirst<T>(Node<T> head, T data)10         {11             Node<T> node = new Node<T>();12 13             node.data = data;14             node.next = head;15 16             head = node;17 18             return head;19 20         }21         #endregion


<3> 插入节点:

           其实这个思想跟插入到”首节点“是一个模式,不过多了一步就是要找到当前节点的操作。然后找到

      这个节点的花费是O(N)。上图上代码,大家一看就明白。

 

效果图:

代码段:


 1 #region 将节点插入到指定位置 2 /// <summary> 3 /// 将节点插入到指定位置 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 /// <param name="head"></param> 7 /// <param name="currentNode"></param> 8 /// <param name="data"></param> 9 /// <returns></returns>10         public Node<T> ChainListInsert<T, W>(Node<T> head, string key, Func<T, W> where, T data) where W : IComparable11         {12             if (head == null)13                 return null;14 15             if (where(head.data).CompareTo(key) == 0)16             {17                 Node<T> node = new Node<T>();18 19                 node.data = data;20 21                 node.next = head.next;22 23                 head.next = node;24             }25 26             ChainListInsert(head.next, key, where, data);27 28             return head;29         }30         #endregion

 

<4> 删除节点:

        这个也比较简单,不解释,图跟代码更具有说服力,口头表达反而让人一头雾水。

        当然时间复杂度就为O(N),N是来自于查找到要删除的节点。

 

效果图:

代码段:


 1 #region 将指定关键字的节点删除 2         /// <summary> 3 /// 将指定关键字的节点删除 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 /// <typeparam name="W"></typeparam> 7 /// <param name="head"></param> 8 /// <param name="key"></param> 9 /// <param name="where"></param>10 /// <param name="data"></param>11 /// <returns></returns>12         public Node<T> ChainListDelete<T, W>(Node<T> head, string key, Func<T, W> where) where W : IComparable13         {14             if (head == null)15                 return null;16 17             //这是针对只有一个节点的解决方案18             if (where(head.data).CompareTo(key) == 0)19             {20                 if (head.next != null)21                     head = head.next;22                 else23                     return head = null;24             }25             else26             {27                 //判断一下此节点是否是要删除的节点的前一节点28                 while (head.next != null && where(head.next.data).CompareTo(key) == 0)29                 {30                     //将删除节点的next域指向前一节点31                     head.next = head.next.next;32                 }33             }34 35             ChainListDelete(head.next, key, where);36 37             return head;38         }39         #endregion



<5> 按关键字查找节点:

         这个思想已经包含到“插入节点”和“删除节点”的具体运用中的,其时间复杂度为O(N)。

 

代码段:


 1 #region 通过关键字查找指定的节点 2         /// <summary> 3 /// 通过关键字查找指定的节点 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 /// <typeparam name="W"></typeparam> 7 /// <param name="head"></param> 8 /// <param name="key"></param> 9 /// <param name="where"></param>10 /// <returns></returns>11         public Node<T> ChainListFindByKey<T, W>(Node<T> head, string key, Func<T, W> where) where W : IComparable12         {13             if (head == null)14                 return null;15 16             if (where(head.data).CompareTo(key) == 0)17                 return head;18 19             return ChainListFindByKey<T, W>(head.next, key, where);20         }21         #endregion


<6> 取链表长度:

          在单链表的操作中,取链表长度还是比较纠结的,因为他不像顺序表那样是在内存中连续存储的,

      因此我们就纠结的遍历一下链表的总长度。时间复杂度为O(N)。

 

代码段:


 1         #region 获取链表的长度 2         /// <summary> 3 ///// 获取链表的长度 4 /// </summary> 5 /// <typeparam name="T"></typeparam> 6 /// <param name="head"></param> 7 /// <returns></returns> 8         public int ChanListLength<T>(Node<T> head) 9         {10             int count = 0;11 12             while (head != null)13             {14                 ++count;15                 head = head.next;16             }17 18             return count;19         }20         #endregion

 

 

好了,最后上一下总的运行代码:

[java] view plaincopy
  1. <pre name="code" class="java">using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5.   
  6. namespace ChainList  
  7. {  
  8.     class Program  
  9.     {  
  10.         static void Main(string[] args)  
  11.         {  
  12.             ChainList chainList = new ChainList();  
  13.   
  14.             Node<Student> node = null;  
  15.   
  16.             Console.WriteLine("将三条数据添加到链表的尾部:\n");  
  17.   
  18.             //将数据添加到链表的尾部  
  19.             node = chainList.ChainListAddEnd(node, new Student() { ID = 2, Name = "hxc520", Age = 23 });  
  20.             node = chainList.ChainListAddEnd(node, new Student() { ID = 3, Name = "博客园", Age = 33 });  
  21.             node = chainList.ChainListAddEnd(node, new Student() { ID = 5, Name = "一线码农", Age = 23 });  
  22.   
  23.             Dispaly(node);  
  24.   
  25.             Console.WriteLine("将ID=1的数据插入到链表开头:\n");  
  26.   
  27.             //将ID=1的数据插入到链表开头  
  28.             node = chainList.ChainListAddFirst(node, new Student() { ID = 1, Name = "i can fly", Age = 23 });  
  29.   
  30.             Dispaly(node);  
  31.   
  32.             Console.WriteLine("查找Name=“一线码农”的节点\n");  
  33.   
  34.             //查找Name=“一线码农”的节点  
  35.             var result = chainList.ChainListFindByKey(node, "一线码农", i => i.Name);  
  36.   
  37.             DisplaySingle(node);  
  38.   
  39.             Console.WriteLine("将”ID=4“的实体插入到“博客园”这个节点的之后\n");  
  40.   
  41.             //将”ID=4“的实体插入到"博客园"这个节点的之后  
  42.             node = chainList.ChainListInsert(node, "博客园", i => i.Name, new Student() { ID = 4, Name = "51cto", Age = 30 });  
  43.   
  44.             Dispaly(node);  
  45.   
  46.             Console.WriteLine("删除Name=‘51cto‘的节点数据\n");  
  47.   
  48.             //删除Name=‘51cto‘的节点数据  
  49.             node = chainList.ChainListDelete(node, "51cto", i => i.Name);  
  50.   
  51.             Dispaly(node);  
  52.   
  53.             Console.WriteLine("获取链表的个数:" + chainList.ChanListLength(node));  
  54.         }  
  55.   
  56.         //输出数据  
  57.         public static void Dispaly(Node<Student> head)  
  58.         {  
  59.             Console.WriteLine("******************* 链表数据如下 *******************");  
  60.             var tempNode = head;  
  61.   
  62.             while (tempNode != null)  
  63.             {  
  64.                 Console.WriteLine("ID:" + tempNode.data.ID + ", Name:" + tempNode.data.Name + ",Age:" + tempNode.data.Age);  
  65.                 tempNode = tempNode.next;  
  66.             }  
  67.   
  68.             Console.WriteLine("******************* 链表数据展示完毕 *******************\n");  
  69.         }  
  70.   
  71.         //展示当前节点数据  
  72.         public static void DisplaySingle(Node<Student> head)  
  73.         {  
  74.             if (head != null)  
  75.                 Console.WriteLine("ID:" + head.data.ID + ", Name:" + head.data.Name + ",Age:" + head.data.Age);  
  76.             else  
  77.                 Console.WriteLine("未查找到数据!");  
  78.         }  
  79.     }  
  80.   
  81.     #region 学生数据实体  
  82.     /// <summary>  
  83. /// 学生数据实体  
  84. /// </summary>  
  85.     public class Student  
  86.     {  
  87.         public int ID { get; set; }  
  88.   
  89.         public string Name { get; set; }  
  90.   
  91.         public int Age { get; set; }  
  92.     }  
  93.     #endregion  
  94.   
  95.     #region 链表节点的数据结构  
  96.     /// <summary>  
  97. /// 链表节点的数据结构  
  98. /// </summary>  
  99.     public class Node<T>  
  100.     {  
  101.         /// <summary>  
  102. /// 节点的数据域  
  103. /// </summary>  
  104.         public T data;  
  105.   
  106.         /// <summary>  
  107. /// 节点的指针域  
  108. /// </summary>  
  109.         public Node<T> next;  
  110.     }  
  111.     #endregion  
  112.   
  113.     #region 链表的相关操作  
  114.     /// <summary>  
  115. /// 链表的相关操作  
  116. /// </summary>  
  117.     public class ChainList  
  118.     {  
  119.         #region 将节点添加到链表的末尾  
  120.         /// <summary>  
  121. /// 将节点添加到链表的末尾  
  122. /// </summary>  
  123. /// <typeparam name="T"></typeparam>  
  124. /// <param name="head"></param>  
  125. /// <param name="data"></param>  
  126. /// <returns></returns>  
  127.         public Node<T> ChainListAddEnd<T>(Node<T> head, T data)  
  128.         {  
  129.             Node<T> node = new Node<T>();  
  130.   
  131.             node.data = data;  
  132.             node.next = null;  
  133.   
  134.             ///说明是一个空链表  
  135.             if (head == null)  
  136.             {  
  137.                 head = node;  
  138.                 return head;  
  139.             }  
  140.   
  141.             //获取当前链表的最后一个节点  
  142.             ChainListGetLast(head).next = node;  
  143.   
  144.             return head;  
  145.         }  
  146.         #endregion  
  147.   
  148.         #region 将节点添加到链表的开头  
  149.         /// <summary>  
  150. /// 将节点添加到链表的开头  
  151. /// </summary>  
  152. /// <typeparam name="T"></typeparam>  
  153. /// <param name="chainList"></param>  
  154. /// <param name="data"></param>  
  155. /// <returns></returns>  
  156.         public Node<T> ChainListAddFirst<T>(Node<T> head, T data)  
  157.         {  
  158.             Node<T> node = new Node<T>();  
  159.   
  160.             node.data = data;  
  161.             node.next = head;  
  162.   
  163.             head = node;  
  164.   
  165.             return head;  
  166.   
  167.         }  
  168.         #endregion  
  169.   
  170.         #region 将节点插入到指定位置  
  171.         /// <summary>  
  172. /// 将节点插入到指定位置  
  173. /// </summary>  
  174. /// <typeparam name="T"></typeparam>  
  175. /// <param name="head"></param>  
  176. /// <param name="currentNode"></param>  
  177. /// <param name="data"></param>  
  178. /// <returns></returns>  
  179.         public Node<T> ChainListInsert<T, W>(Node<T> head, string key, Func<T, W> where, T data) where W : IComparable  
  180.         {  
  181.             if (head == null)  
  182.                 return null;  
  183.   
  184.             if (where(head.data).CompareTo(key) == 0)  
  185.             {  
  186.                 Node<T> node = new Node<T>();  
  187.   
  188.                 node.data = data;  
  189.   
  190.                 node.next = head.next;  
  191.   
  192.                 head.next = node;  
  193.             }  
  194.   
  195.             ChainListInsert(head.next, key, where, data);  
  196.   
  197.             return head;  
  198.         }  
  199.         #endregion  
  200.   
  201.         #region 将指定关键字的节点删除  
  202.         /// <summary>  
  203. /// 将指定关键字的节点删除  
  204. /// </summary>  
  205. /// <typeparam name="T"></typeparam>  
  206. /// <typeparam name="W"></typeparam>  
  207. /// <param name="head"></param>  
  208. /// <param name="key"></param>  
  209. /// <param name="where"></param>  
  210. /// <param name="data"></param>  
  211. /// <returns></returns>  
  212.         public Node<T> ChainListDelete<T, W>(Node<T> head, string key, Func<T, W> where) where W : IComparable  
  213.         {  
  214.             if (head == null)  
  215.                 return null;  
  216.   
  217.             //这是针对只有一个节点的解决方案  
  218.             if (where(head.data).CompareTo(key) == 0)  
  219.             {  
  220.                 if (head.next != null)  
  221.                     head = head.next;  
  222.                 else  
  223.                     return head = null;  
  224.             }  
  225.             else  
  226.             {  
  227.                 //判断一下此节点是否是要删除的节点的前一节点  
  228.                 if (head.next != null && where(head.next.data).CompareTo(key) == 0)  
  229.                 {  
  230.                     //将删除节点的next域指向前一节点  
  231.                     head.next = head.next.next;  
  232.                 }  
  233.             }  
  234.   
  235.             ChainListDelete(head.next, key, where);  
  236.   
  237.             return head;  
  238.         }  
  239.         #endregion  
  240.   
  241.         #region 通过关键字查找指定的节点  
  242.         /// <summary>  
  243. /// 通过关键字查找指定的节点  
  244. /// </summary>  
  245. /// <typeparam name="T"></typeparam>  
  246. /// <typeparam name="W"></typeparam>  
  247. /// <param name="head"></param>  
  248. /// <param name="key"></param>  
  249. /// <param name="where"></param>  
  250. /// <returns></returns>  
  251.         public Node<T> ChainListFindByKey<T, W>(Node<T> head, string key, Func<T, W> where) where W : IComparable  
  252.         {  
  253.             if (head == null)  
  254.                 return null;  
  255.   
  256.             if (where(head.data).CompareTo(key) == 0)  
  257.                 return head;  
  258.   
  259.             return ChainListFindByKey<T, W>(head.next, key, where);  
  260.         }  
  261.         #endregion  
  262.   
  263.         #region 获取链表的长度  
  264.         /// <summary>  
  265. ///// 获取链表的长度  
  266. /// </summary>  
  267. /// <typeparam name="T"></typeparam>  
  268. /// <param name="head"></param>  
  269. /// <returns></returns>  
  270.         public int ChanListLength<T>(Node<T> head)  
  271.         {  
  272.             int count = 0;  
  273.   
  274.             while (head != null)  
  275.             {  
  276.                 ++count;  
  277.                 head = head.next;  
  278.             }  
  279.   
  280.             return count;  
  281.         }  
  282.         #endregion  
  283.   
  284.         #region 得到当前链表的最后一个节点  
  285.         /// <summary>  
  286. /// 得到当前链表的最后一个节点  
  287. /// </summary>  
  288. /// <typeparam name="T"></typeparam>  
  289. /// <param name="head"></param>  
  290. /// <returns></returns>  
  291.         public Node<T> ChainListGetLast<T>(Node<T> head)  
  292.         {  
  293.             if (head.next == null)  
  294.                 return head;  
  295.             return ChainListGetLast(head.next);  
  296.         }  
  297.         #endregion  
  298.   
  299.     }  
  300.     #endregion  
  301. }  


运行结果:

 

当然,单链表操作中有很多是O(N)的操作,这给我们带来了尴尬的局面,所以就有了很多的

优化方案,比如:双向链表,循环链表。静态链表等等,这些希望大家在懂得单链表的情况下

待深一步的研究


0 0
原创粉丝点击