一起学数据结构和算法(二)| 数组(线性结构)

数组(Array)

数组是最基础的数据结构,在内存中连续存储,支持随机访问。适用于需要频繁按索引访问元素的场景。


简介

数组是一种线性结构,将相同类型的元素存储在连续的内存空间中。每个元素通过其索引值(数组下标 index)来进行唯一标识和访问。

核心特性

  1. 固定大小:在绝大多数语言中,数组创建后大小固定不变
  2. 连续内存:元素在内存中顺序存储,无额外开销
  3. 随机访问:O(1)时间复杂度直接访问任意元素
  4. 同质性:同意数组中所有元素类型相同
  5. 索引访问:通过数字索引访问元素

基本操作

时间复杂度分析
操作 时间复杂度
访问 O(1)
更新 O(1)
遍历 O(n)
搜索 无序数组O(n);有序数组O(log n)(二分查找)
插入/删除 在末尾O(1);在数组指定位置O(n)(需要移动元素)
代码实现
java 复制代码
// 声明和初始化
int[] numbers = new int[5];  // 创建一个长度为5的int数组,默认值都是0
int[] primes = {1, 9, 78, 25, 3};  // 直接使用初始值创建数组

// 访问元素
int firstPrime = primes[0];  // 得到1

// 更新元素
numbers[0] = 10;

// 获取数组长度
int length = numbers.length;

// 遍历数组
for (int i = 0; i < primes.length; i++) {
    System.out.println(primes[i]);
}

// 使用增强for循环遍历
for (int prime : primes) {
    System.out.println(prime);
}

/* 随机访问元素 */
int randomAccess(int[] nums) {
    // 在区间 [0, nums.length) 中随机抽取一个数字
    int randomIndex = ThreadLocalRandom.current().nextInt(0, nums.length);
    // 获取并返回随机元素
    int randomNum = nums[randomIndex];
    return randomNum;
}

优缺点

优点
  • 空间效率高:数组为数据分配了连续的内存块,无需额外的结构开销
  • 支持随机访问:数组允许在 O(1) 时间内访问任意元素
  • 缓存局部性:当访问数组元素时,计算机不仅会加载该数组,还会缓存其周围的其他数据,从而借助高速缓存来提升后续操作的执行速度
缺点
  • 插入与删除效率低:当数组中的元素较多时,插入/删除元素都得移动大量的元素
  • 长度不可变:数组在初始化后长度就固定了,扩容数组需要将原数组所有数据复制到新数组,开销很大
  • 空间浪费:如果数组空间分配大小超过了实际所需,多余空间容易浪费

应用场景

  • 随机访问:如果需要随机抽取一些样本,可以用数组存储,并生成一个随机序列,根据索引实现随机抽样
  • 排序和搜索:数组是排序和搜索算法中常用的数据结构。快速排序、归并排序、二分查找等都主要在数组上进行
  • 查找表:当需要快速查找一个元素或其对应关系时,可以使用数组作为查找表。如实现字符到 ascii 码的映射,可以将字符的 ascii 值作为索引,对应元素存放在数组中对应位置
  • 机器学习:神经网络中使用了大量的向量、矩阵、张量之间的线性代数运算,这些数据都是以数组的形式构建的。数组是神经网络编程中最常用的数据结构
  • 数据结构实现:数组可以用于实现栈、队列、哈希表、堆、图等数据结构

扩展

  • 二维数组
  • 多维数组

热门题目

53. 最大子数组和

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组是数组中的一个连续部分。

示例:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]

输出:6

解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

题解

动态规划

分而治之,避免重复计算

  1. 初始化
    1. maxSum 设置为数组第一个元素
    2. currentSum 也设置为第一个元素(子数组最少包含一个元素)
  2. 遍历数组
    1. 从第二个元素开始遍历
    2. 对于每个元素 nums[i],有两种选择:
      1. 将其加入到之前的子数组,即 currentSum + nums[i]
      2. 重新开始一个子数组,只包含当前元素,即 nums[i]
    3. 选择最大的作为新的 currentSum
    4. 最后,更新 maxSum,保证其是currentSummaxSum中最大的值
java 复制代码
class Solution {
    public int maxSubArray(int[] nums) {
        int maxSum = nums[0];
        int currentSum = nums[0];

        for(int i = 1; i < nums.length; i++) {
            // 是将当前元素加入到之前的子数组,还是重新开始一个子数组
            currentSum = Math.max(currentSum + nums[i], nums[i]);
            // 更新最大子数组和
            maxSum = Math.max(currentSum, maxSum);
        }

        return maxSum;
    }
}

参考资料

1\] [Hello 算法](https://www.hello-algo.com/) \[2\] [算法导航](https://algo.codefather.cn/)

相关推荐
1白天的黑夜1几秒前
数据结构之堆(topk问题、堆排序)
c语言·数据结构·算法
加什么瓦20 分钟前
Java—多线程
java·开发语言
野木香22 分钟前
idea使用笔记
java·笔记·intellij-idea
bing_15829 分钟前
在 Spring Boot 项目中如何合理使用懒加载?
java·spring boot·后端
枫景Maple31 分钟前
LeetCode 1871. 跳跃游戏 VII(中等)
算法·leetcode
L下自成蹊L34 分钟前
2. 数据结构基本概念 (2)
数据结构·算法·面试·数据结构与算法基础
CN.LG35 分钟前
MyBatis 的动态 SQL 特性来实现有值字段才进行插入或更新
java·sql·mybatis
lyh13441 小时前
【JavaScript 性能优化方法】
java
小羊在奋斗1 小时前
【LeetCode 热题 100】打家劫舍 / 零钱兑换 / 单词拆分 / 乘积最大子数组 / 最长有效括号
算法·leetcode·职场和发展
皮皮虾我们跑1 小时前
Java开发——三层架构,分层耦合
java·架构