一:概述

什么是数组呢?

数组对应的英文名为array,是有限个相同类型所组成的集合,数组中的每一个变量被称为元素。
数组是最为简单、最为常用的数据结构。

举例说明:

元素     3 1 2 5 4 9 7 2
索引     0 1 2 3 4 5 6 7
正如军队里的士兵存在编号一样,数组中的每一个
元素也有着自己的小标,这个小标从0开始,一致到数组长度-1。
数组的另一个特点,是在内存中的顺序存储,因此可以很好地实现
逻辑上的顺序表。
数组在内存中的顺序存储:内存是一个个连续的内存单元组成的,每一个内存单元都有自己的地址。
在这些内存单元中,有些被其他数据占用了,有些是空闲的。
数组红的每一个元素,都存储在小小的内存单元中,并且元素之间紧密排列
既不能打乱元素的存储顺序,也不能跳过某个存储单元进行存储。
不同类型的数组它所占的字节数也不同,

二:数组的基本操作

<1>读取元素

 对于数组来说,读取元素是最简单的操作。由于数组在内存中的顺序存储,所以只要 输出一个数组的下标,就可以读取对应数组的元素。 假设有一个名称为array的数组,我们要读取的数组为3的下标元素。,就写作array[3],读取数组下标为 5的元素,就写作array[5],需要注意的是,输入的小标必须是在数组的长度范围之内,否则会出现数组越界。 这种根据下标读取元素的方式叫做随机读取。

案例:

//1. 创建数组
int[] array = new int[]{3, 1, 2, 5, 4, 9, 7, 2};
 //2. 数组元素的读取 ,读取下标为6的元素
 System.out.println(array[6]);
//     System.out.println(array[8]);
//     当下标超出数组的长度之外,运行编译代码时就会报错
//      Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 8 out of bounds for length 8
//      at com.algorithm1.test3.main(test3.java:35)

<2>更新元素

要把数组中的某一个元素的值替换为新的一个值,直接利用下标,就可以把新的值赋值给该元素

案例:

  //3. 将数组下标为3的元素修改为34
        // 输出原数组中下标为3的元素
        System.out.println(array[3]);
        array[3] = 34;
        // 输出修改后数组中下标3的元素
        System.out.println(array[3]);

<3>插入元素

 3. 插入元素

    数组的实际元素数量可能小于数组的长度,

 例如:

元素             3 1 2 5 4 9  null   null

下标/索引     0 1 2 3 4 5  6     7

根据上面可知插入数组元素的操作存在3种情况:

(1)尾部插入

(2)中间插入

(3) 超范围插入

尾部插入,最简单的情况,直接把插入的元素放在数组的尾部空闲位置,等同于更新元素操作

中间插入:稍微复杂一些。由于数组中的每一个元素都有固定的下标,所以不得不不首先把插入位置

及后面的元素向后移动,腾出地方,再把要插入的元素放到对应数组位置上。

案例:(未考虑超范围插入,不包括删除)

// 先封装一个MyArray1数组类
// 中间插入元素实现代码
    public  int[] array;
    public  int size;
    public MyArray1(int capacity){
        this.array = new int[capacity];
        size = 0;

    }
    /*
     * 数组插入元素
     * @param index 插入的位置
     * @param element 插入元素
     *
     * **/

    public void insert(int index, int element) throws Exception {

        // 判断访问下标是否超出范围
        if(index < 0 || index > size) {
            throw new IndexOutOfBoundsException("超出数组实际元素范围!");
        }
        // 从有向左循环,将元素逐个向右挪1位
        for(int i = size - 1; i >= index; i--) {
            array[i + 1] = array[i];
        }

        // 腾出的位置放入元素
        array[index] = element;
        size++;

    }

    /**
     * 输出数组
     */

    public void output(){
        for(int i = 0; i < size; i++){
            System.out.println(array[i]);
        }

    }

