数据结构-数组

一,数组基础及注意事项

1,用来储存一组相同的类型的数据.
2,在内存中,分配连续的空姐,数组创建时要指定容量(大小).
3,创建格式: 数据类型 []数组名 int[] arr = new int[10] int[] arr2 = {1,2,3,4}.
4,索引--访问数组时通过索引进行操作.
(注意:一定要理解索引的含义,在数据结构的学习中基本每次都用,索引简单的可以理解为,待插入元素,即,还没有赋值的第一个元素.)
5.索引从0开始,最大为数组名.length-1;
6,常见的错误: NullPointException ArrayIndexOutOfBoundsException 即我们常说的空指针h=和越界.
7,常见的数组:字符串,对象数组,哈希表

二,演示数组的使用,及数组的方法使用

使用数组时,最重要的就是数组的 索引 ,通过索引可以对数组进行改和查操作。
接下来用图 来演示

1,向数组中添加元素
2,向指定位置添加元素

3,向数组头添加元素
4,获取指定位置的元素和修改指定位置的元素
5,包含、搜索和删除元素

首先:对int类型的数组进行操作

接下来让我们手撕代码.:

复制代码
import java.util.Arrays;
import java.util.Random;

// 封装属于自己的数组
public class MyArray {
    private int[] data; // 底层数据结构
    private int size;// 用来保存实际存放元素的个数

    public MyArray() {
        this(100);
    }

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

    // 判断数组是否为空
    public boolean isEmpty() {
        return this.size == 0;
    }

    // 获取数组实际存放元素的个数
    public int getSize() {
        return this.size;
    }

    // 对数组进行操作
    /*
    * 1、增加的方法
       发现:this.size指向待插入元素的位置,因此,可以在this.size位置增加元素
       在头部增加: 1》 将数组中的元素后移,2》 将val添加到索引为0的位置
       * 在任意位置添加
     */

    /**
     * 在尾部添加
     *
     * @param val val
     */
    public void addTail(int val) {
        add(this.size, val);
    }

    /**
     * 在头部添加
     *
     * @param val val
     */
    public void addHead(int val) {
        add(0, val);
    }

    /**
     * 在任意位置添加
     *
     * @param position 插入的位置
     * @param val      插入的值
     */
    public void add(int position, int val) {
        if (position < 0 || position > this.size) {
            throw new IllegalArgumentException("position is invalid");
        }
        for (int i = this.size - 1; i >= position; i--) {
            this.data[i + 1] = this.data[i];
        }
        this.data[position] = val;
        this.size += 1;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < this.size; i++) {
            sb.append(this.data[i] + ",");
        }
        String result = sb.toString();
        return result.substring(0, result.length() - 1);
    }

    //获取指定位置的元素
    public int getElementByIndex(int index) {
        if (index < 0 || index >= this.size) {
            throw new IllegalArgumentException("index is invalid");
        }
        return this.data[index];
    }

    // 修改指定位置的元素
    public void setElementByIndex(int index, int val) {
        if (index < 0 || index >= this.size) {
            throw new IllegalArgumentException("index is invalid");
        }
        this.data[index] = val;
    }

    // cotains 用来判断数组中是否包含指定的元素
    public boolean contains(int searchVal) {
        for (int i = 0; i < this.size; i++) {
            if (this.data[i] == searchVal) {
                return true;
            }
        }
        return false;
    }

    // 查找指定元素在数组中的索引
    public int findIndex(int searchVal) {
        for (int i = 0; i < this.size; i++) {
            if (this.data[i] == searchVal) {
                return i;
            }
        }
        return -1;
    }

    // 删除数组中最后一个元素
    public int removeFromTail() {
        if (isEmpty()) {
            throw new IllegalArgumentException("this array is null!");
        }
        return this.data[--this.size];
    }

    // 删除数组中的第一个元素
    public int removeFromHead() {
        if (isEmpty()) {
            throw new IllegalArgumentException("this array is null!");
        }
        // 1、先保存数组中的第一个元素
        int result = this.data[0];

        // 2、将数组从索引为1的位置进行前移
        for (int i = 1; i < this.size; i++) {
            this.data[i - 1] = this.data[i];
        }
        this.size--;
        return result;
    }

    // 删除指定位置的元素
    public int removeByIndex(int index) {
        if (index < 0 || index >= this.size) {
            throw new IllegalArgumentException("index is invalid!");
        }
        int result = this.data[index];
        // 从索引为index位置的元素进行前移
        for (int i = index; i < this.size - 1; i++) {
            this.data[i] = this.data[i + 1];
        }
        this.size--;
        return result;
    }

    // 删除指定的元素
    public void remove(int val) {
        for (int i = 0; i < this.size; ) {
            if (this.data[i] == val) {
                // 删除元素---将后面的元素前移,然后更新size
                for (int j = i; j < this.size - 1; j++) {
                    this.data[j] = this.data[j + 1];
                }
                this.size -= 1;
            } else {
                i++;
            }
        }
    }

}

我们要进行任意数据类型的数组,这时就要使用泛型来进行操作.

接下来让我们手撕代码.在上述我们自己写的int类型数组进行修改,添加泛型.

复制代码
import java.util.Random;

// 封装属于自己的数组,使用泛型
public class MyArray2<T> {
    private T[] data; // 底层数据结构
    private int size;// 用来保存实际存放元素的个数

    private int capacity; // 表示容积

    public MyArray2() {
        this(100);
    }

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

    // 获取容积的方法
    public int getCapacity() {
        return this.capacity;
    }

    // 判断数组是否为空
    public boolean isEmpty() {
        return this.size == 0;
    }

    // 获取数组实际存放元素的个数
    public int getSize() {
        return this.size;
    }

