数据结构之常用表结构

    最近结合博客园和自己近几年的一些积累,觉得有必要对.Net常用的一些表进行一次总结,一边为了自己后面看另一方面也希望能够对各位博友有一定的帮助,有不正确的地方希望大家帮忙纠正,非常感谢!!!

表的数组结构(针对一维数组):

    概述:数组是一个长度固定的表结构,它的元素必须存放在一个内存空间当中。

    功能说明:它提供了表的创建、清除、复制和元素的存取以及排序搜索功能(由于它长度固定所以不能对元素进行新增和删除)

    创建数组:创建数组通常采用初始化或者对下标进行赋值的方式进行创建

    清除数组:该功能主要由Array类的静态方法实现,可以将指定范围内的元素清空,重置为初始值

    复制数组:由Array类的静态方法实现的浅度复制,可以将源数组指定范围内的元素复制到目标数组中的指定位置

    元素搜索:由Array类的静态方法实现,元素可支持正向搜索、反响搜索、可以搜索元素在数组当中的位置、可以搜索指定元素、可以顺序搜索也可以二分法搜索(注意:使用二分法搜索表中的元素必须进行排序)

    元素排序:由Array类的静态方法实现,使用快速排序算法将数组元素进行重新排序,一边能够使用二分法搜索

    元素存取:由实例方法实现,使用元素在表中的位置通过下标访问符或 GetValue、SetValue 方法对表元素进行随机存取

 1        //创建数组:初始化数组(初始化的方式创建)
 2        int[] arr_int = new int[] { 1, 2, 3, 4, 5 };
 3        //数组输出结果:{1,2,3,4,5}
 4 
 5        //创建数组:通过赋值下标的方式创建数组
 6        int[] array_int = new int[2];
 7        array_int[0] = 1;
 8        array_int[1] = 1;
 9        //数组输出结果:{1,2}
10        //清除数组:
12        Array.Clear(arr_int, 0, 1);
13        //数组输出结果:{0,2,3,4,5}
14 
15        //复制数组:
16        //var copyArr_int = new int[] { };//如果是复制到没有固定长度的数组会直接报错
17        var copyArr_int = new int[5];
18        Array.Copy(arr_int, copyArr_int, arr_int.Length);
19        //数组输出结果:{0,2,3,4,5}
20 
21        //数组搜索:
22        var number = Array.Find(arr_int, e => e == 3);//搜索指定的元素
23        var index = Array.IndexOf(arr_int, 2);//正向搜索
24        var lastvalue = Array.LastIndexOf(arr_int, 3);//反向搜索
25        var index1 = Array.FindIndex(arr_int, e => e == 2);//搜索元素在数组当中的位置
26 
27        Array.Sort(arr_int);
28        var binIndex = Array.BinarySearch(arr_int, 0);//二分法搜索表中的元素
29 
30        //数组排序:
31        Array.Sort(arr_int); 

   应用场景:当我们操作的数据满足如下的几个条件,那么我们则可以使用该数据结构

   1、元素数量固定(数组长度固定)

   2、无需动态添加或者删除元素

   3、可以通过元素在表中的位置尽心随机存取

   性能说明: 

   元素存取:由于我们只能通过下标或者GetValue、SetValue来存取数组元素,所以该方法的存取难度为0(1),注意:由于GetValue 和 SetValue 方法来进行随机存取时,有可能出现装箱的额外操作,所以首先推荐使用通过下标的方式进行存取数据

   元素排序:使用快速排序法进行排序,该操作的时间复杂度为 O(N * log N)

   元素搜索:元素的搜索分为两种情况:顺序搜索和二分搜索。如果使用顺序搜索则该操作的时间复杂度为 O(N);如果使用二分搜索则该操作的时间复杂度为 O(log N)

   

