动态数组是指在声明时没有确定数组大小的数组,即忽略圆括号中的下标;当要用它时,可随时用ReDim语句重新指出数组的大小。使用动态数组的优点是可以根据用户需要,有效利用存储空间。
数据结构
数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。数据结构往往同高效的检索算法和索引技术有关。
数据的逻辑结构
指反映数据元素之间的逻辑关系的数据结构,其中的逻辑关系是指数据元素之间的前后间关系,而与他们在计算机中的存储位置无关。逻辑结构包括:
- 集合:数据结构中的元素之间除了“同属一个集合” 的相互关系外,别无其他关系;
- 线性结构:数据结构中的元素存在一对一的相互关系;
- 树形结构:数据结构中的元素存在一对多的相互关系;
- 图形结构:数据结构中的元素存在多对多的相互关系。
线性结构包括:线性表、数组、链表、栈、队列和哈希表。
树形结构包括:二叉树、AVL树、红黑树、B树、堆、Trie、哈夫曼树和并查集。
图形结构包括:邻接矩阵和邻接表。
常用的数据结构:
线性表
线性表是最基本、最简单、也是最常用的一种数据结构。线性表(linear list)是数据结构的一种,一个线性表是n个具有相同特性的数据元素的有限序列。
a1 是首节点(首元素),an 是为节点(尾元素)。
a1 是 a2 的前驱,a2 是 a1 的后继。
ps:什么是线性表
数组
数组是一种顺序存储的线性表,所有元素的内存地址是连续的。一维数组是最简单的数组,其逻辑结构是线性表。
在很多编程语言中,数组都有个致命的缺点,无法动态修改容量。怎么实现一个容量可以动态修改的数组呢?👇
ps:什么是数组
动态数组
接口设计
|
|
实现方案
定义 size 记录数组的大小,定义 elements 存储元素。
添加元素
添加新元素,就是在 size 处添加新元素,代码实现:
删除元素
size 等于 7,index 等于 3:
从 index + 1
处开始依次向前移动,最后一个元素不做处理(因为执行了 size--
,所以最后一个元素不会被外界访问到):
插入元素
size 等于 5,index 等于 2:
从 size - 1
处开始依次向后移动,最后覆盖 index 处的元素:
扩容
创建新的数组,新数组的容量为旧数组容量的1.5倍(iOS 1.6倍, java 1.5倍)。
缩容
如果内存使用比较紧张,动态数组有比较多的剩余空间,可以考虑进行缩容操作。比如剩余空间占总容量的一半时,就进行缩容。
如果扩容倍数、缩容时机设计不得当,有可能会导致复杂度震荡。比如缩容时机改为 size > newCapacity
,此时容量等于数组的一半时,新增加元素需要扩容,删除元素需要缩容,那么复杂度就一直是 O(n)。
在 clear() 和 remove() 方法里进行缩容:
泛型
使用泛型技术可以让动态数组更加通用,可以存放任何数据类型。
E 表示泛型:
使用 Object 创建的数组可以存放所有对象类型,因为所有的类都继承自Object。
示例:
对象数组
数组中存放的是对象地址。
删除元素
删除元素时,需要将数组对应的位置设为 null:
在调用 clear()
方法时,Java 的垃圾回收机制不会立即执行,可以通过 System.gc()
让垃圾回收机制立即启动:
查找元素
如果数组支持 null,需要修改 indexOf()
方法:
判等
Person 类里实现 equals()
方法(age 相等 -> 两个 Person 对象相等):
源码分析
ArrayList
JDK中内置了一个动态数组类:java.util.ArrayList。
方式一:
如果 Eclipse 里没有加载这个包,可以手动导入:
按住 command 点击 ArrayList:
方式二:
代码
变量
|
|
构造方法
|
|
数组大小
|
|
判空
|
|
查找
|
|
获取
|
|
修改
|
|
添加
|
|
删除
|
|
清空
|
|
扩容
|
|
测试
使用 Asserts(断言)进行测试: