算法通过村第三关-数组基础笔记|爱不起的数组

news2024/11/26 18:36:51

文章目录

  • 前言
  • 线性表的概念
    • 什么是线性表
      • 从语言实现的角度看
      • 从存储的角度看
      • 从访问限制的角度看
      • 从扩容的角度看
      • 数组的概念
      • 数组元素的特征
  • 数组的基本操作
    • 数组的创建和初始化
    • 查找一个元素
    • 增加一个元素
    • 删除一个元素
  • 总结


前言

提示:孩子们有时候挺伤人的,他们以为只要你恰好是个大人,你就刀枪不入,怎么也不会受伤。


谈起数组,都是令人头疼的问题,恶心的临界判断💣
当然了这里不是吐槽的,我们要把数组这一块学会的🥰,还是一步一步的来吧,先补习一下知识:

  1. 什么是线性表
  2. 数组的概念
  3. 数组元素的存储特征

线性表的概念

什么是线性表

先来谈谈常见的数据结构:
在这里插入图片描述
Q:当然了这就要问了,什么是线性表?
A:所谓的线性表就是具有相同特征元素的一个有限序列,其中所含元素的个数成为线性表的长度。

我们从多角度分析一下:

从语言实现的角度看

可以分为一体式和分离式
在这里插入图片描述

从存储的角度看

可分为顺序型和链表型:

顺序型:就是将数据存放在一段固定的区间内,此时访问元素的效率非常高,但是删除和增加元素的代价比较大,如果想扩容只能整体搬迁。

链表型:元素之间是通过地址依次连接的,因此访问时必须要从头开始逐步向后找,所以说查找的效率低,删除和增加的效果非常好,并不需要考虑扩容的问题。常见的链表实现方式:单链表,循环链表,双链表等等。

从访问限制的角度看

栈和队列又被称为访问受限的线性表,插入和删除受到了限制,只能在固定的位置进行。而Hash比较特殊,其内部真正存储数据的一般是数组,但是访问是通过映射来实现的,因此大部分材料里面比不将Hash归结到线性表中。

线性表的知识框架图:
在这里插入图片描述
线性表的常见问题:初始化、求表长、增删改查等、其本质就是上面的每种数据结构至少要有这几中操作,当然大部分的算法题目也是基于此扩展的。

从扩容的角度看

采用分离式结构的顺序表,若将数据更换为存储空间更大的区域,则可以在不改变表对象的前提下对其数据存储区进行扩容,所有使用这个表的地方都不必修改。只要程序的要运行环境(计算机系统)还有剩余,这种表结构就不会因为满了而导致无法进行操作。人们把采用这种技术实现的顺序表称为动态顺序表,因为其容量可以在使用中动态变化。

扩容的两种策略:

  1. 每次扩容增加固定的数目的存储位置,比如每次扩充10个元素位置,这种策略可以称为线性增长。特点是:节省空间,但是扩充操作频繁,操作次数多。
  2. 每次扩容容量加倍,比如每一次扩充增加一倍存储空间。特点是:减少了扩充操作的执行次数,但是可能会造成浪费空间资源。典型的以空间换时间,推荐的方式。(java)

数组的概念

数组是线性表最基本的结构,特点是元素是一个紧密在一起的序列,相互之间不需要记录彼此的关系就能访问,比如月份,星球等。

数组用索引的数组来标识每项数据在数组中的位置,且在大多数编程语言中,索引是从0 算起的。我们可以通过索引快速定位到数组中的元素。
在这里插入图片描述
数组有两点需要注意的:

  1. 索引从0开始 及第一个 存储元素的位置是a[0],最后一个存储元素的位置是a[length-1]。
  2. 数组中的元素在内存中是连续存储的,且每个元素占用相同的大小内存。

在这里插入图片描述
注意:数组空间不一定是满的,100的空间可能只用了10个位置,所以要注意数据个数的变化size和数组长度length可能不一样。

数组元素的特征

数组中的经典问题:

Q:我创建了一个大小为10的数组,请问此时数组里面是什么?

A:在Java里面,会默认初始化为0.

Q:是否可以只初始化一部分位置?初始化的本质是什么?

A:当然可以,你可以将前面5个位置赋值,后面的空着。比如数组内容{1,2,3,4,5,0,0,0,0,0}.初始化的本质就是覆盖已有的值,你需要的值覆盖原来的0,因为数组本来是{0,0,0,0,0,0,0,0,0,0}.这里只是做了替换。因此你想要知道有效元素的个数,就必须有一个额外的变量,例如size来标记。

