数组的实现原理(Java版)

 

目录

一.数组是什么?

内存分配:

特点:

数组的实现原理:

时间复杂度:

二.Java数组的实现:

总结:


一.数组是什么?

数组(Array) 是一种数据结构,用于存储相同类型的元素集合。数组在内存中是连续分配的,所有的元素都使用相同的数据类型,并且可以通过下标(索引)来访问特定元素。数组是一种常见的线性数据结构,适合用于高效的随机访问操作。

内存分配:

//8字节的markword
//4字节的class指针(压缩class指针的情况)
//4字节的数组大小(决定了数组最大容量是2的32次方)
//java中所有的对象大小都是8字节的整数倍,不足的要用对齐字节补足
//int[] array = {1,2,3,4,5} => 8 + 4 + 4 + 5 * 4 + 4(alignment补齐) = 40字节

特点:

  1. 固定大小:数组在创建时需要指定大小,大小一旦确定,不能更改。
  2. 连续内存空间:数组的元素在内存中是连续存储的,这使得它在读取时可以快速通过索引定位。
  3. 索引从0开始:数组的索引是从0开始的,第一个元素的索引是0,最后一个元素的索引是 长度 - 1
  4. 相同类型元素:数组中的所有元素必须是相同的数据类型。

数组的实现原理:

  • 存储结构:数组在内存中以连续的地址空间存储。假设数组的起始地址为 base_address,每个元素的大小为 size,则索引为 i 的元素的地址为 base_address + i * size。这使得数组可以通过索引在常数时间内(O(1))访问任意元素。

  • 访问时间复杂度:由于数组元素在内存中的地址是可以直接计算的,数组的读取操作(通过索引)时间复杂度为 O(1),即随机访问非常高效。

  • 缺点:由于数组大小固定,插入和删除操作在数组中相对较慢,特别是当需要在数组中间插入或删除元素时,时间复杂度为 O(n)

时间复杂度:

访问元素O(1)直接通过索引访问
修改元素O(1)直接通过索引修改
查找元素O(n)必须遍历整个数组(线性查找)
插入元素O(n)插入元素需要移动后续元素
删除元素O(n)

删除元素后需要移动后续元素

二.Java数组的实现:

Java的数组扩容机制:先创建更大容量的数组,然后将原来数组内的元素复制到新的数组,以此用新数组代替旧数组。

package ArrayStudy;

import java.util.Arrays;
import java.util.Iterator;
import java.util.function.Consumer;
import java.util.stream.IntStream;

public class ArrayListCreateCode implements Iterable<Integer> {
    //创建动态数组ArrayList
    //size => 动态数组有效元素个数
    //容量扩容 => 先创建更大容量的数组,然后将原来数组内的元素复制到新的数组,以此用新数组代替旧数组

    private int size = 0;//逻辑大小
    private int capacity = 8;//容量
    private int[] array = {};//空数组,懒加载(刚开始没用就不数组的情况就不会加载,如果需要此数组就)

    //新增元素
    public void addList(int element){
//        array[size] = element;
//        size++;
        add(size, element);
    }

    // 插入元素
    public void add(int index,  int element){
        checkAndGrow();
        // 添加逻辑
        if(index >= 0 && index < size){
            //数组间或数组内的元素拷贝(想要拷贝的数组,从哪拷贝,拷贝到的数组,拷贝到的数组的索引位置开始拷贝,拷贝元素个数)
            System.arraycopy(array,index,
                    array,index + 1,size - index);
        }
        array[index] = element;//插入元素
        size++;
    }

    private void checkAndGrow() {
        if(size == 0){
            array = new int[capacity];
        }else if(size == capacity){
            // 进行扩容 1.5倍
            capacity += capacity >> 1;
            int[] newArray = new int[capacity];
            System.arraycopy(array, 0, newArray, 0, size);
            array = newArray;// 新数组取代旧数组
        }
    }

    // 获取元素
    public int get(int index){
        return array[index];
    }


    // 遍历数组 => 以函数式接口的形式写出
    public void foreach(Consumer<Integer> consumer){
        for(int i = 0; i < size; i++){
            System.out.println(array[i]);
            // 返回void
            // 提供array[i]
            // 上两条分析后可以使用Consumer
            consumer.accept(array[i]);
        }
    }

    // 迭代器遍历
    @Override
    public Iterator<Integer> iterator(){
        // 匿名内部类
        return new Iterator<Integer>() {
            int i = 0;
            @Override
            public boolean hasNext() {// 有没有下一个元素
                return i < size;
            }

            @Override
            public Integer next() {// 返回当前元素,并移动到下一个元素
                return array[i++];
            }
        };
    }

    // (整数)流的遍历
    public IntStream stream(){
        return IntStream.of(Arrays.copyOfRange(array,0,size));// 选择有效部分流式返回
    }

    // 删除元素
    public int remove(int index){
        int removed = array[index];
        System.arraycopy(array,index + 1,
                array,index,size - index - 1);
        size--;
        return removed;
    }
}

总结:

  • 数组 是存储相同类型数据的基本数据结构,它提供了高效的随机访问。
  • 数组的主要操作包括访问、修改、遍历、获取长度等。
  • 数组的时间复杂度很高效(访问O(1),但插入和删除需要O(n))。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

记得开心一点嘛

您的打赏是对我最大的鼓励与期待

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值