    // 对数组进行操作
    /*
    * 1、增加的方法
       发现:this.size指向待插入元素的位置,因此,可以在this.size位置增加元素
       在头部增加: 1》 将数组中的元素后移,2》 将val添加到索引为0的位置
       * 在任意位置添加
     */

    /**
     * 在尾部添加
     *
     * @param val val
     */
    public void addTail(T val) {
        add(this.size, val);
    }

    /**
     * 在头部添加
     *
     * @param val val
     */
    public void addHead(T val) {
        add(0, val);
    }

    /**
     * 在任意位置添加
     *
     * @param position 插入的位置
     * @param val      插入的值
     */
    public void add(int position, T val) {
        if (position < 0 || position > this.size) {
            throw new IllegalArgumentException("position is invalid");
        }
        // 在增加之前,判断数组是否已满,如果已满,要进行扩容
        if (this.size == this.capacity) {
            // 扩容操作
            resize(this.capacity*2);
        }
        for (int i = this.size - 1; i >= position; i--) {
            this.data[i + 1] = this.data[i];
        }
        this.data[position] = val;
        this.size += 1;
    }

    // 改变容积的方法
    private void resize(int newCapacity) {
        System.out.println("--------resize--------");
        // 2、 创建一个新数组
        T[] newArr = (T[]) new Object[newCapacity];

        // 3、将原来数组的内容转移到新数组
        for (int i = 0; i < this.size; i++) {
            newArr[i] = this.data[i];
        }
        // 4、将newArr赋值给 this.data
        this.data = newArr;
        // 5、将newCapacity 赋值给this.capacity
        this.capacity = newCapacity;
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < this.size; i++) {
            sb.append(this.data[i] + ",");
        }
        String result = sb.toString();
        return result.substring(0, result.length() - 1);
    }

    //获取指定位置的元素
    public T getElementByIndex(int index) {
        if (index < 0 || index >= this.size) {
            throw new IllegalArgumentException("index is invalid");
        }
        return this.data[index];
    }

    // 修改指定位置的元素
    public void setElementByIndex(int index, T val) {
        if (index < 0 || index >= this.size) {
            throw new IllegalArgumentException("index is invalid");
        }
        this.data[index] = val;
    }

    // cotains 用来判断数组中是否包含指定的元素
    public boolean contains(T searchVal) {
        for (int i = 0; i < this.size; i++) {
            if (this.data[i].equals(searchVal)) {
                return true;
            }
        }
        return false;
    }

    // 查找指定元素在数组中的索引
    public int findIndex(T searchVal) {
        for (int i = 0; i < this.size; i++) {
            if (this.data[i].equals(searchVal)) {
                return i;
            }
        }
        return -1;
    }

    // 删除数组中最后一个元素
    public T removeFromTail() {
        return removeByIndex(this.size-1);
    }

    // 删除数组中的第一个元素
    public T removeFromHead() {
        return removeByIndex(0);
    }

    // 删除指定位置的元素
    public T removeByIndex(int index) {
        if (index < 0 || index >= this.size) {
            throw new IllegalArgumentException("index is invalid!");
        }
        T result = this.data[index];
        // 从索引为index位置的元素进行前移
        for (int i = index; i < this.size - 1; i++) {
            this.data[i] = this.data[i + 1];
        }
        this.size--;
        if(this.size <= this.capacity/2 && this.capacity/2>1){
            resize(this.capacity/2);
        }
        return result;
    }

    // 删除指定的元素
    public void remove(int val) {
        for (int i = 0; i < this.size; ) {
            if (this.data[i].equals(val)) {
                // 删除元素---将后面的元素前移,然后更新size
                for (int j = i; j < this.size - 1; j++) {
                    this.data[j] = this.data[j + 1];
                }
                this.size -= 1;
            } else {
                i++;
            }
        }
        // 删除之后,进行判断是否要进行缩容,如果需要缩容,缩到原容积的1/2
        if(this.size <= this.capacity/2 && this.capacity/2>1){
            resize(this.capacity/2);
        }
    }
}

代码较长希望有心人可以看完.

三,数组的复杂度分析.

我们对数组的逻辑有了简单的了解,就对数组的复杂度进行分析,后面可以通过比较复杂度,来选择合适的数据结构来储存数据.

1,分析动态数组的时间复杂度

(1),添加操作

1,addLast(e) O(n)

2,addFirst(e) O(1) 渐进时间复杂度

3,add(index,e) O(n^2) 描述n趋近于无穷的情况

(2),添加操作
(3),删除操作
(4),修改操作
(5),查找操作
(6) 综合
相关推荐
wand codemonkey1 小时前
SpringbootWeb【入门】+MySQL【安装】+【DataDrip安装 】+【连接MySQL】
java·mysql·mybatis
Mahir089 小时前
Spring 循环依赖深度解密:从问题本质到三级缓存源码级解析
java·后端·spring·缓存·面试·循环依赖·三级缓存
RyFit10 小时前
SpringAI 常见问题及解决方案大全
java·ai
石山代码10 小时前
C++ 内存分区 堆区
java·开发语言·c++
绝知此事10 小时前
【算法突围 01】线性结构与哈希表:后端开发的收纳术
java·数据结构·算法·面试·jdk·散列表
无风听海10 小时前
C# 隐式转换深度解析
java·开发语言·c#
一只大袋鼠11 小时前
Git 进阶(二):分支管理、暂存栈、远程仓库与多人协作
java·开发语言·git
LuminousCPP12 小时前
数据结构 - 线性表第四篇:C 语言通讯录优化升级全记录(踩坑 + 思考)
c语言·开发语言·数据结构·经验分享·笔记·学习
德思特12 小时前
从 Dify 配置页理解 RAG 的重要参数
java·人工智能·llm·dify·rag
YOU OU12 小时前
Spring IoC&DI
java·数据库·spring