表的数组结构(针对ArrayList数组):

   概述:ArrayListshi是通过维护一个object对象类型的_items的数组来存放所有元素

   功能说明:它提供了表的创建、清除、复制,表元素的存取、搜索、新增、删除和排序功能

   表的创建:实例化 _items,并可以将传入的元素集合拷贝(浅度拷贝)到 _items 中

   表的清除(Clear):清除 _items 中的数据,通过调用 Array.Clear 方法来实现的

   表的复制(CopyTo):将表中指定范围内的元素复制到目标表中指定的位置,通过调用 Array.Copy 方法来实现的

   元素的存取(this[]):只能使用元素在表中的位置通过索引器来对元素进行随机存取

   元素的新增:可以将一个新元素添加到表的最后(Add),也可以将其插入到指定的位置(Insert);可以将一组新元素添加到表的最后(AddRange),也可以将其插入到指定的位置(InsertRange)

   元素的删除:可以从表中删除指定的元素(Remove),也可以将表中指定位置的元素删除(RemoveAt),还可以将表中指定范围内的元素删除(RemoveRange)

   元素的排序(Sort):将表中的元素进行快速排序,以便能够使用二分法进行元素的搜索

   元素的搜索:可以进行顺序搜索(IndexOf 和 LastIndexOf,通过调用Array.IndexOf和Array.LastIndexOf方法实现);也可以使用二分法进行搜索(BinarySearch,调用Array.BinarySearch 方法实现)

   性能说明

   元素的存取:虽然对于外部来说是使用索引器来对元素进行随机存取,其实其内部就是使用数组的下标对_items 的元素进行存取,所以该操作的时间复杂度为O(1)

   元素的新增:虽然对于外部来说它提供了元素的新增功能,但是对于其内部来说只是指定数组元素的赋值,

                         如果在表的尾部添加元素(Add),则只是简单的为指定的数组元素赋值,所以该操作的时间复杂度为O(1);如果在表的中间插入元素(Insert),则需要将数组中指定位置之后的元素都向后移动,然后为指定位置的数组元素赋以新值,则该操作的时间复杂度为O(N)

                         只要存在元素的新增,这里就会存在一个扩容的问题。ArrayList内部是通过创建容量更大的新的数组,将所有已有元素拷贝到新数组中指定的位置,然后再将新增的元素存入数组

   元素的删除:当表中指定的元素被删除时,需要将 _items 中被删除元素之后的元素都向前移动,即 _items 中的所有元素必须集中在数组的前部,中间不能出现空元素,所以该操作的时间复杂度为 O(N)

   元素的排序:使用快速排序法对表中的元素进行重新排序,该操作的时间复杂度为 O(N * log N)

   元素的搜索:如果使用顺序搜索则该操作的时间复杂度 O(N);如果表元素已经进行过排序,使用二分法搜索则该操作的时间复杂度为 O(log N)

 

   应用场景:当我们要操作的数据满足下面条件时就比较适合使用ArrayList:

   1、  能够通过元素在表中的位置进行随机存取;

   2、  能够动态新增和删除元素;

   3、  不能保证各个元素的数据类型能够兼容;

   4、  能够对元素进行排序;

 

表的泛型集合List<T>  

   概述

          它实现了一个可以动态添加、删除元素的强类型表结构,内部维护一个强类型T的数组 _items 来存放所有的元素,所以它只提供通过元素的位置来存取元素的方式。

   它所提供的功能和内部实现与ArrayList 一样,唯一的区别是:ArrayList 相对来说是弱类型的,没有类型安全保障;而List<T> 相对来说是强类型的,有类型安全保障。

   ArrayList:它操作的是一个 object 数组,所以加入它的数据都必须先转换为object 类型,这对于值类型来说就需要进行装箱操作,这也意味着ArrayList中可能存放着各种类型的数据,而且这些数据不一定兼容。

   List<T>:它操作的是一个指定类型T的数组,这不仅避免了值类型的装箱操作,也提供了类型安全,所有加入它的数据都必须与T类型兼容。

   功能说明:参照 ArrayList 的功能说明。

   性能说明:参照ArrayList 的性能说明。

   应用场景:List<T> 和 ArrayList 的适用场景也只有一个区别——能不能保证各个元素数据类型的兼容性:能够保证就使用List<T>,不能保证就使用ArrayList

 

