数据结构之什么是数组?
文章目录
- 什么是数组?
- 数组的基本操作
- 查——读取元素
- 改——更新元素
- 增——插入元素
- 数组扩容
- 删——删除元素
- 数组操作的时间复杂度
- 数组的优势和劣势
- 数组的完整代码(Java)
- 最后
什么是数组?
数组对应的英文是array,是有限个相同类型的变量所组成的有序集合,数组中的每一个变量被称为元素。数组是最为简单、最为常用的数据结构。
- 数组的每一个元素都有自己的下标,该下标从0开始,一直到数组长度-1结束。
- 数组在内容中是顺序存储,在内存中的表现形式为一整块完整的内存空间。
- 数组的特点,有限个数,相同类型,有序。
数组的基本操作
数组的基本操作,无非就是增、删、改、查四种情况。
查——读取元素
对于数组来说,读取元素是最为简单的操作。由于数组在内存中顺序存储,所以只需要给出一个数组下标,就可以读取到对应的数组元素。
这种通过数组下标读取元素的方式叫做随机读取
int[] arr = new int[]{1, 5, 4, 6, 1, 3, 5, 3};
// 输出下标为2的数组元素,即数组的第三个元素,4
System.out.println(arr[2]);
改——更新元素
把数组的某一个元素替换为一个新值,也是非常简单的事情,直接利用数组的下标,就可以把新值赋给该元素。
int[] arr = new int[]{1, 5, 4, 6, 1, 3, 5, 3};
// 输出赋值前,下标为4的数组元素,值为:1
System.out.println(arr[4]);
// 赋值,改变数组元素的值
arr[4] = 10;
// 输出赋值后,下标为4的数组元素,值为:10
System.out.println(arr[4]);
增——插入元素
数组的插入元素操作是一个比较复杂的操作,因为涉及数组元素个数的变动,所以在介绍插入元素操作之前,需要先介绍一下数组的长度和数组的实际元素个数。
数组的长度:即数组初始化时开辟的内存空间大小。
// 开辟了一个数组长度为5的数组内存空间
int[] arr = new int[5];
数组的实际元素个数:即数组中存在的元素个数。
// 开辟了一个数组长度为5的数组内存空间
int[] arr = new int[5];
arr[0] = 2;
arr[1] = 8;
for (int i : arr) {// 输出:2 8 0 0 0,数组的实际元素个数为2System.out.print(i + "\t");
}
上述的数组中,实际的元素个数只有两个,即下标为0、1的两个元素,其他元素之所以输出为0,是因为在Java中,int类型的初始化值为0,所以输出的数组为2 8 0 0 0
,如果使用Integer
类型的数组,则可以通过null
值进行更直观的判断。
// 开辟了一个数组长度为5,类型为Integer的数组内存空间
Integer[] array = new Integer[5];
array[0] = 2;
array[1] = 8;
for (Integer integer : array) {// 输出:2 8 null null null,数组的实际元素个数为2System.out.print(integer + "\t");
}
正是因为存在数组的长度和实际元素个数不同的情况,所以在一般情况下,我们会使用一个变量来记录数组的实际元素个数。
public class Array {/*** 数组*/private int[] array;/*** 数组的最大元素个数,即为数组的长度*/private int maxSize;/*** 数组的实际元素个数*/private int size;/*** 构造函数** @param capacity 初始化数组的容量大小,即maxSize大小*/public Array(int capacity) {// 初始化数组长度this.maxSize = capacity;// 初始化数组,开辟数组空间this.array = new int[maxSize];// 初始化数组实际元素个数,为0this.size = 0;}/*** 获取数组的实际元素个数** @return 数组的实际元素个数*/public int size() {return this.size;}/*** 获取数组的长度** @return 数组的长度*/public int length() {return this.maxSize;}}
我们只需要通过创建Array类的对象的方式,即可完成一个数组的初始化。
Array array = new Array(5);
// 数组的实际元素个数为:0
System.out.println(array.size());
// 数组长度为:5
System.out.println(array.length());
这个时候,数组的插入插入操作即可以开始了。
数组的插入操作也分为三种,分别为:
- 尾部插入
- 中间插入,头部插入本质上也属于中间插入的一种
- 超范围插入
尾部插入最为简单,只需要将元素放置在数组尾部的空闲元素的位置上即可。
中间插入较为复杂,因为在数组中间位置插入元素,需要先将插入位置及插入位置后面的元素向后移动,空出一个数组下标给插入的元素。
超范围插入最为复杂,因为超范围插入涉及到了数组的扩容。
数组扩容
为什么需要数组扩容?
我们不断往一个数组中插入元素,最终数组实际元素个数等于,甚至大于数组长度,这个时候数组已经无法容纳更多的元素了,所以我们需要通过扩容在扩大数组的容量。
怎么扩容?
数组的长度在初始化的时候就已经固定了,这也是数组有限个数的特点,如果如果想要对数组进行扩容,就需要创建一个容量比原数组更大的新数组,并将原数组的元素复制到新数组中,实现原数组的替换操作。
所以数组的插入操作的具体代码为:
/*** 直接在数组尾部插入元素** @param element 需要插入的元素*/
public void add(int element) {add(this.size, element);
}/*** 在数组指定位置插入元素** @param index 数组指定的下标位置* @param element 需要插入的元素*/
public void add(int index, int element) {// 这样操作的目的是为了保证数组的元素全部都可以从0开始,并且中间不会出现空闲元素if (index < 0 || index > size) {throw new IndexOutOfBoundsException("插入元素的位置超出数组的实际元素范围");}// 如果当前数组实际元素个数大于等于数组长度,进行扩容操作if (size >= maxSize) {resize();}// 从下标index开始将元素向后移动一位for (int i = size; i > index; i--) {this.array[i] = this.array[i - 1];}// 在index位置插入需要插入的元素this.array[index] = element;// 数组实际元素个数+1size++;
}/*** 扩容操作,每次扩容,新数组的长度为原数组的2倍*/
private void resize() {// 新数组的长度为原数组的2倍this.maxSize = this.maxSize * 2;// 初始化新数组int[] newArray = new int[maxSize];// 将原数组的元素复制到新数组中System.arraycopy(this.array, 0, newArray, 0, this.size);// 使用新数组替换原数组this.array = newArray;
}
删——删除元素
数组的删除操作比起插入元素来,比较简单一些,因为不涉及数组扩容的问题,我们只需要将数组被删除位置后面的元素向前移动即可。
/*** 删除数组元素** @param index 需要删除的数组元素下标位置* @return 删除的元素*/
public int delete(int index) {// 判断需要删除的数组下标是否在数组实际元素范围之内if (index < 0 || index >= size) {throw new IndexOutOfBoundsException("删除元素的位置超出数组的实际元素范围");}int deleteElement = this.array[index];for (int i = index; i < size - 1; i++) {this.array[index] = this.array[index + 1];}size--;return deleteElement;
}
数组操作的时间复杂度
数组操作 | 时间复杂度 |
---|---|
读取元素 | O(1) |
更新元素 | O(1) |
插入元素 | O(n) |
删除元素 | O(n) |
数组的优势和劣势
优势:数组拥有非常高效的随机访问能力,只需要通过下标,就可以用常量时间找到对应的元素。
劣势:数组在插入和删除的时候,需要移动大量元素,导致效率低下。
总结:数组适用于读操作多,写操作少的场景。
数组的完整代码(Java)
public class Array {/*** 数组*/private int[] array;/*** 数组的最大元素个数,即为数组的长度*/private int maxSize;/*** 数组的实际元素个数*/private int size;/*** 构造函数** @param capacity 初始化数组的容量大小,即maxSize大小*/public Array(int capacity) {// 初始化数组长度this.maxSize = capacity;// 初始化数组,开辟数组空间this.array = new int[maxSize];// 初始化数组实际元素个数,为0this.size = 0;}/*** 获取数组的实际元素个数** @return 数组的实际元素个数*/public int size() {return this.size;}/*** 获取数组的长度** @return 数组的长度*/public int length() {return this.maxSize;}/*** 获取下标对应的元素** @param index 数组下标* @return 下标对应的元素*/public int get(int index) {// 判断需要删除的数组下标是否在数组实际元素范围之内if (index < 0 || index >= size) {throw new IndexOutOfBoundsException("删除元素的位置超出数组的实际元素范围");}return this.array[index];}/*** 更新下标对应的元素** @param index 数组下标* @param element 需要更新的元素*/public void update(int index, int element) {// 判断需要删除的数组下标是否在数组实际元素范围之内if (index < 0 || index >= size) {throw new IndexOutOfBoundsException("删除元素的位置超出数组的实际元素范围");}this.array[index] = element;}/*** 直接在数组尾部插入元素** @param element 需要插入的元素*/public void add(int element) {add(this.size, element);}/*** 在数组指定位置插入元素** @param index 数组指定的下标位置* @param element 需要插入的元素*/public void add(int index, int element) {// 这样操作的目的是为了保证数组的元素全部都可以从0开始,并且中间不会出现空闲元素if (index < 0 || index > size) {throw new IndexOutOfBoundsException("插入元素的位置超出数组的实际元素范围");}// 如果当前数组实际元素个数大于等于数组长度,进行扩容操作if (size >= maxSize) {resize();}// 从下标index开始将元素向后移动一位for (int i = size; i > index; i--) {this.array[i] = this.array[i - 1];}// 在index位置插入需要插入的元素this.array[index] = element;// 数组实际元素个数+1size++;}/*** 扩容操作,每次扩容,新数组的长度为原数组的2倍*/private void resize() {// 新数组的长度为原数组的2倍this.maxSize = this.maxSize * 2;// 初始化新数组int[] newArray = new int[maxSize];// 将原数组的元素复制到新数组中System.arraycopy(this.array, 0, newArray, 0, this.size);// 使用新数组替换原数组this.array = newArray;}/*** 删除数组元素** @param index 需要删除的数组元素下标位置* @return 删除的元素*/public int delete(int index) {// 判断需要删除的数组下标是否在数组实际元素范围之内if (index < 0 || index >= size) {throw new IndexOutOfBoundsException("删除元素的位置超出数组的实际元素范围");}int deleteElement = this.array[index];for (int i = index; i < size - 1; i++) {this.array[index] = this.array[index + 1];}size--;return deleteElement;}
}
最后
本文Github https://github.com/herenpeng/code-learn 已收录,欢迎Star。
数据结构之什么是数组?相关推荐
- 数据结构与算法---稀疏数组
数据结构与算法-稀疏数组 1.基本介绍: 当一个数组中大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组. 2.稀疏数组的处理方法是: (1)记录数组一共有几行几列,有多少个 ...
- 看得见的数据结构Android版之数组表(数据结构篇)
零.前言: 一讲到装东西的容器,你可能习惯于使用ArrayList和数组,你有想过ArrayList和数组的区别吗? Java的类起名字都不是随便乱起的,一般前面是辅助,后面是实质:ArrayList ...
- python求数组最大值_Python算法与数据结构--求所有子数组的和的最大值
Python算法与数据结构--求所有子数组的和的最大值 玄魂工作室秘书 玄魂工作室 昨天 题目:输入一个整形数组,数组里有正数也有负数.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. ...
- java 数据结构详解,数组,集合,HashMap
数组的特性: 数组在内存中是一块连续的存储单元存储起来的,声明数组的时候我们必须声明其长度,这样才会为我们声明一个连续的存储区域. 这种存储方式造成我们想要往数组中存储一个数据时那么其后面各个元素都要 ...
- JavaScript数据结构和算法简述——数组
为什么先讲数组 数据结构可以简单的被分为线性结构和非线性结构. 线性结构大致包括: 数组(连续存储): 链表(离散存储): 栈(线性结构常见应用,由链表或数组增删和改进功能实现): 队列(线性结构常见 ...
- 数据结构 (一) ----- 数据结构基本概念基于数组实现线性表
相关文章: <数据结构 (一) ----- 数据结构基本概念&基于数组实现线性表> 文章目录 数据结构基本概念 一.逻辑结构 二.存储结构 三.数据结构定义 四.数据结构的通用的几 ...
- 看得见的数据结构Android版之数组表(视图篇)
零.前言: 1.本文的姊妹篇:看得见的数据结构Android版之表的数组实现(数据结构篇) 2.希望你可以和我在Github一同见证:DS4Android的诞生与成长,欢迎star 3.激动人心的时刻 ...
- Python数据结构之树形结构——数组存储
Python数据结构之树形结构--数组存储 树:一种非线性结构,主要使用链表来存储,也可以使用数组存储. 本代码使用两种数组 元素数组:0,6,3,5,4,7,8,9,2 由于 0 索引不存储元素,所 ...
- 数据结构:串、数组和广义表
串 线性结构:线性表.栈和队列.串与数组和广义表 串的逻辑结构和线性表极为相似,区别仅在于串的数据对象限定为字符集.在基本操作上,串和线性表有很大差别.线性表的基本操作主要以单个元素作为操作对象,如查 ...
- python 树状数组_【算法日积月累】19-高级数据结构:树状数组
树状数组能解决的问题 树状数组,也称作"二叉索引树"(Binary Indexed Tree)或 Fenwick 树. 它可以高效地实现如下两个操作: 1.数组前缀和的查询: 2. ...
最新文章
- mysql 导入文件提示 --secure-file-priv option 问题
- WeightNet torch
- server2012 r2搭建双DNS
- 1、ShardingSphere基本概念
- ES10的动态导入文件
- 数据恢复软件(绝对真实可用)
- 验证授权【msdn】
- 使用js对select动态添加和删除OPTION示例代码
- springbatch读取外部数据到mysql
- sleep() wait() yield() join()
- 《嵌入式系统可靠性设计技术及案例解析》读书笔记(七)
- Android MTK修改手机型号
- SSM社区医院卫生所病人患者随访信息管理javaweb网站系统设计与实现
- UIBezierPath+画板,签名档
- 浪潮之巅-读书笔记二
- 积木编程安卓app入门 —— 5 分钟学会 App Inventor
- 将前端网页生成二维码
- 运营商大数据:未来移动联通电信三大运营商数据会同步共享吗?
- 2011RTIC论坛回顾
- linux安装——管理应用程序