DSA 第1天:数组基础
Source: Dev.to
介绍
我选择 数组 作为我的 DSA 之旅的起点。虽然我并非完全的初学者——我之前已经学习过 Java 和基础的 DSA——但我觉得数组是一个值得重新学习并巩固的概念,在进入更高级的主题之前。
然而,我 不 推荐绝对的初学者直接从数组开始。初学者应首先熟悉 基本的编程概念,如变量、数据类型和循环。一旦这些基础清晰,数组就会容易得多。
在学习 DSA 之前,选择一门编程语言很重要。我选择 Java 作为我的主要语言,在本博客中,我将 从 Java 的角度 具体讲解 DSA 概念,并在必要时简要对比 Python。
特别感谢这段 YouTube 教程 的讲师——它帮助我更好地理解了这些概念。
本博客涵盖的主题
- 为什么我们需要数组?
- 什么是数组?
- Java 和 Python 中的数组
- Java 中数组的语法
- Java 中数组的规则
- 声明与初始化
- 创建数组的示例
- 数组的索引
- 数组的长度
- 数组的默认值
- 字符串数组与内存
- 基本类型 vs 对象
- 数组的可变性
为什么我们需要数组?
数组用于在单个名称下存储一组相关值,该名称通常称为引用变量。
例如,如果我们想存储朋友的名字,而不是为每个名字创建多个变量,我们可以将所有名字存储在一个名为 friendsNames 的数组中。这使代码更有条理、可扩展且更易于使用。
当我想象数组时,我会把它想象成架子上一排空盒子。每个盒子都有一个固定的位置编号,我可以在每个盒子里放入一个相关的项目。这种思维模型有助于以后编写循环,因为我知道每个索引遵循可预测的模式。
什么是数组?
常用的数组定义是:
数组是存储在连续内存位置中的、具有相同数据类型的元素集合。
该定义对 C、C++ 等低级语言 完全准确。然而,不同编程语言对数组的内部实现可能有所差异。
“连续”仅指这些槽位在内存中是相邻的。其优势在于能够快速随机访问:跳转到索引 i 很快,因为程序可以计算出确切的内存地址。其代价是,调整大小通常意味着创建一个全新的数组并复制其中的元素。
Java中的数组
- 在 Java 中,数组只能存储 单一数据类型,这使得数组是 同质的。
- Java 中的数组是 对象,并且它们在 堆内存 中创建。
- 对于 基本数据类型(
int、double等),其值在数组对象内部 连续存储。 - 对于 引用类型(
String、Object等),数组存储 连续的引用,而实际对象可能位于堆中的不同位置。
我喜欢记住 String[] names 实际上保存的是引用。将 names[0] = "Bob" 只会更换该槽位指向的 String 对象;它 不会 将底层的 String 对象移动或复制到其他位置。
Arrays in Python
- Python 默认不提供传统数组。
- 在 Python 中常用的是 list(列表),它可以存储 不同的数据类型。
- Python 列表存储的是 对象的引用,而不是原始值本身。
由于 Python 列表是动态的,追加元素几乎感觉毫不费力。运行时会在需要时悄悄重新分配内存并复制数据。这对初学者很友好,但也隐藏了相对于固定大小的 Java 数组而言,列表增长的成本。
Java 中数组的语法
datatype[] arrayName = new datatype[size];
说明
| 符号 | 含义 |
|---|---|
datatype | 指定数组可以存储的元素类型 |
[] | 表示该变量是数组类型 |
arrayName | 指向数组对象的引用变量 |
new | 用于在堆中创建数组对象 |
datatype[size] | 指定数据类型以及数组能够容纳的元素数量 |
当我第一次写这段代码时,[] 的位置让我感到困惑。datatype[] arrayName 和 datatype arrayName[] 在 Java 中都可以编译通过,但我坚持使用第一种写法,因为它可以读作 “arrayName 是 datatype 类型的数组”。数组的大小在创建时就已经固定。
Java 中数组的规则
- 引用变量名必须遵循与普通变量相同的命名约定。
- 数组中的所有元素必须具有相同的数据类型。
- 一旦创建,数组的大小是固定的,且不能更改。
如果我认为需要可变大小,我会改用 ArrayList。坚持使用普通数组是学习索引以及在面试题中需要固定大小存储时的极好练习。
声明与初始化
datatype[] arr; // declaration
arr = new datatype[size]; // initialization
- 在 声明 时,会创建一个 引用变量。
- 在 初始化 时,会在堆中创建 数组对象。
- 声明在 编译时 进行检查。
- 数组的内存分配发生在 运行时。
一个常见错误:在 arr 初始化之前调用 arr[0] 会触发 NullPointerException,因为引用指向空。我要不断提醒自己,仅仅声明并 不 创建数组——是初始化才会。
创建数组的示例
int[] nums = {1, 2, 3, 4, 5, 6};
这行代码创建并初始化了一个包含六个元素的整数数组。
每当我使用大括号声明时,我读取的 va…(原文在此处截断)。
数组索引
索引用于访问数组的元素。
- Java 中的数组索引从 0 开始。
- 第一个元素存储在索引
0处。
Example
int[] num = {2, 7, 8};
-
num[0]→2 -
num[1]→7 -
num[2]→8 -
数组的长度 =
3 -
最后一个索引 =
length - 1 = 2
许多初学者会混淆 数组的长度 与 最后一个索引,但它们并不相同。
如果我们尝试访问大于最后一个索引的元素,Java 会抛出名为 ArrayIndexOutOfBoundsException 的异常。
在编写循环边界之前,我仍会停下来思考:
for (int i = 0; i
附加资源
- GeeksforGeeks introduction to arrays
- W3Schools Java arrays overview
- freeCodeCamp guide on array basics
如果你看到这里,感谢与你一起学习。我仍然把它当作实验笔记本:简单的图示、少量代码片段,以及我在过程中发现的真实错误。如果你发现了遗漏或有喜欢的入门资源,告诉我,我会继续改进这本日志。