表的链表结构

   概述:LinkedList<T> 提供了一个以双向链表方式实现的表结构,内部维护了一组 LinkedListNode<T> 类型的节点,每个节点都保存了自己所属的 LinkedList<T>(list)、前一个节点(prev)、后一个节点(next)和储存在该节点的元素(item)。在链表形式的表中存在节点和元素两个概念,它们虽有关联但不尽相同。元素是表结构需要存储的真正数据,但是它不包含任何能够访问其它元素的信息,这样不可能实现链表形式的表;而节点不仅存储了表结构需要储存的真正数据,还储存了访问其它节点的信息。由上可以看出:元素是表结构需要存储的真正数据;而节点是这些元素的载体,是组成链表的基本单位。

             由于链表的组成单位是节点,所以对表元素的存取都必须通过储存元素的节点间接存取,不能直接存取。又因为每个节点都记录了前一个节点和后一个节点的内存地址,所以这些节点不需要存放在连续的内存空间中。

   功能说明:它提供了表的创建、清除、复制,表元素的存取、新增、删除和搜索。

   表的创建:表的实例化,并可以根据传入的元素创建相应的节点,加入新建的表中。

   表的清除:清除表中所有的节点。

   表的复制:将表中所有节点中储存的元素复制(浅度复制)到指定数组的指定位置。

   元素的存取:必须要先通过元素的搜索获取储存该元素的节点,然后再通过该节点对元素进行存取。但是对于链表的第一个元素或最后一个元素的存取不用那么繁琐,只需要通过First 或 Last 这两个属性直接获取储存它们的第一个节点或最后一个节点。

   元素的新增:新增一个元素其实就是新增一个节点,所以新增元素时可以传入要新增的元素,也可以传入包含该新增元素的节点,但是同一个节点不能加入到不同的链表中。可以将元素添加到表头(AddFirst),也可以将元素添加到表尾(AddLast),还可以将元素插入到指定元素之前(AddBefore)或之后(AddAfter)。

   元素的删除:删除一个元素其实就是删除一个节点,所以删除元素时可以传入要删除的元素,也可以传入要删除的节点(这个节点必须属于该表)。当传入的是要删除的元素时,会先根据该元素搜索到储存该元素的节点,然后将该节点删除。除了可以删除指定的元素外,还可以删除特殊的元素:第一个元素(RemoveFirst)或最后一个元素(RemoveLast)。

