数据结构---->数组

 

1.什么是数组?

           数组是一种线性的数据结构.它同一组连续的内存空间,来存储一组具备相同类型的数据。数组

简单说明几点:数据结构

          (1).线性表:就是数据排成像一条线同样的结构。每一个线性表的数据最多只有前和后两个方向。除了数组,链表,队列,栈等也是线性表结构。spa

              

                对立的是非线性表,好比二叉树,堆,图等之因此被称为非线性,是由于,在非线性表中,数据之间并不简单的先后关系。code

             

         (2).数组是连续的内存空间和相同的数据类型。正是由于这样数据的随机访问的速度很快,有利就有弊,好比在数组中删除和插入一个数据,为了保证连续性,就须要大量的数据搬用   的工做。blog

 

2.说到数据的访问,那你知道数组是如何实现根据下标随机访问数组元素的吗?

      咱们拿一个长度为 10 的 int 类型的数组 int[] a = new int[10] 来举例。在我画的这个图 中,计算机给数组 a[10],分配了一块连续内存空间 1000~1039,其中,内存块的首地址 为 base_address = 1000。索引

      咱们知道,计算机会给每一个内存单元分配一个地址,计算机经过地址来访问内存中的数据。 当计算机须要随机访问数组中的某个元素时,它会首先经过啊a[i]_address=base-address+i * data_type_size 的寻址公式,计算出该元素 存储的内存地址.队列

其中 data_type_size 表示数组中每一个元素的大小。咱们举的这个例子里,数组中存储的是 int 类型数据,因此 data_type_size 就为 4 个字节。这个公式很是简单,我就很少作解释 了。内存

 ,数组支持随机访问,根据下标随机访问的时间复杂度为 O(1)ci

3.数组为了保持内存数据的连续性,会致使插入,删除这两个操做的效率比较低,那为何会致使低效,有什么改进的方法?

      假设数组长度是n ,如今须要将一个数据插入到数组的第K个位置,为了吧k位置挪出来,给新来的数据,咱们须要吧k—n 这部分的元素顺序日后移动一位,那么时间的复杂度是多少呢?element

下面咱们来分析一下:

     若是在数组的末尾插入元素,那就不须要移动元素了,那么时间的复杂度为O(1),若是在数组的开头插入元素,那么全部的数据须要一次向后移动一位,因此最坏的时间复杂度是O(N),由于咱们在每一个位置插入元素的几率是同样的,因此平均时间复杂度(1+2+。。。。+n)/n=O(n)

     若是数组中的数据是有序的,咱们在某一个位置插入一个新元素时,就必须搬移k以后的数据。可是数组中的数据是无序的,没有规律,数据只是存储数据的集合。在这种状况下,若是要将元素插入到K位置,为了不大规模的数据移动,之间将K位置的数据搬移到数组元素的最后,把新的元素之间放到第K个位置。删除的操做,为了内存的连续性,也须要移动数据,和插入相似,若是删除数组末尾的数据,则最好状况时间复杂度为 O(1);若是删除开头的 数据,则最坏状况时间复杂度为 O(n);平均状况时间复杂度也为 O(n)。

    实际上,在某些特殊场景下,咱们并不必定非得追求数组中数据的连续性。若是咱们将屡次 删除操做集中在一块儿执行,删除的效率是否是会提升不少呢?

    咱们继续来看例子。数组 a[10] 中存储了 8 个元素:a,b,c,d,e,f,g,h。如今,我 们要依次删除 a,b,c 三个元素,为了不 d,e,f,g,h 这几个数据会被搬移三次,咱们能够先记录下已经删除的数据。 每次的删除操做并非真正地搬移数据,只是记录数据已经被删除。当数组没有更多空间存 储数据时,咱们再触发执行一次真正的删除操做,这样就大大减小了删除操做致使的数据搬移。

 

4.容器可否彻底替换数组?

(1).在Java中提供的容器类,ArrayList最大的优势就是能够将不少数组操做的细节封装起来,便于调用,另外一个优势是支持动态扩容。

(2).数组自己在定义的时候预先指定了大小,由于须要分配连续的内存空间,若是咱们分配了大小为10的数组,当第11个元素须要存储到数组当中时,咱们须要从新分配一块更大的空间,将原来的数据复制过去,而后将新的数据插入。

(3).使用ArrayList,咱们彻底不须要关心底层的扩容逻辑,ArrayList 已经帮咱们实现好了,存储空间不够的时候,会将空间自动扩容1.5倍的大小。

(4).ArrayList没法存储基本的数据类型,(8种基本数据类型),而是引用类型,因此基本数据类型,能够选用数组.

5.代码实现数组的增长删除查询的操做?

public class ArrayTest {

    private Object[] elementData; //定义一个空的数组

    private int size; //数组的大小

    //初始话数组的大小
    public ArrayTest() {
        elementData = new Object[10];
    }

    /**
     * 增长元素
     */
    public boolean add(Object obj) {
        ensureCapacityInternal(size + 1); 
        elementData[size++] = obj;
        return true;

    }
    //主要的判断数组是否须要扩容
    private void ensureCapacityInternal(int minCapaCity) {

        if (minCapaCity - elementData.length > 0) {
            grow(minCapaCity);
        }
    }
    //数组扩容的操做
    private void grow(int minCapaCity) {
        int oldcapaCity = elementData.length;
        int newCapaCity = oldcapaCity + oldcapaCity >> 1;
        if (newCapaCity - minCapaCity < 0) {
            newCapaCity = minCapaCity;
        }
        if (newCapaCity - Integer.MAX_VALUE > 0) {
            newCapaCity = Integer.MAX_VALUE;
        }
        elementData = Arrays.copyOf(elementData, newCapaCity);
    }

    /**
     * 删除数组中的元素,经过索引
     */
    public Object remove(int index) {
        rangCheck(index);
        Object oldValue = elementData[index];
        int moveNum = size - index - 1; //数组移动的次数
        if (moveNum > 0) {
            System.arraycopy(elementData, index + 1, elementData, index, moveNum);
        }
        elementData[--size] = null;
        return oldValue;
    }
    //查询指定索引下数组的元素
    public Object get(int index) {
        rangCheck(index);
        return elementData[index];
    }

    private void rangCheck(int index) {
        if (index < 0 && index > size) {
            throw new IndexOutOfBoundsException("index:" + index + "size:" + size);
        }
    }


    public static void main(String[] args) {
        ArrayTest arrayTest = new ArrayTest();
        for (int i = 0; i < 10; i++) {
            arrayTest.add("第" + i + "个元素");
        }
        arrayTest.remove(3);
        for (int i = 0; i < 9; i++) {
            System.out.println(arrayTest.get(i));
        }
    }
}

 

6.总结:

数组用一块连续的内存空 间,来存储相同类型的一组数据,最大的特色就是支持随机访问,但插入、删除操做也所以 变得比较低效,平均状况时间复杂度为 O(n)。在平时的业务开发中,咱们能够直接使用编 程语言提供的容器类,可是,若是是特别底层的开发,直接使用数组可能会更合适。

 

 

相关文章
相关标签/搜索