当前位置: 首页 > news >正文

【基础巩固】详细总结对数组的理解

在这里插入图片描述

本篇文章需要分析如下的问题

    • 一、数组的定义
    • 二、数组有哪些特点?
    • 三、数组的插入、查找、删除元素时间复杂度如何分析?
      • 3.1、插入操作
      • 3.2、删除操作
    • 四、数组在使用过程中需要注意什么?
    • 五、数组和容器类ArrayList的区别是什么?它们各自的优缺点是什么?
    • 六、数组下标为什么是从0开始的?

一、数组的定义

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

在这里,线性表的意思是,数据像一条线一样组织起来的,每个线性表上的数据只有向前和向后两个方向,比如数组、链表、队列、栈等;而非线性表就比如树、堆、图之类的。

二、数组有哪些特点?

  • 需要连续的内存空间,如果要删除或者插入一个数据,就需要做数据搬移的工作;
  • 存储相同的数据类型;
  • 随机访问,数组任意位置的地址计算为a[i]_address = base_address + i * data_type_size
  • 数组查找的时间复杂度只有在随机访问的时候才是O(1),使用二分查找时间复杂度则是O(logn);

三、数组的插入、查找、删除元素时间复杂度如何分析?

3.1、插入操作

  • 有序数组

    对于有序数组,最好和最坏情况下完成插入操作的时间复杂度分别是O(1)和O(n),那么平均下来的时间复杂度就是(1+2+3+......+n)/n=O(n)

  • 无序数组

    对于无序的数组,为了避免大规模的数据搬移工作,我们可以把原来第k位的元素搬移到最后,把需要插入到第k个位置的值插入,如此,时间复杂度将从O(n)变为O(1);

3.2、删除操作

删除操作在最好和最坏情况下的时间复杂度为O(1)和O(n),平均时间复杂度也是O(n),那有什么办法可以优化删除操作,减少搬运数据的过程,提高效率呢?

我们完全可以将多次删除操作集中在一起进行。当一开始删除时,我们可以将待删除的元素标记为已删除,等到数组已分配空间不够用的时候,触发一次清除操作和搬运数据操作。

四、数组在使用过程中需要注意什么?

在C语言中,数组越界会使得程序陷入无限死循环;

在高级语言中,比如Java,会抛出运行时异常ArrayIndexOutOfBoundsException;

建议在程序中,使用数组中元素时,都需要做越界检查,或者捕获该异常进行处理。

五、数组和容器类ArrayList的区别是什么?它们各自的优缺点是什么?

ArrayList和数组有什么区别,它们各自的优缺点是什么,以及在什么场景下使用哪个比较合适?

首先,ArrayList的底层实现就是基于数组的,但是它封装了很多数组的实现,比如插入元素和删除元素,我们直接调用add和remove即可,不用关心数据的搬移和优化等操作。

其次,ArrayList是可以自动扩容的,每次扩容都是原来的1.5倍,而数组一旦初始化好空间了,就不能更改大小,除非自己申请一块更大的连续内存空间,再手动搬运数据。ArrayList把扩容和搬运数据的操作都封装起来了,使用起来更加便捷。然而,每次扩容都涉及申请空间和搬运数据,所以,如果一开始能确定数据大小的话,就尽量就指定大小。

List<String> sl = new ArrayList<String>(100); 

然后,ArrayList的泛型只支持封装类,不支持基本数据类型,比如Integer、Long,对于如下的操作都会有自动装箱和拆箱操作,会损耗一定的性能。

List<String> sl = new ArrayList<String>(100); 
sl.add(15);
int num = sl.get(1);

还有,如果你能提前确定好数组的大小,并且代码逻辑很简单,用不着ArrayList的方法,那么就可以直接使用数组,而不是容器。如果你想要用到二维数组,也推荐使用数组,而不是容器,因为int[][]明显比ArrayList<ArrayList<>>更加的直观。

