zoukankan      html  css  js  c++  java
  • 说一下几种常见的数据类型

    数组Array:

    数组是最简单的数据结构,具有以下特点:

    数组存储在连续的内存上。

    数组的内容都是相同的类型。

    数组可以通过下标访问。

          数组的创建:

    int a=5;

    int [] array=new int[a];

    创建一个数组是在CLR托管堆中申请分配一个连续的内存空间。来存放大小为a的、所声明的数组元素。如果类型为值类型,将会有a个未装箱的该类型的值被创建。如果类型为引用类型,则将会有a个相应类型的引用被创建。

    由于是在连续内存上面存储,所以他的索引速度是非常快的。访问一个元素的时间是恒定的,也就是说与该集合元素的数量是不相关的。而且赋值与修改也是非常简单的。

    但是:

    有优点那就有缺点,由于是连续存储的,所以在俩个元素之间插入新的元素会变得异常不方便。因为声明数组是必须制定长度的,所以这就有一个潜在问题,如果我们声明的长度过长时,显然会浪费内存,当声明较短时,可能会有溢出的风险。针对这种缺点,于是就有了ArrayList这种数据结构

    ArrayList

    为了解决数组常见必须指定长度以及只能存放同一种类型的数据问题。ArrayList是System.Collections命名空间下的一部分,所以若要使用必须引入System.Collections.                                      

    ArrayList不必指定数组长度,这是由于ArrayList对象的长度是按照其中存储的数据来动态正常与缩减的。ArrayList中可以存储不同的数据类型,是因为他内部是以object类型来存储数据的。                                  

    ArrayList的操作:                                                                                                                         

     ArrayList arrayList = new ArrayList();
                    arrayList.Add("chen");
                    arrayList.Add("j");
                    arrayList.Add("d");
                    arrayList.Add("is");
                    arrayList.Add(25);//修改数据
                    arrayList[4] = 26;//删除数据
                    arrayList.RemoveAt(4);

    那么同样的,这个数据结构有“优点”那么也有缺点的。针对优点的引号,是因为这个优点并不怎么优。因为ArrayList中将数据都是以Object存储。                                                                                  

    那么就会发生类型安全的问题,因为他将所有的数据都已Object存储,那么在类型转换的时候,就可能出现类型转换失败的情况。

    如上所述,数组存储值类型的时候,并未发生装箱,但是ArrayList将所有的类型都已Object类型存储,很明显,发生了装箱操作,在根据下标获取数据的时候,又要拆箱,那么在取数上,想能是很差的。针对这种情况,在C#中肯定是不能被容忍的。就会出现后面所述的List<T>泛型。(这个稍后再说)

    为什么频繁说装箱拆箱会很耗费性能呢?所谓装箱,其实就是将值类型包装成引用类型。拆箱,就是将引用类型处理为值类型的过程。着这个过程中,假如我们的数据时值类型,这个时候会发生我们的数据存储的是有放在了托管堆上,使用的时候又放回了栈上,数据在堆栈之间切换,耗费了大量时间

    说完这个说说List<T>泛型吧                                                                                                                   

    为了解决ArrayList不安全类型和拆装箱的问题,所以出现了泛型的概念,作为一种全新引入的类型,同时也是工作中常用的类型,和ARrrayList很类似,长度都可以灵活改变。最大的不同是List在声明时需要指定对象类型。这一点有何Array很相似,其实List的内部实现是基于Array实现的。(同时,我们也可以看出ArrayList也是使用的Array实现的吧)

    泛型最大的好处是,1.确保了类型安全。2.避免了拆箱和装箱单的操作。3.他融合了Array和ArrayList的优点。

    关于List<T>的实现:

    因为其是使用了数组,所以在实例化的时候,如果我们不给数组大小,那么Lits会使用默认值来申请内存(默认值为4)。当我们在往数组中增加数据的时候,代码会去检测数组大小是否足够,如果不足,那么会重新申请一块内存空间,大小是之前大小的2倍(好像是这样的)。将之前的数据存入新的数组中,然后再将我们本次存入的数据Push进去。这就完成了数组的动态扩容。也就是ArrayList的优点。从以上描述中可以看出。假如我们所需要的空间为513,那么程序会申请出来1024大小的内存空间出来,这种情况下,内存很大一部分就会被浪费掉。

    所以建议,在我们开发过程中,如果您对您所使用的集合数量有个大致了解,就应该尽可能的设置一个初始值,以保证最大程度节省空间。

    关于LinkedList                                               

    这个也就是链表了,和数组最大的不同之处在于。链表在内存中是可以不连续的。这是由于链表是通过一个元素指向下一个元素来排列的。所以不能通过下边来访问。如图

     如上所见,链表在内存中不一定连续,那么链表相对于数组的优劣就很明显了。LinkedList是使用了双向链表来实现的。

         在链表中插入和删除数组的时候无需调整结构的容量,因为他本身不是连续存储的,而是依靠各自对象的指针所决定,所以添加和删除元素都相比数组有更大的优势。

         链表适合在需要有序排序的情况下进行增加新的元素,与数组添加元素时,需要移动在指定位置后面的所有元素相比,链表只是更改了数组对象的指针指向,而不用移动数组本身。

        有优点就有缺点,那么由于数据在内存中不连续,导致查找数据时不能以下标访问,所以需要从头部结点开始遍历链表,直到找到对应数据。所以当需要快速找到对象数据时,数组更有优势。

       由此可见:链表适合元素不固定,且频繁增删的情况

    队列    Queue<T>                                                     

        在Queue<T>这种数据结构中,最先插入的数据将会被最先删除。因此次队列也成为了先见先出(FIFO—First Input First Output)的线性表,通常使用 Enqueue和Dequeue这两个方法来实现对 Queue<T> 的存取。

         一些需要注意的地方:

              先进先出的场景

               默认情况下,Queue<T>的初始容量为32.增长因子为2.0。

              当使用进队列时,代码会判断队列长度是否足够,若不足,则会根据增长因子来增加容量,如原来为32,增加之后为64.

    栈   Stack<T>                                                             

           与队列相对,栈是先进后出的。当需要这种数据结构时,我们就使用它。

              注意之处:

    1. 后进先出的情景。
    2. 默认容量为10。
    3. 使用pop和push来操作

    字典   Dictionary<K,T>                                              

      字典相信大家都很熟悉。我们平时使用字典进行数据存取,数据缓存都是能够使用的。如果我们想要谈论字典(Dictionary<K,T>),那么我们就得说说HashTable以及Hashing(也叫散列),因为字典就是使用的哈希表的方式来实现的。

         只不过子字典是类型安全的。也就是说,当我们创建字典的时候,必须声明,Key和Value的数据类型。这是字典和哈希表的一个区别。

         关于哈希,简单的说就是讲一种任意长度的消息压缩到某一固定长度。(其使用哈希算法将数据哈希(getHashCode()这个方法大家不陌生吧!)成为一串uint“索引”,当我们一个集合中数据足够多的时候,哈希冲突的概率就会越大)。

        回到字典,那么他的劣势是什么呢?是的,就是空间。字典是以空间换取时间,通过更多的内存开销来满足我们对时间上面的追求,在创建字典的时候,我们指定了一个初始的容量值,但实际使用的空间可能不是这个数值的大小,而是使用的不小于该值的最小质数来作为他使用的实际容量。最小是3(3.1默认).当有了实际容量之后,并非直接实现,而是通过创建额外的2个数组来实现,即int[] buckets和Entryentries[]俩个数组(即buckets中保存的其实是entries数组的“索引“),这就是字典和哈希表的第二条区别。

          前面不是稍微解释了一下哈希冲突嘛。是的,第二个区别就是处理哈希冲突的策略是不同的。字典采用了额外的数据结构来处理哈希冲突。这就是刚才说的int[] buckets(哈希桶),桶的长度就是字典的实际长度,因为哈希桶就是字典每个位置的映射,然后,哈希桶中的所有的数据都是一个链表,来存储元素,然后在分配存储空间。(因此,当我想在一个字典中存入多个相同的Key的时候,我们只需重写一下getHashCode(string就算了),就可以实现这个需求(好像没什么用))

    (以上的图片其实不是很准确,因为在.Net中采用了双重哈希的方式,第一次对数据进行哈希是为了确保数据存放在哪个桶中,第二次哈希是为了确定数据存放的位置,所以存在多个桶中的数据不均衡的情况)

    因此,我们面临的情况就是,即便我们新建了一个空的字典,那么伴随而来的是2个长度为3的数组。所以当处理的数据不多时,还是慎重使用字典为好,其实很多情况下使用数组也是可以的。

    几种常见的数据结构的使用场景

    Array

     需要处理的元素的个数固定并且需要使用下标时可以考虑使用。建议使用List

    ArryList  不推荐使用(当使用object数组时也可以)
    List<T> 当数据长度不确定的时候,可以使用。
    LinkedList 链表适合元素数量不固定,且频繁增减的情况。2端都可以增减。
    Queue<T> 使用先进先出的情况
    Stack<T> 使用先进后出的情况
    Dictionary<K,V> 需要键值对存储,快速操作。
       

    参考博客:https://blog.csdn.net/qiaoquan3/article/details/51380992

  • 相关阅读:
    监听手机晃动(摇一摇)SensorEventListener
    adb logcat 命令行用法
    设计模式:观察者模式
    设计模式学习笔记-观察者模式
    Android中Parcelable序列化总结
    2048 Puzzle游戏攻略
    projecteuler----&gt;problem=14----Longest Collatz sequence
    桥模式设计模式进入Bridge
    SessionA和pplication网上聊天室的网络范例
    [ACM] hdu 5045 Contest (减少国家Dp)
  • 原文地址:https://www.cnblogs.com/zhangrgLearning/p/13254187.html
Copyright © 2011-2022 走看看