数据结构与算法基础

线性结构-数组

1、数组的基本概念

数组是由有限个相同类型的变量(或对象)组成的有序集合

数组是一种线性数据结构。即数组中各元素是按顺序线性排列的。

在这里插入图片描述
(1)数组有唯一的名称标识,通过数组名可以对数组元素进行引用,array[0]表示数组中的第一个元素“1”;
注意:数组的下标是从0开始的。
(2)数组中的元素类型必须相同;
(3)数组的内存单元是连续的,一个数组要占据一个地址连续的内存空间;
(4)数组中的元素都是顺序存放的,元素之间有先后关系,数组元素之间不能存在空隙。

数组是一种物理空间和逻辑形式都连续的线性数据结构。

2、数组的定义

以Java为例

# 定义 一个整型数组
int[] array;

上面只是申明了一个引用变量array,其本质还是一个指针,而该数组本身并不存在,即在内存中还没有开辟连续的内存空间。

  • 要使用该数组必须先进行初始化!!!

在Java中初始化数组分为静态初始化动态初始化

  • 静态初始化:在定义数组时显示地指定数组的初始值,系统会根据初始值的个数和类型自动为数组在内存中开辟空间
int[] array = {1,2,3,4,5}; //定义数组和初始化数组同时完成

或者

int[] array;					//定义数组
array = new int[] {1,2,3,4,5};	//初始化数组

上述代码执行完毕后,系统会在堆内存中分配5个int类型长度的内存空间,并为数组array初始化元素1,2,3,4,5。

  • 动态初始化:在初始化数组时仅仅指定数组的长度,不指定数组元素的初始值
int[] array = new int[5]; //定义数组和初始化数组同时完成

或者

int array[];   		//定义数组
array = new int[5]; //动初始化数组,只指定数组的长度

上述代码执行完毕后,系统会在堆内存中分配5个int类型长度的内存空间。
需要注意的是:动态初始化数组不会显示地为数组指定初始值,系统会该数组指定默认的初始值。

数组类的定义

public class MyArray {
    int[] array;        			//数组本身
    int elemNumber;     			//记录数组中元素的个数
    public MyArray(int capacity){
        array = new int[capacity];  //动态初始化数组,长度为capacity
        elemNumber = 0;             //数组中元素个数为0
    }

    //插入元素
    public boolean insertElem(int elem, int index){
        //在数组的第index位置上插入一个元素
        //......
        return true;
    }

    //删除元素
    public boolean deleteElem(int index){
        //删除数组中第index个位置上的元素
        // ......
        return true;
    }
}

该数组类中包含两个成员变量:
(1)array表示一个int[]类型的数组,通过array[index]可以引用数组中的元素;
(2)elemNumber表示数组中元素的数量。
在调用 MyArray(int capacity)构造函数初始化该函数后,elemNumber被赋值为0,表示数组已在堆内存中开辟了存储空间,但是没有存储数据。

注意:区分数组的容量capacity和数组中元素数量elemNumber

  • 数组的容量指数组在堆内存中开辟出的内存单元的数量,即上述代码中构造函数参数capacity所指定的大小,表=表示该数组中最多可以存放多少个元素;
  • 数组中元素的数量是变量elemNumber记录的数据,表示该数组中当前存储的有效元素的数量。
    在这里插入图片描述
    可以通过array.length()函数获取数组的容量,所以在MyArray类中不需要再定义一个变量专门记录数组的容量,但是变量elemNumber是必须的,因为数组的容量与数组中元素的个数并不一定相等,如上图所示,数组容量为5,单数数组中元素的个数为3。通过变量记录数组中有效元素的数量,防止从数组中取出无效值。

3、数组的基本操作

3.1 插入

public boolean insertElem(int elem, int index);//elem表示要插入的元素 index表示要插入的位置,规定插入位置从1开始

数组元素位置从1开始,则数组下标与数组元素的位置相差1。
在这里插入图片描述
在数组的index位置上插入元素,就是插入的这个新的元素要位于数组的第index位置上,原来第index位置上的元素以及后续元素均要顺序向后移动一个位置。
插入位置index取值要在[1,elemNumber+1]之间才有效!!

在这里插入图片描述
(1)移动数组元素时要从最后一个元素开始,从后向前移动,直到将第index个位置的元素向后移动一个位置,即最终index位置被空出来;
(2)将新的元素插入到数组的第index位置,即array[index-1]=elem;数组的下标与数组位置index之间差1;
在这里插入图片描述
注意:还需要将记录数组元素数量的变量elemNumber加1,数组中插入新的元素,总个数加1。

插入元素函数实现代码如下

