数组的初识

简介: 数组的初识

1.初识数组

 

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

以整型数组为例:数组的存储形式如下:

元素:3    1    6    4    8    7    6

下标:0    1    2    3    4    5    6

由上,数组中的每一个元素都拥有自己的下标,只不过这个下标从0开始,一直到数组大小-1.

数组的另外一个特点,是在内存中顺序存储,因此可以很好地实现逻辑上的顺序表。

数组在内存中的存储,具体是什么样子呢?

内存是由一个个连续的内存单元组成的,每一个内存单元都拥有自己的地址。在这些内存单元中,有些被其他数据占用了,有些是空闲的。

数组中的每一个元素,都存储在小小的内存单元中,并且元素之间紧密排列,既不能打乱存储顺序,也不能跳过存储单元进行存储。如下表表示一段内存空间中数组的存储方式:

* * 3 6 4
8 7 * * # *
# # # # * *

(注:*表示该内存单元不存储任何东西,#表示该内存单元存储除数组外的其他内容)

不同类型的数组,每个元素所占的字节数也不同,该表格只是简单举例.

2.数组的简单操作

2.1读取元素

对于数组来说,读取元素是最简单的操作。由于数组在内存空间中的存储方式是顺序存储,所以只要得到数组下标,就能获得对应元素。

假设有一个名字叫arr的数组,若要获取到下标为一的元素,就写作arr[1]。注意:输入的下标必须在数组长度范围之内,否则会出现数组越界。

像这种根据下标获取元素的方式叫做随机读取

简单的代码示例如下:

int[] array = new int[]{3,1,6,4,8,7};
//输出数组中下标为三的元素
System.out.println(array[3]);

2.2更新元素

要把数组中的某一个元素的值替换为另一个新值,只需要利用数组下标直接赋值即可

简单代码示例如下:

//初始化数组
int[] arr = new int[]{3,1,6,4,8,7};
//给下标为1的元素重新赋值
arr[1] = 10;
//输出下标为1的元素
System.out.println(arr[1]);

根据上次我们学习的时间复杂度和空间复杂度的有关知识,我们可以得知读取元素和更新元素的时间复杂度为O(1),空间复杂度为O(n)。

2.3插入元素

在介绍该操作之前,我们首先需要知道一个概念:那就是数组的实际元素数量还可能小于数组的长度。例如:

3 1 6 4 8 7
0 1 2 3 4 5 6 7

因此,插入数组元素的操作存在3种情况。

1.尾部插入

2.中间插入

3.超范围插入

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

3 1 6 4 8 7 6
0 1 2 3 4 5 6 7

2.中间插入,稍微复杂一些。由于数组的每一个元素都有其固定下标,所以先把插入位置及后面的元素向后移动,腾出地方,再把要插入的元素放入该位置

譬如在下标为1的位置插入元素6:

(注意:移动元素的步骤一定是从后往前,如上图步骤,若为从前向后,则会一直只挪动一个元素)

挪动后得到:

3 6 1 6 4 8 7
0 1 2 3 4 5 6 7

完整代码如下:

private int[] array;
private int size;
 
//创建大小为capacity的数组
public Arrayinsert(int capacity){
    this.array = new int[capacity];
    size = 0;
}
 
/*index-插入的位置;element-插入的元素*/
 
public void insert(int index, int element) throws Exception{
    //判断访问下标是否超出范围
    if(index<0 || index>size){
        throw new IndexOutOfBoundsException("超出数组实际范围!");
    }
    //从右向左循环,将元素逐个向右挪动一位
    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{
   Arrayinsert myArray = new Arrayinsert[8];
   myArray.insert(0,3);
   myArray.insert(1,1);
   myArray.insert(2,6);
   myArray.insert(3,4);
   myArray.insert(4,8);
   myArray.insert(5,7);
   myArray.insert(1,6);
   myArray.output():
}

代码中成员变量size是数组实际元素的数量。如果插入元素在数组尾部,则size=index,如果插入在中间则index<size。

如果传入的是下标参数大于size或者小于零,会认为是非法输入,会直接抛出异常。

到现在,我们已经大致了解了插入操作,但现在仍存在一个问题:如果不断插入元素,元素数量就会大于数组长度,这怎么办?

这就涉及了超范围插入

比如现在有一个数组长度为6的数组,已经装满了元素,还想要添加一个新元素,这就涉及了数组的扩容

3 1 6 4 8 7
0 1 2 3 4 5

如图,我们可以知道该数组的大小在一开始就确定了,无法随意的变长变短。那么此时,我们就可以考虑创建一个新数组,长度是旧数组的二倍,再把旧数组的内容复制过来,这就实现了数组的扩容。

                                       
0 1 2 3 4 5 6 7 8 9 10 11
3 1 6 4 8 7
10 11

如此一来,我们插入数组的方式也改变了,部分代码如下:

public void insert(int index, int element){
    //判断下标是否超出范围
    if(index<0 || index>size){
        throw new IndexOutOfBoundsException("超出数组的实际范围!");
    }
    //从右向左逐一移动数组元素
    for(int i=size-1; i>=index; i--){
        array[i+1] = array[i];
    }
    //如果数组实际长度大于等于数组长度,则引入扩容函数resize
    if(size >= array.length){
        resize();
    }
    array[index] = element;
    size++;
}
 
public void resize(){
    //创建一个新数组,大小是旧数组长度的两倍
    int[] arrayNew = new int[array.length*2];
    //利用arraycopy函数将旧数组内容复制到新数组内
    //附:arraycopy函数用法:arraycopy(arr1, a, arr2, b, c);
    //即在arr1数组内从下标为a的元素开始,放在arr2下标为b的元素开始,复制元素为c个
    System.arraycopy(array, 0, arrayNew, 0, size);
    array = arrayNew;
}

这样就完成了数组扩容的操作。

2.4删除元素

数组的删除操作和插入操作相反,如果删除的元素在中间,其之后的元素都会向前移动一位

(其之后的元素的移动位次与插入操作相反,应该为从右向左的元素逐向前移动一位)

由于不涉及数组的扩容操作,因此比插入操作要更简单。

代码如下:

public void deleted(int index){
    //判断是否超出数组范围
    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 deletedElemet;
}

相信各位对数组的概念及其操作有了一定的理解,希望该文章对大家有帮助,谢谢大家支持哦

 

相关文章
|
JavaScript
|
网络协议 前端开发 物联网
带你读《互联网协议第六版 (IPv 6)》第三章IPv6过渡技术3.1IPv6 改造的基本概念
《互联网协议第六版 (IPv 6)》第三章IPv6过渡技术3.1IPv6 改造的基本概念
带你读《互联网协议第六版 (IPv 6)》第三章IPv6过渡技术3.1IPv6 改造的基本概念
|
2天前
|
云安全 人工智能 算法
以“AI对抗AI”,阿里云验证码进入2.0时代
三层立体防护,用大模型打赢人机攻防战
1292 1
|
9天前
|
编解码 人工智能 自然语言处理
⚽阿里云百炼通义万相 2.6 视频生成玩法手册
通义万相Wan 2.6是全球首个支持角色扮演的AI视频生成模型,可基于参考视频形象与音色生成多角色合拍、多镜头叙事的15秒长视频,实现声画同步、智能分镜,适用于影视创作、营销展示等场景。
697 4
|
2天前
|
机器学习/深度学习 安全 API
MAI-UI 开源:通用 GUI 智能体基座登顶 SOTA!
MAI-UI是通义实验室推出的全尺寸GUI智能体基座模型,原生集成用户交互、MCP工具调用与端云协同能力。支持跨App操作、模糊语义理解与主动提问澄清,通过大规模在线强化学习实现复杂任务自动化,在出行、办公等高频场景中表现卓越,已登顶ScreenSpot-Pro、MobileWorld等多项SOTA评测。
535 2
|
3天前
|
人工智能 Rust 运维
这个神器让你白嫖ClaudeOpus 4.5,Gemini 3!还能接Claude Code等任意平台
加我进AI讨论学习群,公众号右下角“联系方式”文末有老金的 开源知识库地址·全免费
|
2天前
|
存储 弹性计算 安全
阿里云服务器4核8G收费标准和活动价格参考:u2a实例898.20元起,计算型c9a3459.05元起
现在租用阿里云服务器4核8G价格是多少?具体价格及配置详情如下:云服务器ECS通用算力型u2a实例,配备4核8G配置、1M带宽及40G ESSD云盘(作为系统盘),其活动价格为898.20元/1年起;此外,ECS计算型c9a实例4核8G配置搭配20G ESSD云盘,活动价格为3459.05元/1年起。在阿里云的当前活动中,4核8G云服务器提供了多种实例规格供用户选择,不同实例规格及带宽的组合将带来不同的优惠价格。本文为大家解析阿里云服务器4核8G配置的实例规格收费标准与最新活动价格情况,以供参考。
230 150