数组知识

一、数组的概述

定义与特点

数组是相同类型数据元素的有序集合,存储在连续内存空间中。其特点包括:

元素类型相同,索引从0开始。

长度固定,初始化后不可修改。

支持快速随机访问(时间复杂度O(1))。

分类

一维数组:线性结构,如 int arr = {1, 2, 3};。

二维数组:可视为“数组的数组”,常用于矩阵或表格,如 int matrix = new int33;。

多维数组:更高维度的扩展,如三维数组。

二、一维数组的初始化、遍历与默认值

初始化

静态初始化:直接指定元素值,如 int arr = {1, 2, 3};。

动态初始化:指定长度后赋值,如 int arr = new int5;(默认值为0)。

遍历方式

循环遍历:通过索引访问,如 for (int i = 0; i < arr.length; i++)。

增强型循环(如Java的for-each):for (int num : arr)。

迭代器/指针遍历:适用于特定语言(如C++的指针)。

默认初始化值

基本类型:数值型为0,布尔型为false,字符型为\u0000^。

引用类型:默认值为null(如String)。

三、一维数组的内存解析

内存分配

栈内存:存储数组引用变量(如arr)。

堆内存:存储实际数组元素,连续分配。

示例

java

int arr = new int3;

// 栈中存引用arr,堆中分配连续12字节(int占4字节)

修改元素时,直接操作堆内存地址。

四、二维数组的初始化、遍历与默认值

初始化

静态初始化:直接指定内层数组,如 int matrix = {{1, 2}, {3, 4}};。

动态初始化:指定外层长度,内层可动态分配,如 int matrix = new int2;。

遍历方式

嵌套循环:外层循环行,内层循环列,如:

java

for (int i = 0; i < matrix.length; i++) {

for (int j = 0; j < matrixi.length; j++) {

    System.out.print(matrixij);

}

}

默认初始化值

外层元素:若未初始化内层数组,默认值为null。

内层元素:同于一维数组(如数值型为0)。

五、二维数组的内存解析

内存结构

二维数组是外层数组引用内层数组的结构,如 matrix0 指向第一个一维数组。

内存中仍为连续分配,但外层数组元素存储的是内层数组的地址。

示例

java

int matrix = new int23;

// 外层数组长度2,每个元素指向一个长度为3的一维数组

六、常见算法操作

特征值计算

特征值用于矩阵分析,通过求解方程 Ax = λx 获得。

应用场景:主成分分析(PCA)、图像处理。

数组赋值与复制

赋值:直接传递引用(如 arr2 = arr1,修改会影响原数组)。

复制:创建新对象(如 System.arraycopy() 或循环赋值)。

反转、扩容与缩容

反转:首尾交换元素(时间复杂度O(n))。

扩容/缩容:创建新数组并复制数据(如Java的Arrays.copyOf())。

查找与排序

查找:顺序查找(O(n))、二分查找(O(log n))。

冒泡排序:相邻元素比较交换,时间复杂度O(n²)。

快速排序:分治策略,平均时间复杂度O(n log n)。

七、Arrays工具类与常见异常

Arrays工具类

常用方法:

sort():排序

binarySearch():二分查找

toString():数组转字符串。

常见异常

越界异常:访问不存在的索引(如arr5,数组长度为5时)。

空指针异常:操作未初始化的数组(如int arr; arr0 = 1;)。

Java数组常见及进阶面试题解析

一、常见基础面试题

数组声明与初始化

题目:如何声明并初始化一维/二维数组?

解析:

一维数组:int arr = new int5(动态初始化)或 int arr = {1, 2, 3}(静态初始化)。

二维数组:int matrix = new int34,内存中按行优先存储,可通过行和列索引访问。

注意点:数组长度固定,初始化后不可修改。

数组遍历与操作

题目:如何遍历数组并打印元素?

解析:

使用普通for循环(需控制索引范围)或增强型for循环(仅需访问元素值)。

示例代码:

java

int arr = {1, 2, 3};

for (int num : arr) {

System.out.print(num + " ");

}

陷阱:避免数组越界异常(ArrayIndexOutOfBoundsException),需确保索引在0, length-1范围内。

数组排序与查找

题目:如何对数组排序?如何实现二分查找?

解析:

排序:使用Arrays.sort(arr)(默认升序,支持自定义比较器)。

二分查找:需数组有序,通过Arrays.binarySearch(arr, key)实现,时间复杂度为O(log n)。

进阶:手动实现二分查找时,注意中间值的计算和边界条件。

数组异常与内存管理

题目:如何避免数组越界异常?二维数组的内存地址如何计算?

解析:

越界处理:使用Arrays.copyOf()扩展数组,避免直接操作原数组。

内存地址:若二维数组A1010中元素A20地址为560,则A10的地址为560 - 10*4 = 520(每个元素占4字节)。

数组与集合的区别

题目:数组与ArrayList有何区别?

解析:

数组:固定长度,支持基本数据类型和对象;内存连续,访问速度快。

ArrayList:动态扩容(默认增长50%),仅存储对象;提供更多操作方法(如add()、remove())。

二、进阶面试题

动态数组实现原理

题目:如何手动实现动态数组?

解析:

底层仍为数组,当容量不足时创建新数组并拷贝元素(类似ArrayList的扩容机制)。

示例步骤:初始化默认容量→添加元素→容量不足时扩容(如翻倍)→拷贝旧数组至新数组。

数组性能优化

题目:处理大数组时如何优化内存和性能?

解析:

内存优化:优先使用基本类型数组(如int而非Integer),减少对象开销。

算法优化:避免嵌套循环(时间复杂度O(n²)),使用双指针或哈希表优化查找。

多维数组应用场景

题目:哪些场景适合使用多维数组?

解析:

矩阵运算、棋盘类游戏(如五子棋)、图像处理(像素矩阵)等。

注意:Java中多维数组本质是“数组的数组”,内存非连续,可能影响缓存命中率。

系统设计中的数组应用

题目:如何用数组实现队列或栈?

解析:

循环队列:使用数组和两个指针(头、尾),通过取模运算实现循环存储。

栈:用数组模拟后进先出(LIFO)结构,需记录栈顶指针。

算法实战题

题目:寻找数组中的重复元素或缺失值。

解析:

重复元素:使用哈希表(时间复杂度O(n))或原地交换法(适用于元素值在0, n-1范围内)。

缺失值:利用数学公式(总和差值)或异或运算(XOR)。

三、高频易错题示例

非法数组引用

题目:以下哪种数组引用是非法的?

java

int a34;

a02*1 // A

a13 // B

a4-20 // C

a022 // D

答案:D(索引越界)。

折半查找轨迹

题目:在有序数组{2,4,6,8,10,12,14,16,18,20,22}中查找16,比较轨迹是?

答案:12 → 18 → 14 → 16(通过中间值逐步缩小范围)。

四、总结与建议

基础重点:掌握数组的声明、遍历、排序及与集合的区别。

进阶方向:深入理解内存布局、动态数组实现及性能优化策略。

实战准备:结合LeetCode高频题(如双指针、滑动窗口)强化算法能力。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容