//插入元素
    public boolean insertElem(int elem, int index) {
        //在数组的第index位置上插入一个元素
        //index取值范围[1,elemNumber+1]
        if (index < 1 || index > elemNumber + 1) {
            System.out.println("插入位置有误!");
            return false;
        }
        if (elemNumber == array.length) {
            System.out.println("数组容量达到上限,无法插入新元素!");
            return false; //数组容量满了,则不允许插入新元素
        }
        //将第index位置及其后续元素后移一位
        for (int i = elemNumber - 1; i >= index - 1; i--) {
            array[i + 1] = array[i];
        }
        //将新元素elem插入空出array[index-1]
        array[index - 1] = elem;    //array[index-1]即为数组的第index个元素
        elemNumber++;               //数组的元素数量加1
        return true;
    }

注意:如果插入位置为最后一个元素,即位置index为elemNumber+1,不满足循环条件 i >= index - 1;故不需要执行移动元素的操作。

测试代码

   public static void main(String[] args) {
        MyArray myArray = new MyArray(5);
        myArray.insertElem(3, 1);
        myArray.insertElem(4, 2);
        myArray.printArray();
        myArray.insertElem(0,2);
        myArray.printArray();
    }
    public void printArray() {
        for (int i = 0; i < elemNumber; i++){
            System.out.print(array[i] + " ");
        }
        System.out.println();
    }

运行结果:
在这里插入图片描述
注意:向数组中插入元素会存在数组容量满了,导致数组越界的情况!!

  • 方案1:当数组元素达到数组容量上限时,不允许插入元素,返回false;
 if (elemNumber == array.length) {
            System.out.println("数组容量达到上限,无法插入新元素!");
            return false; //数组容量满了,则不允许插入新元素
    }

缺点:限制了数组容量的大小,不够灵活~

  • 方案2:动态扩容的方法,当数组容量满了,则将数组的容量扩大。
    向数组中插入元素带扩容机制的Java代码如下:
 //插入元素
    public boolean insertElem(int elem, int index) {
        //在数组的第index位置上插入一个元素
        //index取值范围[1,elemNumber+1]
        if (index < 1 || index > elemNumber + 1) {
            System.out.println("插入位置有误!");
            return false;
        }
//        方案1:
//        if (elemNumber == array.length) {
//            System.out.println("数组容量达到上限,无法插入新元素!");
//            return false; //数组容量满了,则不允许插入新元素
//        }
//        方案2:
        if (elemNumber == array.length) {
            increaseCapacity();
        }
        //将第index位置及其后续元素后移一位
        for (int i = elemNumber - 1; i >= index - 1; i--) {
            array[i + 1] = array[i];
        }
        //将新元素elem插入空出array[index-1]
        array[index - 1] = elem;    //array[index-1]即为数组的第index个元素
        elemNumber++;               //数组的元素数量加1
        return true;
    }

扩容函数实现如下:

   public void increaseCapacity() {
        //初始化一下一个新的数组arrayTemp,其容量是array容量的2倍
        int[] arrayTemp = new int[array.length * 2];
        //将原数组array的整体内容拷贝到新数组arrayTemp中
        System.arraycopy(array, 0, arrayTemp, 0, array.length);
        array = arrayTemp; //array指向这个新数组
    }

3.2 删除

删除第index位置上的元素,只需要将第index位置之后的数据顺序向前移动一个位置,最后将数组元素数量减1。
数组的元素是不能删的,只能覆盖。
在这里插入图片描述注意:
(1)被删除元素的位置只能在[1,elemNumber]之间,其余均为非法位置!
(2)在移动数组元素时要从数组的第index+1个元素开始从前向后逐个移动,直到移动到第elemNumber个元素。
(3)数组的元素数量只能通过变量elemNumber记录,所以删除元素后要将elemNumber的值减1,保证数组下标在elemNumber-1之外的元素都是无效的。

从数组中删除元素

   //删除元素
    public boolean deleteElem(int index) {
        //删除数组中第index个位置上的元素
        //index的取值范围是[1,elemNumber]
        if (index < 1 || index > elemNumber) {
            System.out.println("删除元素位置非法!");
            return false;
        }
        //将index位置之后的元素顺序向前移动一个位置
        for (int i = index; i < elemNumber; i++) {
            array[i - 1] = array[i];
        }
        //数组元素数量减1
        elemNumber--;
        return true;
    }

4、数组性能分析

  • 优点:
    数组是一种可以随机访问的线性结构。由于数组存储于连续的地址空间,所以只要给定数组名(例如array)和数组下标,就可以用O(1)的时间复杂度直接定位到对应的元素。
  • 缺点:
    (1)数组中的元素是顺序存储的,在插入、删除元素时会有大量的元素移动,效率较低。在数组中插入或删除一个元素的时间复杂度都是O(n)级别的;
    (2)没有扩容功能的数组大小是固定的,在使用数组时容易出现越界问题。增加扩容机制后在一定程度上也导致了内存资源的浪费。

综上所述,数组比较适合读操作频繁,而插入、删除操作较少的场景。

  • 11
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值