数据结构与算法篇--结构不变式--动态数组
动态数据列表类的不变式
重点:形式化定义转换成 checkInvariants
代码
DArrayList
DArrayListTest
形式化定义
Invariant:(1) data != null(2) capacity > 0(3) 0 <= size <= capacity(4) ∀ i ∈ [0, size): data[i] != null(5) ∀ i ∈ [size, capacity): data[i] == null(6) capacity 仅通过 resize() 成倍增长
checkInvariants
源码
public void checkInvariants() {// --- 1. 容量与大小约束检查 ---// C1: 容量必须大于 0if (capacity <= 0) {throw new AssertionError("Invariant Broken: Capacity must be positive (capacity=" + capacity + ")");}// C2: Size 必须在 [0, capacity] 范围内if (size < 0 || size > capacity) {throw new AssertionError("Invariant Broken: Size must be between 0 and capacity (size=" + size + ", capacity=" + capacity + ")");}// --- 2. 数组和数据完整性检查 ---// D1: 底层数组必须存在if (data == null) {throw new AssertionError("Invariant Broken: Internal array 'data' must not be null.");}// D2: 数组的实际长度必须等于记录的 capacityif (data.length != capacity) {throw new AssertionError("Invariant Broken: data.length (" + data.length + ") does not match recorded capacity (" + capacity + ")");}// --- 3. 数据填充和空值约束检查 ---// 验证有效数据范围 [0, size-1]for (int i = 0; i < size; i++) {// D3: 有效数据区域 [0, size-1] 不得包含 nullif (data[i] == null) {// 根据您的 add 方法,data[i] 应该是非空的throw new AssertionError("Invariant Broken: Element at index " + i + " must not be null (size=" + size + ")");}}// 验证闲置空间范围 [size, capacity-1]for (int j = size; j < capacity; j++) {// D4: 闲置空间 [size, capacity-1] 必须为 null (防止内存泄漏)if (data[j] != null) {throw new AssertionError("Invariant Broken: Element at index " + j + " must be null to prevent memory leak (size=" + size + ", capacity=" + capacity + ")");}}InternalIterator it = new InternalIterator();int elementsFound = 0;while(it.hasNext()) {try {it.next();elementsFound++;} catch (NoSuchElementException e) {throw new AssertionError("Iterator failed unexpectedly near index " + elementsFound);}}if (elementsFound != size) {throw new AssertionError("Iterator found " + elementsFound + " elements, but size is " + size);}
}
使用指南
- 整合代码: 将
checkInvariants()
方法添加到您的DArrayList
类定义中。 - 插入调用: 在每个修改数组状态的方法(
DArrayList
的add
和remove
以及私有方法resize
)的末尾调用this.checkInvariants();
。
通过这种方式,每次修改数组后,程序都会进行一次快速的自我验证,确保您的动态扩容和元素移动逻辑没有破坏任何核心不变式。