public static void main(String[] args) throws Exception {

 // 插入元素
    // 1. 创建对象
        MyArray1 myarray = new MyArray1(10);
        myarray.insert(0,3);
        myarray.insert(1,7);
        myarray.insert(2,9);
        myarray.insert(3,5);
        myarray.insert(3,11);
        myarray.output();
}
/*
*  代码中的成员变量size是数组的实际元素数量。如果插入元素在数组尾部,传入的下标参数
* index等于size;如果插入元素在数组中间或者头部,则index小于size
* 如果传入的下标参数index大于size或小于0则会直接抛出异常
*
* 当数组不断插入新的元素,元素数量超过了数组的最大长度,数组要撑爆
*
* 超范围插入:
* 假如现在有一个长度为6的数组,已经装满了元素,这时还想插入一个新的元素
* 元素  3  1  6   2  5  4
* 索引  0  1  2   3  4  5
*
* 此时就涉及到数组扩容了。可是数组长度在创建时,就已经确定了,无法随意变换长短。
* 此时创建一个新数组,长度是旧数组的2倍,再把旧数组中的元素统统复制
* 过去,这样就实现了数组扩容
*
* */

案例:(考虑超范围插入,包含删除)

/*
* 当超范围插入时,需要对数组进行扩容
*
*
* */


private int[] array;
private int size;

public MyArray2(int capacity) {
    this.array = new int[capacity];
    size = 0;
}

/*
*
* 数组插入元素
* @ param index     插入的位置
* # param element   插入的元素
*
* **/


public void insert(int index, int element) throws Exception{
    // 判断访问下标是否超出范围
    if(index < 0 || index >= size) {
        throw new IndexOutOfBoundsException("超出数组实际元素范围");
    }
    // 如果实际元素达到数组容量上限,则对数组进行扩容
    if(size >= array.length) {
        resize();
    }
    // 从右向左循环,将元素逐个向右挪1位
    for(int i = size - 1; i >= index ; i--) {
        array[i + 1] = array[i];
    }
    // 腾出的位置放入新的元素
    array[index] = element;
    size++;
}

/*
*
* 数组扩容
*
* */
public void resize () {
    int[] arrayNew = new int[array.length * 2];
    // 从旧数组复制到新数组
    System.arraycopy(array,0, arrayNew, 0, array.length );
    array = arrayNew;
}


/**
 * 输出数组
 *
 */

public void output() {
    for(int i = 0; i < size; i++) {
        System.out.println(array[i]);
    }

}


/*
 * 数组删除元素
 * 数组的删除操作和插入操作过程相反,如果删除元素位于数组中间,
 * 其后的元素都需要向前挪动一位
 *
 * @param index 删除的位置
 *
 *
 * */

    public int delete(int index) throws Exception {
        // 判断访问下标元素是否超出范围
        if(index < 0 || index >= size) {
            throw new IndexOutOfBoundsException("超出数组实际元素范围!");
        }
        int deletedElement = array[index];
        // 从左向右循环,将元素逐个向左挪一位
        for(int i = index; i < size - 1; i++) {
            array[i] = array[i+ 1];
        }
        size--;
        return deletedElement;
    }


public static void main(String[] args) throws Exception {
    MyArray2 myArray = new MyArray2(8);
    myArray.insert(0,5);
    myArray.insert(1,7);
    myArray.insert(2,9);
    myArray.insert(3,5);
    myArray.insert(1,6);
    myArray.output();
    myArray.delete(3);
}


/*插入操作,数组扩容的时间复杂度为O(n),插入元素并移动元素的时间复杂度也是O(n)。
* 综合起来插入操作的时间复杂度是O(n)。至于删除操作,只涉及元素的移动,时间复杂度也是O(n)
* */

    /*
    * 数组拥有非常高效的随机访问能力,只要给出下标,就可以用常量时间找到
    * 对应的元素。有一种高效的查找元素的算法叫作二分查找,就是利用数组的这个优势
    *
    * 至于数组的劣势,体现在插入元素和删除元素是方面,由于数组元素连续紧密的
    * 存储在内存中,插入、删除元素都会导致大量元素被移动,影响效率
    *
    * 总的来说,数组适合读操作多,写操作少的场景。
    *
    * */

}