Q:那么上面已经初始化的元素之间是否可以空着,比如这样{1,0,0,2,0,3,8,3,9},0表示还没有初始化的数据。

A:不可以! 当然不可以这么做。要初始化,就必须从前向后的连续空间初始化,不可以出现空缺的情况,这里违背数组的原则。你在进行某种运算期间可以先给一部分位置赋值,而一旦稳定了,就不再可能在出现空位置的情况。

Q:如果我需要的数据在中间的某一段该怎么办?比如{0,0,0,3,4,5,5,67,0,0,0},此时我想获取3-67的元素呢?

A:你需要使用两个变量,例如left = 3 ,right = 7 来表示区间[left,right]是有效的。

Q:我删除的时候,已经被删除的位置该是什么呢?例如原始数组为{1,2,3,4,5,0,0},我删除了4之后,根据数组的移动原则,从4开始向前移动,变成{1,2,3,5, ?,0,0},原来5的位置应该是什么呢?

A:还是5,也就是删除4之前的结构是{1,2,3,5, 5,0,0},此时便是元素数量的size会建议变成4,原来5的位置还是5,因为我们是通过size来标记元素数量的,所以最后一个5不会呗访问到。

Q:这里的5看起来不好看,可以用来再优化一下?

A:不必要,没啥用。

数组的基本操作

当然在面试中,大多使用int类型,所以这里我们就使用int来举例啦🤣

数组的创建和初始化

int[] arr = new int[10];

数组最基础的初始化就是循环赋值

for(int i = 0; i < arr.length, i++)
    arr[i] = i;

但是这种方式在面试题中一般不行,因为很多题目会给出若干测试数据组让你都能测试通过,比如给你[0,1,2,3,4,5,6]和[0,3,4,5,6,1]。这样的时候怎么初始化最优呢?

显然这里不能使用循环了,too low😒,可以试试一下的写法

int[] arr = new int[]{0,1,2,3,4,5,6};
// 也可以这样写
int[] arr = {0,3,4,5,6,1};//背下来  记住 ⭐⭐⭐⭐⭐

这样的化,如果测试第二组数据,直接将其替换就行,并且简单方便,在面试中也是比较常用的,牢记⭐,

注意:创建数组时大小就是元素的数量,是无法再插入元素的,如果你需要增加新的元素就不能这么用。

查找一个元素

我们探讨一下💡为什么数组的题目这么多呢?

其实多数题目的本质实在查找问题,而数组时查找的最佳载体。很多复杂的算法都是为了提高查询效率的,比如二分查找,二叉树,红黑树,B+树,Hash和堆等等。另一方面很多算法的本质也是查找问题,就比如滑动窗口问题,回溯问题,动态规划问题等待都是再寻找目标结果。

这里简单的写一个等值查找,实现如下:

 /**
     * @param arr
     * @param size 已经存放的元素容量
     * @param key  待查找的元素
     * @return
     */
    public static int findByElement(int[] arr, int size, int key) {
        // 参数校验
        if (arr == null || size == 0) {
            return -1;
        }
        for (int i = 0; i < size; i++) {
            if (arr[i] == key) {
                return i;
            }
        }
        return -1;
    }

增加一个元素

增加和删除元素时数组最基本的操作,看别人的代码很容易,但是自己写代码的时候,你就知道了“纸上谈兵”😥。能准确的处理游标和边界等情况是数组算法最基础重要的问题之一。所以当然需要自己亲手写一边才可以,不要觉得简单就不去做,当真正用的时候才后悔,这样得不偿失。

将给给定的元素插入到有序的数组的对应位置中,我们可以先找到位置,然后再其后的元素整体右移,最后插入到空位上。这里需要注意的是,算法必须保证在数组的首部,尾部,中部插入都可以成功。问题貌似采用一个for循环就可以解决,但是当你写出来运行时,傻眼了☠️,各种bug出现,很恶心。

推荐一种方式,你可以这样写⭐。(保证数组的单调性)

/**
     * @param arr
     * @param size    数组已经存储的元素数量
     * @param element 待插入的元素元素
     * @return
     */
    public static int addByElementSequence(int[] arr, int size, int element) {
        // 校验参数
        if (arr == null || arr.length == 0) {
            return -1;
        }
		// 这里不能是 大于 等于的时候也是
        // 数组的下标是从 0 开始的
        // size 记录有效元素 1 开始的   arr.length 记录数组的长度   从 1 开始
        if (size >= arr.length) {
            return -1;
        }
        //这里是为了保持单调性  即 index != 0/arr.length - 1
        int index = size;
        // 找到新元素插入的位置
        for (int i = 0; i < size; i++) {
            if (element < arr[i]) {
                index = i;
                break;
            }
        }
        // 元素后移
        for (int j = size; j > index; j--) {
            arr[j] = arr[j - 1]; // index下标的元素后移一个位置
        }
        arr[index] = element;
        return index;

    }

