动态数组代码实现

简介: 本文介绍动态数组的基本实现,涵盖增删查改及自动扩缩容机制:容量满时扩容2倍,元素过少时缩容一半。重点解析索引越界检查、内存泄漏防范(如置null避免引用残留)等关键细节,并对比插入与访问时的索引合法性差异,帮助理解底层原理。

❗前置知识
阅读本文前,请学习:数组(顺序存储)基础
几个关键点
下面我会直接给出一个简单的动态数组代码实现,包含了基本的增删查改功能。这里先给出几个关键点,等会你看代码的时候可以着重注意一下。
关键点一、自动扩缩容
在上一章 数组基础 中只提到了数组添加元素时可能需要扩容,并没有提到缩容。
在实际使用动态数组时,缩容也是重要的优化手段。比方说一个动态数组开辟了能够存储 1000 个元素的连续内存空间,但是实际只存了 10 个元素,那就有 990 个空间是空闲的。为了避免资源浪费,我们其实可以适当缩小存储空间,这就是缩容。
我们这里就实现一个简单的扩缩容的策略:
当数组元素个数达到底层静态数组的容量上限时,扩容为原来的 2 倍;
当数组元素个数缩减到底层静态数组的容量的 1/4 时,缩容为原来的 1/2。
关键点二、索引越界的检查
下面的代码实现中,有两个检查越界的方法,分别是 checkElementIndex 和 checkPositionIndex,你可以看到它俩的区别仅仅在于 index < size 和 index <= size。
为什么 checkPositionIndex 可以允许 index == size 呢,因为这个 checkPositionIndex 是专门用来处理在数组中插入元素的情况。
比方说有这样一个 nums 数组,对于每个元素来说,合法的索引一定是 index < size:
但如果要在数组中插入新元素,那么新元素可能插入位置并不是元素的索引,而是索引之间的空隙:
这些空隙都是合法的插入位置,所以说 index == size 也是合法的。这就是 checkPositionIndex 和 checkElementIndex 的区别。
关键点三、删除元素谨防内存泄漏
单从算法的角度,其实并不需要关心被删掉的元素应该如何处理,但是具体到代码实现,我们需要注意可能出现的内存泄漏。
在我给出的代码实现中,删除元素时,我都会把被删除的元素置为 null,以 Java 为例:
Java 的垃圾回收机制是基于 图算法 的可达性分析,如果一个对象再也无法被访问到,那么这个对象占用的内存才会被释放;否则,垃圾回收器会认为这个对象还在使用中,就不会释放这个对象占用的内存。
如果你不执行 data[size - 1] = null 这行代码,那么 data[size - 1] 这个引用就会一直存在,你可以通过 data[size - 1] 访问这个对象,所以这个对象被认为是可达的,它的内存就一直不会被释放,进而造成内存泄漏。
其他带垃圾回收功能的语言应该也是类似的,你可以具体了解一下你使用的编程语言的垃圾回收机制,这是写出无 bug 代码的基本要求。
其他细节优化
下面的代码当然不会是一个很完善的实现,会有不少可以进一步优化的点。比方说,我是用 for 循环复制数组数据的,实际上这种方式复制的效率比较差,大部分编程语言会提供更高效的数组复制方法,比如 Java 的 System.arraycopy。
不过它再怎么优化,本质上也是要搬移数据,时间复杂度都是 O(n)。本文的重点在于让你理解数组增删查改 API 的基本实现思路以及时间复杂度,如果对这些细节感兴趣,可以找到编程语言标准库的源码深入研究。
动态数组代码实现
Java
运行代码
复制代码
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
import java.util.Arrays;
return size;
}

public boolean isEmpty() {
    return size == 0;
}

// 将 data 的容量改为 newCap
private void resize(int newCap) {
    E[] temp = (E[]) new Object[newCap];

    for (int i = 0; i < size; i++) {
        temp[i] = data[i];
    }

    data = temp;
}

private boolean isElementIndex(int index) {
    return index >= 0 && index < size;
}

private boolean isPositionIndex(int index) {
    return index >= 0 && index <= size;
}


// 检查 index 索引位置是否可以存在元素
private void checkElementIndex(int index) {
    if (!isElementIndex(index))
        throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}


// 检查 index 索引位置是否可以添加元素
private void checkPositionIndex(int index) {
    if (!isPositionIndex(index))
        throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}

private void display() {
    System.out.println("size = " + size + " cap = " + data.length);
    System.out.println(Arrays.toString(data));
}