最后,对于平常的业务逻辑开发,建议使用容器类,比较简单省心,一点点的性能损耗对于整个应用来说算不得什么;但是如果你是用来写一些公共的底层方法,需要考虑很高的性能,那么就推荐使用数组。

六、数组下标为什么是从0开始的?

  • 方便寻址。比如上面说到寻址公式为a[i]_address = base_address + i * data_type_size,倘若下标从1开始,那么寻址公式就要改为a[i]_address = base_address + (i-1) * data_type_size,这样,每次数组随机访问寻址就会多一次减法操作,数组是系统中使用最为频繁的数据结构,这一点点的性能提升对整个系统来说就是很可观的。
  • 历史原因。C语言最先是这么设计的,然后其它高级语言都是基于C语言而来,所以也就继承了这一特点。但是也有例外,比如Matlab和Python。

相关文章:

  • ⌈Linux_ 感受系统美学⌋ 剖释“Linux下一切皆文件” ,底层级操作增进Linux内功
  • 哪些是模糊用语-《软件方法》自测题解析020
  • 【设计模式】-创建型模式-第2章第5讲-【对象池模式】
  • 125款浪漫七夕表白网站源码【建议收藏】HTML+CSS+JavaScript
  • 基于JAVA忻府区饭中有豆粮油销售系统计算机毕业设计源码+系统+数据库+lw文档+部署
  • 毕业设计 基于单片机的风速测量系统 - 物联网 嵌入式 stm32 arduino
  • 【MSP430G2553】图形化开发笔记(4) Timer_A 定时器
  • 【老板要我啥都会】|前端升全栈之项目使用express重构项目(上篇)
  • SpringMVC之使用SpringMVC获取参数与返回数据
  • (附源码)spring boot车辆管理系统 毕业设计 031034
  • 【Linux】关于Linux中的权限
  • 【FPGA教程案例92】图像处理1——基于FPGA的图像形态学膨胀处理实现,使用MATLAB辅助测试
  • 基于LabVIEW的温度计程序实现
  • 10.3 串口实验(A7核和M4核)
  • 使用Java实现一个定时器
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • 【Amaple教程】5. 插件
  • 【剑指offer】让抽象问题具体化
  • Java比较器对数组,集合排序
  • jQuery(一)
  • js算法-归并排序(merge_sort)
  • PAT A1050
  • pdf文件如何在线转换为jpg图片
  • Python学习之路13-记分
  • 简单基于spring的redis配置(单机和集群模式)
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 名企6年Java程序员的工作总结,写给在迷茫中的你!
  • 手机端车牌号码键盘的vue组件
  • 跳前端坑前,先看看这个!!
  • 微服务入门【系列视频课程】
  • 文本多行溢出显示...之最后一行不到行尾的解决
  • 我建了一个叫Hello World的项目
  • 如何用纯 CSS 创作一个菱形 loader 动画
  • #laravel 通过手动安装依赖PHPExcel#
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • (12)Linux 常见的三种进程状态
  • (13)[Xamarin.Android] 不同分辨率下的图片使用概论
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (done) 两个矩阵 “相似” 是什么意思?
  • (Java数据结构)ArrayList
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (安全基本功)磁盘MBR,分区表,活动分区,引导扇区。。。详解与区别
  • (二)Linux——Linux常用指令
  • (附源码)springboot家庭装修管理系统 毕业设计 613205
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (十五)使用Nexus创建Maven私服
  • (学习日记)2024.04.04:UCOSIII第三十二节:计数信号量实验
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • *Algs4-1.5.25随机网格的倍率测试-(未读懂题)
  • .net core 控制台应用程序读取配置文件app.config
  • .NET Standard、.NET Framework 、.NET Core三者的关系与区别?
  • .NET 解决重复提交问题
  • .Net的C#语言取月份数值对应的MonthName值
  • .NET简谈设计模式之(单件模式)
  • .NET设计模式(7):创建型模式专题总结(Creational Pattern)