专栏学习笔记03 数据结构与算法入门-----数组

学习目标

为什么数组从0开始编写

数组如何实现随机访问

概念

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

核心概念理解

线性表:

数据排成像一条线一样的结构。每个线性表上的数据最多只有前和后两个方向。(链表、队列、栈等也是线性表结构)
在这里插入图片描述
非线性表,数据之间并不是简单的前后关系,如二叉树、堆、图等。
在这里插入图片描述

连续的内存空间和相同类型的数据:

连续则说明这段空间是不可间断的,相同类型则说明所存储的数据要是类型一致的,不能有其他类型放在同一数组里面

特征

随机访问。正是因为以上的两个特性,数组有了随机访问这个特征。,但对数组进行删除插入,为了保证数组的连续性,就要做大量的数据搬移工作

问题的解决

通过下标随机访问过程

我们拿一个长度为10的int类型的数组int [] a =new int[10]来举例。
在这里插入图片描述如图所示,计算机给数据a[10],分配了一块连续内存空间1000~1039,其中,内存块的首地址为base_address=1000。

计算机会给每一个内存单元分配一个地址,计算机通过地址来访问内存中的数据。
当计算机需要随机访问数组中的某个元素时,它会首先通过下面的寻址公式,计算出该元素存储的内存地址:

a[i]_address = base_address + i * data_type_size

其中,data_type_size表示数组中每个元素的大小。如果数组中存储的是int类型数据,所以data_type_size的大小就为4个字节。

从0开始的原因:

1、减少CPU运算负担,少了一次减法运算指令
如:
从0开始内存地址计算方式:

a[k]_address = base_address + k * type_size

从1开始内存地址计算方式:

a[k]_address = base_address + (k-1)*type_size

2、历史原因

常见的方法

增删改查

插入操作(根据索引)

大致流程:找到位置→移动元素→插入
代码如下:

 public boolean insert(int index, int value){
        // 数组空间已满
        if (count == n) {
            System.out.println("没有可插入的位置");
            return false;
        }
        // 如果count还没满,那么就可以插入数据到数组中
        // 位置不合法
        if (index < 0||index > count ) {
            System.out.println("位置不合法");
            return false;
        }
        // 位置合法
        //移动元素
        for( int i = count; i > index; --i){
            data[i] = data[i - 1];
        }
        //插入值
        data[index] = value;
        //空间++
        ++count;
        return true;
    }

时间复杂度分析:

1、在数组末尾处添加,不需要移动,此时时间复杂度为O(1)
2、在数组开头处添加,需要移动,此时时间复杂度为O(n)
3、平均时间复杂度为O(n)

删除操作 (根据索引)

大致流程:找到要删除的元素→移动元素
代码如下

 public boolean insert(int index, int value){
        // 数组空间已满
        if (count == n) {
            System.out.println("没有可插入的位置");
            return false;
        }
        // 如果count还没满,那么就可以插入数据到数组中
        // 位置不合法
        if (index < 0||index > count ) {
            System.out.println("位置不合法");
            return false;
        }
        // 位置合法
        //移动元素
        for( int i = count; i > index; --i){
            data[i] = data[i - 1];
        }
        //插入值
        data[index] = value;
        //空间++
        ++count;
        return true;
    }

时间复杂度分析:

1、在数组末尾处删除,不需要移动,此时时间复杂度为O(1)
2、在数组开头处删除,需要移动,此时时间复杂度为O(n)
3、平均时间复杂度为O(n)

查询操作

大致流程:找到需要查询的下标→显示结果

    //根据索引,找到数据中的元素并返回
    public int find(int index){
        if (index<0 || index>=count) return -1;
        return data[index];
    }

改进方法:

插入操作(不需要移动元素版本)

核心:替换
具体过程:创建一个新的空间→将原值放置到新空间→新元素插入
如图所示:
在这里插入图片描述

删除操作(累计触发)

在这里插入图片描述
如上图所示,当我们要依次删除 a,b,c 三个元素。
为了避免d,e,f,g,h这几个数据被移动三次,可以先记录下已经删除的数据。每次的删除操作并不是真正地搬移数据,只是记录数据已经被删除。当数组没有更多空间存储数据时,我们再触发执行一次真正的删除操作。
形似JVM,

联系

数组是一个基础的数据结构,在查询方面的优势较为明显,也比较通俗易懂,但是在插入与删除方面,效率较为低下,所以,需要另一种数据结构来解决这个问题。

注意事项

数组越界问题

数组与链表的区别

典型错误:
链表适合插入、删除,时间复杂度O(1);数组适合查找,查找时间复杂度为O(1)
解析:数组是适合查找操作,但是查找的时间复杂度并不为O(1)。排好序的数组,用二分查找,时间复杂度O(logn)。
正确的表述:
数组支持随机访问,根据下标随机访问的时间复杂度为O(1)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值