public static void main(String[] args) {
    // 初始容量设置为 3
    MyArrayList<Integer> arr = new MyArrayList<>(3);

    // 添加 5 个元素
    for (int i = 1; i <= 5; i++) {
        arr.addLast(i);
    }

    arr.remove(3);
    arr.add(1, 9);
    arr.addFirst(100);
    int val = arr.removeLast();

    for (int i = 0; i < arr.size(); i++) {
        System.out.println(arr.get(i));
    }
}

}

相关文章
|
数据采集 存储 人工智能
141_模型更新:在线学习策略 - 焦点在增量微调的独特无中断部署
在大语言模型(LLM)的实际生产环境中,模型更新是维持服务质量和持续改进的关键环节。随着业务需求的演变、数据分布的变化以及模型能力的提升,如何高效、安全地更新已部署的LLM成为技术团队面临的重要挑战。传统的全量模型替换方法往往伴随着服务中断风险、资源消耗大以及可能的性能波动等问题。为此,增量微调技术作为一种轻量级的模型更新策略,正逐渐成为2025年LLM部署领域的主流选择。
962 9
|
9月前
|
人工智能 安全 前端开发
OpenClaw Tools深度解析:10大工具组+多层防护+阿里云1键部署实战(2026版)
OpenClaw的核心魅力在于其强大的Tools体系——作为AI智能体直接操作外部世界的标准化接口,它就像“小龙虾”的强力钳子,让AI能打开浏览器、执行命令、读写文件甚至控制IoT设备。而Tools与Skills的本质区别在于:Tools是“工具箱”(功能单元),Skills是“操作手册”(使用指南),两者协同让AI从“只会说”变成“会动手”。
2068 6
|
存储 人工智能 小程序
微信掌上医院是如何实现的?智慧掌上医院核心实现原理及关键技术解析
微信掌上医院(智慧医院)小程序源码,基于uni-app与Vue.js开发,集成预约挂号、在线支付、报告查询等功能,支持与医院HIS、医保系统对接,采用微服务架构与多重安全机制。
767 2
|
11月前
|
XML Java 数据格式
springboot@Configuration
`@Configuration` 注解用于标记配置类,相当于 XML 配置文件,配合 `@Bean` 注解注册 Bean 到 Spring 容器。通过 `AnnotationConfigApplicationContext` 可加载配置类并启动 IOC 容器,实现组件的自动管理与注入。
|
11月前
|
人工智能 自然语言处理 Cloud Native
概述篇
AI时代重塑软件开发,本课程填补DeepSeek+Cursor+Devbox融合教学空白。零基础也能通过自然语言实现“需求→代码→部署”全链路开发。掌握AI辅助设计数据库、生成代码、联调测试到云原生部署,3小时实战交付完整项目,助力开发者高效转型,抢占智能开发先机。(238字)
|
11月前
|
人工智能 自然语言处理 Cloud Native
AI时代代码开发(DeepSeek+Cursor+Devbox)
AI时代重塑软件开发,本课程聚焦DeepSeek+Cursor+Devbox+Sealos工具链,实现自然语言到代码的零基础全栈开发。覆盖需求分析、数据库设计、编码测试至云部署全流程,助力开发者高效构建并上线项目,抢占智能开发先机。(238字)
|
11月前
|
存储 SQL 人工智能
AI时代代码开发(数据库设计)
本文介绍基于三范式与DDD的数据库设计流程,结合AI工具辅助分析页面原型,通过部门、员工及工作经历模块,演示表结构设计与优化过程,强调人工校验与调整的重要性,最终完成符合业务需求的数据库建模与测试数据构建。
|
11月前
|
缓存 网络协议 算法
核心原理:能否画张图解释下 RPC 的通信流程?
RPC(远程过程调用)是一种实现分布式系统间通信的技术,它让调用远程服务像调用本地方法一样简单。本文深入浅出地讲解了RPC的定义、核心目标、通信流程及在微服务架构中的关键作用,帮助开发者理解其底层原理,掌握如何通过动态代理、序列化、协议设计等机制屏蔽网络复杂性,提升开发效率与系统可维护性。
|
11月前
|
人工智能 Java 程序员
SpringAI+DeepSeek大模型应用开发
本教程以SpringAI为核心,讲解Java与大模型(如DeepSeek)融合开发,助力传统应用智能化升级。适合Java程序员入门AI开发,推动企业低成本拥抱AI变革。
|
11月前
|
存储 Java Maven
服务端(DevBox)-项目创建
使用Sealos创建SpringBoot工程zxyf-management,配置Java语言、3.3.2版本,2核CPU、4G内存,通过Devbox在云端搭建开发环境。利用Cursor智能工具打开项目,自动识别Maven结构,一键启动运行,实现高效云端开发。

热门文章

最新文章