数据结构一、数组(玩转动态数组)

本文详细介绍了如何创建一个自定义的数组类`MyArray<T>`,包括初始化、扩容缩容、添加删除元素、查询修改元素等操作。通过泛型实现了存储任意类型数据的能力,并通过扩容策略优化了添加元素的效率。同时,文章强调了数组在查询上的优势和在增删操作上的局限性,以及如何通过索引来提高效率。
摘要由CSDN通过智能技术生成

数组描述

  • 数组就是一个容器
  • 数组的声明
       int[] arr = new int[10];
  • 数组的优缺点
    • 数组的优点:快速查询
    • 数组的缺点:增删慢
  • 索引
    • 数组最好应用在索引有语义的情况下
    • 索引最好有语义,也可以没有语义
    • 并非所有有语义的数字都可以作为数组的索引,
      • eg:身份证号,
        • 他是大数,要开辟大内存,
        • 如果只有10个人,就用身份证号来做索引,只有十个人,会浪费大量内存

创建数组

1.先创建一个数组类
public class MyArray<T> {
}
2.数组的声明
  • 这里使用泛型,因为数组可以存储任意类型数据
  • 初始化为10,
  • 并且可以获取数组中存放元素的个数
  • 判断数组是否为空
    private T[] data;  //数组容器
    private int size;  //实际存放元素的个数

    public MyArray() {
        this(10);
    }

    public MyArray(int capacity) {
        data = (T[]) new Object[capacity];
        size = 0;
    }
    
    //获取数组中存放元素的个数
    public int getSize() {
        return size;
    }

    //判断数组是否为空
    public boolean isEmpty() {
        return size == 0;
    }
3.扩容与缩容
  • 在数组满足条件下可以进行扩容和缩容,
  • 创建一个长度为原来数组2倍或者1/2的新数组,
  • 将原数组的元素赋进去就可以
  • 时间复杂度为O(n)
 //扩容与缩容
    public void resize(int newCapacity) {
        T[] newData = (T[]) new Object[newCapacity];
        for (int i = 0; i < size; i++) {
            newData[i] = data[i];
        }
        data = newData;
    }
4.向数组中添加元素
  • 判断数组是否为空
  • 我们的添加元素的位置不能大于数组长度
  • 判断数组是否满了没满则调用上述的扩容为其扩容2倍,一般是扩容1.5倍
  • 在尾部添加时直接添加
    • 时间复杂度为O(1)
  • 在头部添加时,需要把元素后移,然后再添加再第一个
    • 所以数组添加慢 时间复杂度为O(n)
  • 在中间添加时,如上,
    • 时间复杂度为O(n/2)
  • 综上来看 添加的时间复杂度为O(n)
 //向数组中的末尾添加元素 size为我们始终添加元素的位置
    public void addTail(T ele) throws IllegalAccessException {
        add(ele, size);
    }

    //向数组指定位置添加元素
    public void add(T ele, int index) throws IllegalAccessException {
        //添加位置不能小于0也不能大于数组长度
        if (index < 0 || index > size) {
            throw new IllegalAccessException("array is error!");
        }
        //判断数组是否已满,满就进行扩容
        if (size == data.length) {
            resize(2 * data.length);
        }
        //元素后移,从最后一个开始移动
        for (int i = size - 1; i > index; i--) {
            data[i + 1] = data[i];
        }
        data[index] = ele;
        size++;
    }

    //向数组的头部添加元素
    public void addHead(T ele) throws IllegalAccessException {
        add(ele, 0);
    }
5.查询数组中的元素
  • 判断数组是否为空
  • 引进了索引,正是因为索引的存在,所以数组的特点就出来了,查询快
  • 时间复杂度为O(1)
//获取头部元素
    public T getHeed() throws IllegalAccessException {
        return getEleByIndex(0);
    }

    //获取指定位置元素
    public T getEleByIndex(int index) throws IllegalAccessException {
        if (index < 0 || index > size - 1) {
            throw new IllegalAccessException("array is error!");
        }
        return data[index];
    }

    //获取尾部元素
    public T getTail() throws IllegalAccessException {
        return getEleByIndex(size - 1);
    }
6.修改指定位置元素
  • 判断数组是否为空
  • 修改同查询一样借用索引十分迅速
  • 时间复杂度为O(1)
//修改指定位置元素
    public void setEleByIndex(int index, T ele) throws IllegalAccessException {
        if (index < 0 || index > size - 1) {
            throw new IllegalAccessException("array is error!");
        }
        data[index] = ele;
    }
7.移除指定位置的元素
  • 判断数组是否为空
  • 数组如果长度太长,使用元素太少容易造成空间浪费,引进了缩容
    • 可以用现数组有3/4的容量被浪费时,可以考虑数组缩容
    • 可以调用上述扩容同样方法,缩容其的1/2
  • 在尾部删除时直接删除
    • 时间复杂度为O(1)
  • 在头部删除时,需要把元素前移,然后再长度减一,直接释放
    • 所以数组删除慢 时间复杂度为O(n)
  • 在中间删除时,如上,
    • 时间复杂度为O(n/2)
  • 综上来看 删除的时间复杂度为O(n)
 //移除指定位置的元素
    public T removeEle(int index) throws IllegalAccessException {
        if (index < 0 || index > size - 1) {
            throw new IllegalAccessException("array is error!");
        }
        T result = data[index];
        for (int i = index; i < size - 1; i++) {
            data[i] = data[i + 1];
        }
        size--;
        //缩容
        if (size <= data.length / 4 && data.length / 2 != 0) {
            resize(data.length / 2);
        }
        return result;
    }
8.根据元素判断数组中是否存在
  • 只需要遍历一遍,有则返回索引
  • 时间复杂度为O(1)
//找到指定元素的索引
    public int getIndex(T ele) {
        int index = -1;
        for (int i = 0; i < size; i++) {
            if (data[i] == ele) {
                index = i;
                break;
            }
        }
        return index;
    }

    //判断数组中是否包含指定的元素
    public boolean contains(T ele) {
        return getIndex(ele) != -1;
    }
9.重新toString
  • 重写toString,这样可以快速输出数组,也是用数组的遍历来进行输出
@Override
    public String toString() {
        StringBuffer sb = new StringBuffer("[");
        for (int i = 0; i < size; i++) {
            sb.append(data[i]);
            if (i != size - 1) {
                sb.append(",");
            }
        }
        sb.append("],数组的容量为:");
        sb.append(data.length).append(",实际存放元素的个数:").append(size);
        return sb.toString();
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值