数组: 一种非常基础且重要的数据结构

大数据 数据分析
数组是一种非常基础且重要的数据结构,很多复杂的数据结构都是基于数组实现的。深入理解数据的存储原理和特点,有利于我们在实际开发工作中,充分发挥数据的优势。

 [[411318]]

本文转载自微信公众号「码上Java」,作者码上Java。转载本文请联系码上Java公众号。

前言

数组是一种非常基础且重要的数据结构,很多复杂的数据结构都是基于数组实现的。深入理解数据的存储原理和特点,有利于我们在实际开发工作中,充分发挥数据的优势。

数据是什么

数组的定义:数组(Array)是一种线性表数据结构。它用一组连续的内存空间,存储一组具有相同类型的数据。

在上面的定义中加黑的描述,我们可以发现数组的几个特点,分别是:线性表、连续的内存空间、相同类型的数据。如下图所示:

数组因具有连续的内存空间的特点,让数据拥有非常高效率的“随机访问”,但也是因为要保持这个连续的内存空间,导致数组在删除或插入操作的时非常低效。因为数组为了保持连续性,必然会涉及大量数据的搬移,这个是非常消耗时间的。

思考:这里你可能会有疑问:什么是连续的内存空间?

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

然而数据中的每个元素,都存储在小小的内存单元中,并且元素之间紧密排列,既不能打乱元素的存储顺序,也不能跳过某个存储单元进行存储。

数组的随机访问

数组的随机访问是有个寻址公式的,上问中我们提到过数组是用一组连续的内存空间存储数据元素的,然而每个内存单元都有自己的地址(在计算机里面就是通过这个地址访问数据的),又加上每个内存单元的大小都是一样的,这样就很容易得到一个公式了,如下所示:

  1. a[i]_address=base_address+i*data_type_size 

我们来简单解释一下上述公式,其中data_type_size表示数组中每个元素的大小、base_address表示内存块的首地址、i 表示数组下标。

数组的基本操作

在开始之前我们先创建一个数组类,来模拟数组操作时候的相关操作。代码如下:

  1. public class MyArray { 
  2.  
  3.     private int[] array; 
  4.     // 数组大小 
  5.     private int size
  6.       
  7.     public MyArray(int capacity) { 
  8.         this.size = 0; 
  9.         this.array = new int[capacity]; 
  10.     } 
  11.      

1. 读取元素

我们知道数组在内存中是连续存储的,所以根据上文的寻址公式可以知道,我们可以根据数组下标 i 快速定位到对应的元素。

简单举例,代码如下:

  1. int[] array={1,2,3,4,5,6}; 
  2. System.out.println(array[1]); // 输出的是2  因为数组的下标是从0开始的。 

2. 更新元素

我们可以根据数组下标快速查找到对应元素。那么同样道理,我们可以根据数组下标 i 快速更新元素,这中间涉及两个过程,首先就是找到数组下标 i 对应的数据元素A,然后将新的数据元素B赋值给A即完成更新。

简单举例,代码如下:

  1. int[] array={1,2,3,4,5,6}; 
  2. System.out.println(array[1]);  // 输出的是2 
  3.  
  4. //更新数组下标为 1 的数组元素 
  5. array[1]=22; 
  6. System.out.println(array[1]); // 输出的是22   

3. 插入元素

相比读取、更新操作,插入元素稍微复杂一些,分为以下两种情况:

尾部插入:首先,我们看看尾部插入,这种情况很简单,在数组的最后新增一个新的元素,此时对于原数组来说没有任何影响,时间复杂度为0(1)。如下图所示:

中间插入:如果在数组的中间位置插入元素的话,此时会对插入元素位置之后的元素产生影响,也就是这些数据需要向后依次挪动一个位置。如下图所示:

中间插入的代码如下:

  1. /** 
  2.  *  插入元素 
  3.  * @param index  待插入的位置 
  4.  * @param element 待插入的元素 
  5. */ 
  6. public void insert(int index,int element){ 
  7.     if(index<0 || index>size){ 
  8.        throw new IndexOutOfBoundsException("超过数组容量 ! 插入失败!"); 
  9.      } 
  10.     // 从左到右,将元素向右移动一位 
  11.     for (int i=size-1 ; i>index ; i--){ 
  12.        array[i+1]=array[i]; 
  13.     } 
  14.     // 此时index这个位置已经腾空了,可以放进入element 
  15.     array[index]=element; 
  16.     //数组中元素个数+1 
  17.     size++; 

3.1 数组扩容

因为数组的长度在创建的时候已经确定了,当插入元素的时候如果数组已经满了,是没办法插入成功的。这个时候就要考虑数组扩容的问题了,那么该如何实现扩容呢?

其实我们可以这样,比如此时的数组是A, A已经满了,我们再创建一个数组B且数组长度是A的2倍,然后我们将数组A的元素全部放到数组B中,这样就完成了数组扩容了。

数组扩容的代码如下:

  1. /** 
  2.  * 数组扩容为原数组的二倍 
  3.  */ 
  4. public void resize(){ 
  5.  int[] newArray=new int[array.length*2]; 
  6.  System.arraycopy(array,0,newArray,0,array.length); 
  7.  array=newArray; 

4. 删除元素

删除元素和插入元素类似,如果我们删除第k个位置的数据,为了内存的连续性,同样会涉及数据的挪动。如下图所示:

删除元素的代码如下:

  1. /** 
  2.  * 根据数组下标删除元素 
  3.  * 
  4.  * @param index 数组下标 
  5.  * @return 
  6.  */ 
  7. public int delete(int index) { 
  8.     if (index < 0 || index > size) { 
  9.         throw new IndexOutOfBoundsException("已经超过数组容量 ! 插入失败!"); 
  10.     } 
  11.     int deleteElement = array[index]; 
  12.     // 从左到右,将元素向左移动一位 
  13.     for (int i = index; i < size - 1; i++) { 
  14.         array[i] = array[i + 1]; 
  15.     } 
  16.     size--; 
  17.     return deleteElement; 

总结

数组是使用一块连续的内存空间,存储相同类型的一组数据,其最大的优点是数组支持随机访问,是因为数组可以通过数组下标(寻址公式)快速访问对应元素,时间复杂度为O(1)。

数组在删除元素和插入元素这两个操作比较低效,是因为数组为了保持数据的连续性,会涉及到数据的挪动,平均时间复杂度为O(N)。

 

责任编辑:武晓燕 来源: 码上Java
相关推荐

2022-11-04 08:29:05

索引数据库JSON

2024-07-11 11:35:08

数组结构内部机制

2023-03-28 07:44:23

数据结构数组

2023-03-11 22:10:20

数据工程师算法数据库

2015-01-26 09:11:15

新数据中心FacebookFabric

2021-03-02 09:06:20

安全API授权

2019-10-29 08:59:16

Redis底层数据

2013-11-18 14:23:14

Json数据结构

2016-08-24 20:09:27

Linux数据结构位数组

2015-08-17 11:42:44

数据中心承重

2020-10-21 12:45:12

Redis数据结构

2024-03-26 09:23:22

自动驾驶轨迹

2024-04-07 13:24:47

2020-09-18 09:13:46

数据结构元素

2022-07-07 10:33:27

Python姿势代码

2020-12-23 10:10:23

Pythonweb代码

2022-06-22 09:44:41

Python文件代码

2009-12-11 10:30:31

2020-12-09 10:15:34

Pythonweb代码

2016-07-29 00:43:22

数据驱动
点赞
收藏

51CTO技术栈公众号