删除一个元素

对于删除元素,不可以一边遍历一边查找,因为元素可能不存在。所以要分为两个步骤,先检查元素是否存在元素,存在再删除。

需要考虑多种情况,首部,中部,尾部,不存在都要有效,推荐这样写🥰

  /**
     * 遍历数组,如果发现目标元素,则将其删除,
     * 数组的删除就是从目标元素开始,用后续元素依次覆盖前继元素
     *
     * @param arr  数组
     * @param size 数组中的元素个数
     * @param key  要删除的目标值
     */
    public static int removeByElement(int[] arr, int size, int key) {
        // 参数校验
        if (arr == null || arr.length == 0){
            return -1;
        }
        int index = -1;
        // 找到要删除元素的位置
        for (int i = 0; i < size; i++) {
            if (arr[i] == key) {
                index = i;
                break;
            }
        }
        if (index != -1) {
            for (int j = index + 1; j < size ; j++) {
                arr[j - 1] = arr[j];
            }
            size--;
        }

        return  size;
    }

总结

提示:不要觉得数组很简单,真的自己写一写才知道。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/872551.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

两个数组的交集-C语言/Java

描述 给定两个数组 nums1 和 nums2 &#xff0c;返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序。&#xff08;1 < nums1.length, nums2.length < 1000&#xff0c;0 < nums1[i], nums2[i] < 1000&#xff09; 示例1 输入…

Linux源码剖析匿名共享内存shmem原理

如下问题如果都清楚了就不用看本文了&#xff1a; 1. shmem ram文件系统的初始化流程是怎样的 2. shmem思想上想复用基于文件的操作流程&#xff0c;实现上shmem也引入了一个文件&#xff0c;那么类似文件open会生成struct file&#xff0c;shmem的struct file怎么生成的 3.…

C语言 棱形图案

目录 一、问题分析 上部分&#xff1a; 下部分&#xff1a; 二、代码演示 一、问题分析 如上图所示&#xff0c;我们可以将棱形进行拆解&#xff0c;分为上下两个部分。 上部分&#xff1a; 通过观察&#xff0c;我们得到 单边空格数 上半部分总行数 - 行数 - 1 …

graphab 教程 ——安装

graphab 软件致力于从图论的框架对生态网络进行建模。Graphab是基于图论原理建立生态网络模型的软件,它可以实现景观组分可视化、连通性分析等,且易于与地理信息系统兼容。Graphab 是基于Java平台开发的,可直接在 Windows、Linux,Mac等操作系统中运行,界面友好且易于使用。Grap…

HCIP学习--BGP实验

一、实验拓扑 二、实验需求 除R5的5.5.5.0环回外&#xff0c;其他所有的环回均可互相访问 三、实验步骤 首先配置IP&#xff0c;配置好IBGP 建立直连的EBGP邻居关系 R1和R2建立直连的EBGP邻居关系 [r1]bgp 1 [r1-bgp]router-id 1.1.1.1 [r1-bgp]peer 12.1.1.2 as-number …

MyBatis插件开发

目录 一、项目简单搭建二 、一个接口了、两大注解、四大对象三、脱敏插件开发 一、项目简单搭建 demo结构&#xff0c;已经搭建了无数次了&#xff0c;懒的粘贴了 o(╥﹏╥)o pom文件 <dependency><groupId>org.springframework.boot</groupId><artifa…

AIGC商用实例—大模型技术助力AI测谎仪,实现视频通话实施测谎!

大家好&#xff0c;我是千寻哥&#xff0c;最近一段时间&#xff0c;给大家分享了不少的AI绘画相关的项目教程&#xff0c;很多星友都反映真的不错&#xff0c;我自己也是感觉很有意义&#xff01; 哈哈哈&#xff0c;今天我在看到了一个项目柑感觉是一个不错的idea&#xff0c…

下一代深度学习的思考与若干问题

下一代深度学习的思考和若干问题

OpenCV基本操作——图像的基础操作

