数据结构笔记整理和思考--动态数组和静态数组的领悟

最近在复习数据结构,但再次重温线性结构中的连续存储章节时,通过使用C语言来模拟Java中的ArrayList的各个方法,感觉对Java中的ArrayList的体会有深刻了。遂想趁此机会将数组的知识点整理一下。

首先要了解:数组分为静态数组和动态数组(后者是前者的升级版,其实就是将静态数组通过一个类来再封装一次而已,没什么神秘的)。

一.静态数组

静态数组又有默认创建,静态创建和动态创建,共三种创建方式;

A.     默认创建:所有的元素的初始值都是0

                     int[] i=new int[5];

B.     静态创建:创建数组时(开辟每个元素的内存空间时)就赋自定义值了

          int[] I = {1,2,3};

C.     动态创建:在默认创建的基础上,后面根据实际情况再针对每个元素赋值

             int[] i=new int[5];

             i[0]=4; i[1]=3;……..

二.动态数组(ArrayList)

                  里面封装了一个Object数组。

                  相对于静态数组的优点:

1.      可以动态的添加和删除元素;add(obj) remove(obj);

2.      可以动态的改变数组的容量;

                                   构造器三个:

                                  A.     默认的构造器,将会以默认(16)的大小来初始化内部的数组
                                                    public ArrayList();

                                  B.     用一个ICollection对象来构造,并将该集合的元素添加到ArrayList
                                                    public ArrayList(ICollection);
                                  C.     用指定的大小来初始化内部的数组  
                                                    public ArrayList(int);

                                           !!!

                                                    Note:

                                                    初始化ArrayList时指定的大小是指容量,而不是其有效元素的个数,

                                                    而其size()方法返回的是其有效元素的个数。

                                          !!!

                                           重要的两个属性:CountCapacity

                                           Count :是只读属性,指有效元素的个数:size()方法返回的就是它!!

                                           Capacity : 可以设置,但是一定要>= Count

                                   两个重要却少用的方法:

                               trimToSize():当我们可以确定动态数组不会再add入元素时,应该在适当时机调用此方法将数组中的Capacity减少到等于Count,就是说:释放掉(Capacity-Count)           个元素的空间。这是优化方面的细节!!

                               toArray() : 可以转化为Object[]  是把ArrayList的元素Copy到一个新的数组中。

 

三.使用注意点(效率方面)

1.      自动拆装箱:

我们知道ArrayList中其实是封装了一个Object[] , 所以存在着:当我们将值类型的数据add进去时,会出现自动拆装箱的操作,这会在编译阶段拖低点效率了。可是对于对象引用类型就不会了。(其实都不差什么。)

2.      数组扩容:

这是一定注意的!!!!

程序不断地add入元素,当Count = Capacity 时,ArrayList对象会自动创建一个2*CapacityObject[]空间(就是new Object[2*Capacity]),然后将原来的数组元素copy到新的Objec数组中,再丢弃原来的Object数组。

是不是很费时间?是不是很极大的拖低了效率?!!!

因此,我们在编码阶段,就应该有个大概的估算,尽量在创建动态数组时定义好合适的初始大小。

在网上有两个很好的案例:

(1)     ArrayList  list = new ArrayList();//默认16个元素空间

for( int i =0 ; i<200 ; i++ ){

    list.add(new String(“**”));    

}

剖析:程序执行完了后,list的属性Capacity == 16*2*2*2*2 ;就是说数组扩容了4次!!这不止,最后还多了56=16*2*2*2*2 – 200)个空闲元素空间浪费!!

(2)     预计有30个元素而创建了一个ArrayList

ArrayList List = new ArrayList(30);

在执行过程中,加入了31个元素,那么数组会扩充到60个元素的大小,而这时候不会有新的元素再增加进来,而且有没有调用TrimSize方法,那么就有1次扩容的操作,并且浪费了29个元素大小的空间。如果这时候,用:

ArrayList List = new ArrayList(40);

那么一切都解决了。

所以说,正确的预估可能的元素,并且在适当的时候调用TrimSize方法是提高ArrayList使用效率的重要途径。

3.      频繁的调用IndexOfContains等方法(SortBinarySearch等方法经过优化,不在此列)引起的效率损失!!!

首先,我们要明确一点,ArrayList是动态数组,它不包括通过Key或者Value快速访问的算法,所以实际上调用IndexOfContains等方法是执行的简单的循环来查找元素,所以频繁的调用此类方法并不比你自己写循环并且稍作优化来的快,如果有这方面的要求,建议使用Hashtable或SortedList等键值对的集合。

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/29900383/viewspace-1460774/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/29900383/viewspace-1460774/

你可能感兴趣的:(数据结构笔记整理和思考--动态数组和静态数组的领悟)