元素的搜索:根据指定的元素从表中搜索储存该元素的节点。可以正向搜索(Find),也可以逆向搜索(FindLast)。

    性能说明

   元素的搜索:链表中的节点只能逐一的顺序访问,所以该操作的时间复杂度为 O(N)。

   元素的存取:链表的组成结构决定了它不能支持随机存取(即:不能通过元素位置来对元素进行直接存取),所以 LinkedList<T> 并不提供随机存取的方式。

                         因为可以通过 First 或 Last 属性直接获取链表的第一个节点或最后一个节点,所以链表中第一个元素或最后一个元素的存取操作的时间复杂度为 O(1)。

                         其它的元素都必须先搜索到储存该元素的节点,然后再通过搜索到的节点对元素进行存取,所以该操作的时间复杂度为O(N)。

   元素的新增:链表中新增元素的操作比较简单,只需要修改前一节点的next、后一节点的prev 和储存该元素的节点的 prev与next的值。该操作的时间复杂度为 O(1)。

   元素的删除:链表中删除元素的操作比较简单,只需要修改前一个节点的next、后一个节点的prev并将删除节点的next、prev和list都重置。该操作的时间复杂度为 O(1)。 

   应用场景:当我们要操作的数据满足下面条件时就比较适合使用LinkedList<T>:

   1、  会频繁的进行元素的新增和删除;

   2、  通常只会顺序的访问表中的所有元素,很少需要对元素进行随机存取;

   3、  不需要对表中的元素进行排序。

   应用实例:如果想要运行该实力,可以去掉redis缓存

  1 using HB.Cache;
  2 using System;
  3 using System.Collections.Generic;
  4 using System.Linq;
  5 using System.Runtime.Serialization;
  6 
  7 namespace HB.Test
  8 {
  9     /// <summary>
 10     /// 
 11     /// </summary>
 12     class Program
 13     {
 14         /// <summary>
 15         /// 
 16         /// </summary>
 17         /// <param name="args"></param>
 18         static void Main(string[] args)
 19         {
 20             try
 21             {
 22                 //获取链表
 23                 var documentLinkeList = GetDocumentLinkeList();
 24 
 25                 //获取链表第一项
 26                 var first = documentLinkeList.First;
 27 
 28                 //获取链表最后一项
 29                 var last = documentLinkeList.Last;
 30 
 31                 //根据查询条件获取链表指定项
 32                 var document = documentLinkeList.FirstOrDefault(e => e.Sequence == 1);
 33                 var documentNote = documentLinkeList.Find(document);
 34 
 35                 //阻塞线程
 36                 Console.ReadKey();
 37             }
 38             catch (Exception ex)
 39             {
 40                 Log4netHelper.Debug<Program>("异常:", ex);
 41             }
 42         }
 43 
 44         /// <summary>
 45         /// 获取文档双向链表
 46         /// 备注:有加redis缓存
 47         /// </summary>
 48         /// <returns></returns>
 49         private static LinkedList<Document> GetDocumentLinkeList()
 50         {
 51             var key = "DocumentLinkeList:Test";
 52             LinkedList<Document> documentLinkeList = null;
 53             ExchangeRedisHelper cache = new ExchangeRedisHelper();
 54             if (cache.ContainsKey(key))
 55             {
 56                 documentLinkeList = cache.GetFromBinary<LinkedList<Document>>(key);
 57             }
 58             else
 59             {
 60                 List<Document> documentList = new List<Document>();
 61                 documentList.Add(new Document() { Title = "one", Content = "Sample_one", Priority = 8, Sequence = 1 });
 62                 documentList.Add(new Document() { Title = "two", Content = "Sample_two", Priority = 8, Sequence = 2 });
 63                 documentList.Add(new Document() { Title = "three", Content = "Sample_three", Priority = 8, Sequence = 3 });
 64                 documentList.Add(new Document() { Title = "four", Content = "Sample_four", Priority = 8, Sequence = 4 });
 65                 documentList.Add(new Document() { Title = "five", Content = "Sample_five", Priority = 8, Sequence = 5 });
 66                 documentList.Add(new Document() { Title = "six", Content = "Sample_six", Priority = 8, Sequence = 6 });
 67                 documentList.Add(new Document() { Title = "seven", Content = "Sample_seven", Priority = 8, Sequence = 7 });
 68                 documentList.Add(new Document() { Title = "eight", Content = "Sample_eight", Priority = 8, Sequence = 8 });
 69                 documentList.Add(new Document() { Title = "nine", Content = "Sample_nine", Priority = 8, Sequence = 9 });
 70                 documentList.Add(new Document() { Title = "ten", Content = "Sample_ten", Priority = 8, Sequence = 10 });
 71 
 72                 documentLinkeList = new LinkedList<Document>(documentList);
 73                 var expireSeconds = (int)DateTime.Now.AddDays(1).Subtract(DateTime.Now).TotalSeconds;
 74                 cache.SetToBinary(key, documentLinkeList, expireSeconds);
 75             }
 76 
 77             return documentLinkeList;
 78         }
 79     }
 80 
 81     /// <summary>
 82     /// 存储在链表中的元素是Document类型
 83     /// </summary>
 84     [Serializable]
 85     [DataContract]
 86     public class Document
 87     {
 88         /// <summary>
 89         /// 文档标题
 90         /// </summary>
 91         [DataMember(Order = 1)]
 92         public string Title { get; set; }
 93 
 94         /// <summary>
 95         /// 文档内容
 96         /// </summary>
 97         [DataMember(Order = 2)]
 98         public string Content { get; set; }
 99 
100         /// <summary>
101         /// 文档优先级
102         /// </summary>
103         [DataMember(Order = 3)]
104         public byte Priority { get; set; }
105 
106         /// <summary>
107         /// 排序字段
108         /// </summary>
109         [DataMember(Order = 4)]
110         public int Sequence { get; set; }
111     }
112 }

 

posted @ 2017-11-13 11:21 ζ๓蜗牛 阅读(...) 评论(...) 编辑 收藏