目录 图像的IO操作读取图像显示图像保存图像 绘制几何图形绘制直线绘制圆形绘制矩形向图像中添加文字效果展示 获取并修改图像中的像素点获取图像的属性图像通道的拆分与合并色彩空间的改变 图像的IO操作 读取图像 cv2.imread()import numpy as np import cv2 imgcv2.imread(…

Postman: 前端必备工具还是后端独享利器

目录 Postman 的使用场景&#xff1a;适用于前端和后端 Postman 适用于前端的场景 Postman 适用于后端的场景 结论 Postman 的使用场景&#xff1a;适用于前端和后端 Postman 是一个流行的 API 测试与开发工具。它被广泛地应用在前后端开发的过程中&#xff0c;但是很多人…

SCAU操作系统知识点之(八)虚拟内存

1、虚拟地址概念&#xff0c;实地址概念 实存储器&#xff08;实存&#xff09;&#xff1a;内存 虚存储器&#xff08;虚存&#xff09;&#xff1a;磁盘 虚拟地址&#xff1a;在虚拟内存中分配给某一位置的地址&#xff0c;它使得该位置可被访问&#xff0c;就好像是主内的一…

机器学习---对数几率回归

1. 逻辑回归 逻辑回归&#xff08;Logistic Regression&#xff09;的模型是一个非线性模型&#xff0c; sigmoid函数&#xff0c;又称逻辑回归函数。但是它本质上又是一个线性回归模型&#xff0c;因为除去sigmoid映射函 数关系&#xff0c;其他的步骤&#xff0c;算法都是…

网络中的一些基本概念整理总结

1.IP地址 是用来定位主机的网络地址,主要是用于标识主机和其他的一些网络设备. 比如路由器是用点分十进制来表示的 2.端口号 用于标识网络协议中不同的服务或应用程序。 3.协议 这里主要说网络协议,是网络通信时,所有经过的网络设备都必须遵守的一套规定,包含怎么建立连接…

机器学习笔记:李宏毅diffusion model

1 概念原理 首先sample 一个都是噪声的vector然后经过denoise network 过滤一些杂质接着继续不断denoise&#xff0c;直到最后出来一张清晰图片 【类似于做雕塑&#xff0c;一开始只是一块石头&#xff08;噪声很杂的雕塑&#xff09;&#xff0c;慢慢雕刻出想要的花纹】 同一个…

简单易懂的 Postman Runner 参数自增教程

目录 什么是 Postman Runner&#xff1f; Postman Runner 如何实现参数自增&#xff1f; 步骤一&#xff1a;设置全局参数 步骤二&#xff1a;将全局参数带入请求参数 步骤三&#xff1a;实现参数自增 资料获取方法 什么是 Postman Runner&#xff1f; Postman Runner 是…

Redis集群 (三十九)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、Redis主从复制 1.1 概念 1.2 作用 1.3 缺点 1.4 流程 1.5 搭建 1.6 验证 二、Reids哨兵模式 2.1 概念 2.2 作用 2.3 缺点 2.4 结构 2.5 搭建 2.6 验证 三、Red…

一文揭秘饿了么跨端技术的演进、实践与落地

跨端技术背景与演进历程 跨端&#xff0c;究竟跨的是哪些端&#xff1f; 自 90 年的万维网出现&#xff0c;而后的三十多年&#xff0c;我们依次经历了 PC 时代、移动时代&#xff0c;以及现在的万物互联&#xff08;的 IoT &#xff09;时代&#xff0c;繁荣的背后&#xff…

SpringBoot后端服务开启Https协议提供访问(使用阿里云资源)

目录 概述 申请/下载证书 部署证书 本地测试访问 服务器部署访问 最后/扩展 总结 概述 本篇博客说明如何将SpringBoot项目开启Https协议提供访问。 博文以步骤【申请/下载证书】&#xff0c;【部署证书】&#xff0c;【本地测试访问】&#xff0c;【服务器部署访问】 &a…

linux0.95(VFS重点)源码通俗解读(施工中)

文件系统在磁盘中的体现 下面是磁盘的内容&#xff0c;其中i节点就是一个inode数组&#xff0c;逻辑块就是数据块可用于存放数据 操作系统通过将磁盘数据读入到内存中指定的缓冲区块来与磁盘交互&#xff0c;对内存中的缓冲区块修改后写回磁盘。 进程(task_struct * task[N…

Python系统学习1-7-字典

一、字典 1、概念及内存图 列表&#xff1a;由一系列变量组成的可变序列容器字典&#xff1a;由一系列键值对组成的可变散列容器字典优势&#xff1a;利用&#xff08;内存&#xff09;空间&#xff0c;换取&#xff08;CPU查找&#xff09;时间 键key 必须唯一且为不…