数组的插入删除时间复杂度是O(n),GapBuffer就是为了解决数组插入删除慢的问题。GapBuffer是一种优化的数据结构,用于高效地在任意位置进行插入和删除操作。它的核心思想是维护一个"间隙"(gap),在间隙位置的插入删除的时间复杂度是 O(1) 。
直接上代码,有详细的代码注释。
/**
* Gap Buffer 数据结构实现
*
* Gap Buffer 是一种优化的数据结构,用于高效地在任意位置进行插入和删除操作。
* 它的核心思想是维护一个"间隙"(gap),在间隙位置的插入/删除是 O(1) 的。
*
* 结构示意图:
* ```
* [A][B][C][_][_][_][_][D][E][F]
* ↑ ↑
* gapStart gapEnd
*
* 逻辑内容: [A, B, C, D, E, F]
* ```
*
* 这是 Compose Runtime 中 SlotTable 使用的核心数据结构。
*/
class GapBuffer<T>(initialCapacity: Int = 16) {
// 内部数组存储
private var buffer: Array<Any?> = arrayOfNulls(initialCapacity)
// 间隙起始位置(包含)
private var gapStart: Int = 0
// 间隙结束位置(不包含)
private var gapEnd: Int = initialCapacity
/**
* 逻辑大小(不包含间隙)
*/
val size: Int
get() = buffer.size - gapSize
/**
* 间隙大小
*/
val gapSize: Int
get() = gapEnd - gapStart
/**
* 当前间隙位置
*/
val currentGapStart: Int
get() = gapStart
/**
* 在指定位置插入元素
*
* 步骤:
* 1. 如果间隙大小为 0,扩容
* 2. 将间隙移动到插入位置
* 3. 在间隙起始位置插入元素
* 4. gapStart++
*
* @param index 逻辑索引位置
* @param element 要插入的元素
*/
fun insert(index: Int, element: T) {
require(index in 0..size) { "Index $index out of bounds for size $size" }
// 1. 需要时扩容
if (gapSize == 0) {
grow()
}
// 2. 移动间隙到目标位置
moveGap(index)
// 3. 在间隙位置插入
buffer[gapStart] = element
// 4. 缩小间隙
gapStart++
}
/**
* 在指定位置插入多个元素
*/
fun insertAll(index: Int, elements: List<T>) {
require(index in 0..size) { "Index $index out of bounds for size $size" }
// 确保有足够空间
while (gapSize < elements.size) {
grow()
}
// 移动间隙到目标位置
moveGap(index)
// 逐个插入
for (element in elements) {
buffer[gapStart] = element
gapStart++
}
}
/**
* 删除指定位置的元素
*
* 步骤:
* 1. 将间隙移动到删除位置
* 2. gapEnd++ (扩大间隙,覆盖要删除的元素)
*
* @param index 逻辑索引位置
* @return 被删除的元素
*/
fun removeAt(index: Int): T {
require(index in 0 until size) { "Index $index out of bounds for size $size" }
// 移动间隙到目标位置后面
moveGap(index + 1)
// 扩大间隙的起始位置(相当于删除元素)
gapStart--
// 获取并清除被删除的元素
@Suppress("UNCHECKED_CAST")
val removed = buffer[gapStart] as T
buffer[gapStart] = null
return removed
}
/**
* 删除指定范围的元素
*
* @param startIndex 起始索引(包含)
* @param endIndex 结束索引(不包含)
* @return 被删除的元素列表
*/
fun removeRange(startIndex: Int, endIndex: Int): List<T> {
require(startIndex in 0..size) { "Start index $startIndex out of bounds" }
require(endIndex in startIndex..size) { "End index $endIndex out of bounds" }
val count = endIndex - startIndex
if (count == 0) return emptyList()
val removed = mutableListOf<T>()
// 移动间隙到删除范围之后
moveGap(endIndex)
// 收集被删除的元素并扩大间隙
repeat(count) {
gapStart--
@Suppress("UNCHECKED_CAST")
removed.add(0, buffer[gapStart] as T)
buffer[gapStart] = null
}
return removed
}
/**
* 获取指定位置的元素
*
* 需要处理逻辑索引到物理索引的转换
*/
operator fun get(index: Int): T {
require(index in 0 until size) { "Index $index out of bounds for size $size" }
@Suppress("UNCHECKED_CAST")
return buffer[toPhysicalIndex(index)] as T
}
/**
* 设置指定位置的元素
*/
operator fun set(index: Int, element: T) {
require(index in 0 until size) { "Index $index out of bounds for size $size" }
buffer[toPhysicalIndex(index)] = element
}
/**
* 将逻辑索引转换为物理索引
*
* 逻辑视图: [A][B][C][D][E][F]
* 0 1 2 3 4 5
*
* 物理数组: [A][B][C][_][_][_][D][E][F]
* 0 1 2 3 4 5 6 7 8
* ↑ ↑
* gapStart gapEnd
*
* 逻辑索引 0-2 直接对应物理索引 0-2
* 逻辑索引 3-5 需要加上 gapSize
*/
private fun toPhysicalIndex(logicalIndex: Int): Int {
return if (logicalIndex < gapStart) {
logicalIndex
} else {
logicalIndex + gapSize
}
}
/**
* 移动间隙到目标位置
*
* 这是 Gap Buffer 的核心操作。
*
* 场景1: 间隙向右移动 (targetIndex > gapStart)
* ```
* 移动前: [A][B][_][_][_][C][D][E]
* ↑ ↑
* gapStart gapEnd
*
* 目标: 移动到索引 4
*
* 操作: 把 gapEnd 到 gapEnd+移动距离 的元素复制到 gapStart
* [A][B][C][D][_][_][_][E]
*
* 移动后: [A][B][C][D][_][_][_][E]
* ↑ ↑
* gapStart gapEnd
* ```
*
* 场景2: 间隙向左移动 (targetIndex < gapStart)
* ```
* 移动前: [A][B][C][D][_][_][_][E]
* ↑ ↑
* gapStart gapEnd
*
* 目标: 移动到索引 1
*
* 操作: 把 targetIndex 到 gapStart 的元素复制到 gapEnd 之前
* [A][_][_][_][B][C][D][E]
*
* 移动后: [A][_][_][_][B][C][D][E]
* ↑ ↑
* gapStart gapEnd
* ```
*/
private fun moveGap(targetIndex: Int) {
if (targetIndex == gapStart) {
// 间隙已在目标位置
return
}
if (targetIndex > gapStart) {
// 间隙向右移动
// 需要把间隙右边的元素移到左边
val moveCount = targetIndex - gapStart
// 从 gapEnd 复制 moveCount 个元素到 gapStart
// copyInto(destination, destinationOffset, startIndex, endIndex)
buffer.copyInto(buffer, gapStart, gapEnd, gapEnd + moveCount)
// 清除原位置
for (i in gapEnd until gapEnd + moveCount) {
buffer[i] = null
}
// 更新间隙位置
gapStart += moveCount
gapEnd += moveCount
} else {
// 间隙向左移动
// 需要把间隙左边的元素移到右边
val moveCount = gapStart - targetIndex
// 从 targetIndex 复制 moveCount 个元素到 gapEnd - moveCount
// copyInto(destination, destinationOffset, startIndex, endIndex)
buffer.copyInto(buffer, gapEnd - moveCount, targetIndex, targetIndex + moveCount)
// 清除原位置
for (i in targetIndex until targetIndex + moveCount) {
buffer[i] = null
}
// 更新间隙位置
gapStart -= moveCount
gapEnd -= moveCount
}
}
/**
* 扩容
*
* 策略: 容量翻倍,新空间全部加入间隙
*/
private fun grow() {
val oldCapacity = buffer.size
val newCapacity = oldCapacity * 2
val newBuffer = arrayOfNulls<Any?>(newCapacity)
// 复制间隙之前的元素
// copyInto(destination, destinationOffset, startIndex, endIndex)
buffer.copyInto(newBuffer, 0, 0, gapStart)
// 复制间隙之后的元素(放到新数组的末尾)
val afterGapCount = oldCapacity - gapEnd
val newGapEnd = newCapacity - afterGapCount
buffer.copyInto(newBuffer, newGapEnd, gapEnd, oldCapacity)
buffer = newBuffer
gapEnd = newGapEnd
}
/**
* 获取当前状态的可视化字符串
*/
fun visualize(): String {
val sb = StringBuilder()
sb.append("GapBuffer(size=$size, capacity=${buffer.size}, gap=$gapStart..$gapEnd)\n")
sb.append("Physical: [")
for (i in buffer.indices) {
if (i > 0) sb.append("][")
if (i in gapStart until gapEnd) {
sb.append("_")
} else {
sb.append(buffer[i] ?: "null")
}
}
sb.append("]\n")
sb.append("Logical: [")
for (i in 0 until size) {
if (i > 0) sb.append(", ")
sb.append(get(i))
}
sb.append("]")
return sb.toString()
}
/**
* 转换为列表
*/
fun toList(): List<T> {
val result = mutableListOf<T>()
for (i in 0 until size) {
result.add(get(i))
}
return result
}
override fun toString(): String = toList().toString()
}
上面就是GapBuffer的实现代码,初次查看可能有点难以理解,下面是带详细日志的GapBuffer,用于演示执行流程。场景是构建 [1,2,4,5,6],然后在2后面插入3,看下执行流程。
/**
* 带详细日志的 GapBuffer,用于演示执行流程
*/
class GapBufferDebug<T>(initialCapacity: Int = 16) {
private var buffer: Array<Any?> = arrayOfNulls(initialCapacity)
private var gapStart: Int = 0
private var gapEnd: Int = initialCapacity
val size: Int get() = buffer.size - gapSize
val gapSize: Int get() = gapEnd - gapStart
fun insert(index: Int, element: T) {
println("┌─────────────────────────────────────────────────────────────")
println("│ 调用 insert(index=$index, element=$element)")
println("├─────────────────────────────────────────────────────────────")
println("│ 【进入 insert 方法】")
println("│ 当前状态:")
println("│ size = $size")
println("│ gapStart = $gapStart")
println("│ gapEnd = $gapEnd")
println("│ gapSize = $gapSize")
println("│ buffer = ${bufferToString()}")
println("│")
require(index in 0..size) { "Index $index out of bounds for size $size" }
// 1. 检查是否需要扩容
println("│ 【步骤1】检查是否需要扩容")
println("│ gapSize ($gapSize) == 0 ? ${gapSize == 0}")
if (gapSize == 0) {
println("│ → 需要扩容,调用 grow()")
grow()
} else {
println("│ → 不需要扩容")
}
println("│")
// 2. 移动间隙到目标位置
println("│ 【步骤2】移动间隙到目标位置 (targetIndex=$index)")
moveGap(index)
println("│")
// 3. 在间隙位置插入
println("│ 【步骤3】在间隙位置插入元素")
println("│ buffer[$gapStart] = $element")
buffer[gapStart] = element
println("│ 插入后 buffer = ${bufferToString()}")
println("│")
// 4. 缩小间隙
println("│ 【步骤4】缩小间隙 (gapStart++)")
println("│ gapStart: $gapStart → ${gapStart + 1}")
gapStart++
println("│")
println("│ 【插入完成】")
println("│ 最终状态:")
println("│ size = $size")
println("│ gapStart = $gapStart")
println("│ gapEnd = $gapEnd")
println("│ gapSize = $gapSize")
println("│ buffer = ${bufferToString()}")
println("│ 逻辑内容 = ${toList()}")
println("└─────────────────────────────────────────────────────────────")
println()
}
private fun moveGap(targetIndex: Int) {
println("│ ┌─ moveGap(targetIndex=$targetIndex) ─────────────────────")
println("│ │ 当前 gapStart=$gapStart, gapEnd=$gapEnd")
println("│ │ 目标位置 targetIndex=$targetIndex")
if (targetIndex == gapStart) {
println("│ │ targetIndex == gapStart,间隙已在目标位置,无需移动")
println("│ └──────────────────────────────────────────────────────")
return
}
if (targetIndex > gapStart) {
// 间隙向右移动
println("│ │ targetIndex ($targetIndex) > gapStart ($gapStart)")
println("│ │ → 间隙需要【向右移动】")
println("│ │")
val moveCount = targetIndex - gapStart
println("│ │ 计算: moveCount = targetIndex - gapStart = $targetIndex - $gapStart = $moveCount")
println("│ │")
println("│ │ 操作: 把间隙右边的 $moveCount 个元素移到间隙左边")
println("│ │ copyInto(buffer, destOffset=$gapStart, startIndex=$gapEnd, endIndex=${gapEnd + moveCount})")
println("│ │ 即: 把 buffer[$gapEnd..${gapEnd + moveCount - 1}] 复制到 buffer[$gapStart..${gapStart + moveCount - 1}]")
println("│ │")
println("│ │ 移动前: ${bufferToString()}")
buffer.copyInto(buffer, gapStart, gapEnd, gapEnd + moveCount)
println("│ │ 复制后: ${bufferToString()}")
// 清除原位置
println("│ │")
println("│ │ 清除原位置 buffer[$gapEnd..${gapEnd + moveCount - 1}]")
for (i in gapEnd until gapEnd + moveCount) {
buffer[i] = null
}
println("│ │ 清除后: ${bufferToString()}")
// 更新间隙位置
println("│ │")
println("│ │ 更新间隙位置:")
println("│ │ gapStart: $gapStart → ${gapStart + moveCount}")
println("│ │ gapEnd: $gapEnd → ${gapEnd + moveCount}")
gapStart += moveCount
gapEnd += moveCount
} else {
// 间隙向左移动
println("│ │ targetIndex ($targetIndex) < gapStart ($gapStart)")
println("│ │ → 间隙需要【向左移动】")
println("│ │")
val moveCount = gapStart - targetIndex
println("│ │ 计算: moveCount = gapStart - targetIndex = $gapStart - $targetIndex = $moveCount")
println("│ │")
println("│ │ 操作: 把间隙左边的 $moveCount 个元素移到间隙右边")
println("│ │ copyInto(buffer, destOffset=${gapEnd - moveCount}, startIndex=$targetIndex, endIndex=${targetIndex + moveCount})")
println("│ │ 即: 把 buffer[$targetIndex..${targetIndex + moveCount - 1}] 复制到 buffer[${gapEnd - moveCount}..${gapEnd - 1}]")
println("│ │")
println("│ │ 移动前: ${bufferToString()}")
buffer.copyInto(buffer, gapEnd - moveCount, targetIndex, targetIndex + moveCount)
println("│ │ 复制后: ${bufferToString()}")
// 清除原位置
println("│ │")
println("│ │ 清除原位置 buffer[$targetIndex..${targetIndex + moveCount - 1}]")
for (i in targetIndex until targetIndex + moveCount) {
buffer[i] = null
}
println("│ │ 清除后: ${bufferToString()}")
// 更新间隙位置
println("│ │")
println("│ │ 更新间隙位置:")
println("│ │ gapStart: $gapStart → ${gapStart - moveCount}")
println("│ │ gapEnd: $gapEnd → ${gapEnd - moveCount}")
gapStart -= moveCount
gapEnd -= moveCount
}
println("│ │")
println("│ │ 移动完成: gapStart=$gapStart, gapEnd=$gapEnd")
println("│ └──────────────────────────────────────────────────────")
}
private fun grow() {
val oldCapacity = buffer.size
val newCapacity = oldCapacity * 2
val newBuffer = arrayOfNulls<Any?>(newCapacity)
buffer.copyInto(newBuffer, 0, 0, gapStart)
val afterGapCount = oldCapacity - gapEnd
val newGapEnd = newCapacity - afterGapCount
buffer.copyInto(newBuffer, newGapEnd, gapEnd, oldCapacity)
buffer = newBuffer
gapEnd = newGapEnd
}
private fun toPhysicalIndex(logicalIndex: Int): Int {
return if (logicalIndex < gapStart) logicalIndex else logicalIndex + gapSize
}
operator fun get(index: Int): T {
require(index in 0 until size)
@Suppress("UNCHECKED_CAST")
return buffer[toPhysicalIndex(index)] as T
}
fun toList(): List<T> {
val result = mutableListOf<T>()
for (i in 0 until size) result.add(get(i))
return result
}
private fun bufferToString(): String {
val sb = StringBuilder("[")
for (i in buffer.indices) {
if (i > 0) sb.append("][")
if (i in gapStart until gapEnd) {
sb.append("_")
} else {
sb.append(buffer[i] ?: "null")
}
}
sb.append("]")
return sb.toString()
}
}
/**
* 演示:构建 [1,2,4,5,6],然后在 2 后面插入 3
*/
fun main() {
println("╔═══════════════════════════════════════════════════════════════╗")
println("║ Gap Buffer 执行流程演示 ║")
println("║ 目标: 构建 [1,2,4,5,6],然后在 2 后面插入 3 ║")
println("╚═══════════════════════════════════════════════════════════════╝")
println()
val buffer = GapBufferDebug<Int>(8)
println("═══════════════════════════════════════════════════════════════")
println("阶段1: 构建初始数组 [1, 2, 4, 5, 6]")
println("═══════════════════════════════════════════════════════════════")
println()
buffer.insert(0, 1)
buffer.insert(1, 2)
buffer.insert(2, 4)
buffer.insert(3, 5)
buffer.insert(4, 6)
println()
println("═══════════════════════════════════════════════════════════════")
println("阶段2: 在 2 的后面插入 3 (即在逻辑索引 2 处插入)")
println(" 当前: [1, 2, 4, 5, 6]")
println(" 目标: [1, 2, 3, 4, 5, 6]")
println("═══════════════════════════════════════════════════════════════")
println()
buffer.insert(2, 3)
println()
println("═══════════════════════════════════════════════════════════════")
println("最终结果: ${buffer.toList()}")
println("═══════════════════════════════════════════════════════════════")
}
Gap Buffer 执行流程追踪
场景:构建 [1,2,4,5,6],然后在 2 后面插入 3
阶段1: 构建初始数组 [1, 2, 4, 5, 6]
插入 1 到位置 0
┌─────────────────────────────────────────────────────────────
│ 调用 insert(index=0, element=1)
├─────────────────────────────────────────────────────────────
│ 【进入 insert 方法】
│ 当前状态:
│ size = 0
│ gapStart = 0
│ gapEnd = 8
│ gapSize = 8
│ buffer = [_][_][_][_][_][_][_][_]
│
│ 【步骤1】检查是否需要扩容
│ gapSize (8) == 0 ? false
│ → 不需要扩容
│
│ 【步骤2】移动间隙到目标位置 (targetIndex=0)
│ ┌─ moveGap(targetIndex=0) ─────────────────────
│ │ 当前 gapStart=0, gapEnd=8
│ │ 目标位置 targetIndex=0
│ │ targetIndex == gapStart,间隙已在目标位置,无需移动
│ └──────────────────────────────────────────────────────
│
│ 【步骤3】在间隙位置插入元素
│ buffer[0] = 1
│ 插入后 buffer = [1][_][_][_][_][_][_][_]
│
│ 【步骤4】缩小间隙 (gapStart++)
│ gapStart: 0 → 1
│
│ 【插入完成】
│ 最终状态:
│ size = 1
│ gapStart = 1
│ gapEnd = 8
│ gapSize = 7
│ buffer = [1][_][_][_][_][_][_][_]
│ 逻辑内容 = [1]
└─────────────────────────────────────────────────────────────
插入 2 到位置 1
┌─────────────────────────────────────────────────────────────
│ 调用 insert(index=1, element=2)
├─────────────────────────────────────────────────────────────
│ 【进入 insert 方法】
│ 当前状态:
│ size = 1
│ gapStart = 1
│ gapEnd = 8
│ gapSize = 7
│ buffer = [1][_][_][_][_][_][_][_]
│
│ 【步骤1】检查是否需要扩容
│ gapSize (7) == 0 ? false
│ → 不需要扩容
│
│ 【步骤2】移动间隙到目标位置 (targetIndex=1)
│ ┌─ moveGap(targetIndex=1) ─────────────────────
│ │ 当前 gapStart=1, gapEnd=8
│ │ 目标位置 targetIndex=1
│ │ targetIndex == gapStart,间隙已在目标位置,无需移动
│ └──────────────────────────────────────────────────────
│
│ 【步骤3】在间隙位置插入元素
│ buffer[1] = 2
│ 插入后 buffer = [1][2][_][_][_][_][_][_]
│
│ 【步骤4】缩小间隙 (gapStart++)
│ gapStart: 1 → 2
│
│ 【插入完成】
│ 最终状态:
│ size = 2
│ gapStart = 2
│ gapEnd = 8
│ gapSize = 6
│ buffer = [1][2][_][_][_][_][_][_]
│ 逻辑内容 = [1, 2]
└─────────────────────────────────────────────────────────────
插入 4 到位置 2
┌─────────────────────────────────────────────────────────────
│ 调用 insert(index=2, element=4)
├─────────────────────────────────────────────────────────────
│ 【进入 insert 方法】
│ 当前状态:
│ size = 2
│ gapStart = 2
│ gapEnd = 8
│ gapSize = 6
│ buffer = [1][2][_][_][_][_][_][_]
│
│ 【步骤1】检查是否需要扩容
│ gapSize (6) == 0 ? false
│ → 不需要扩容
│
│ 【步骤2】移动间隙到目标位置 (targetIndex=2)
│ ┌─ moveGap(targetIndex=2) ─────────────────────
│ │ 当前 gapStart=2, gapEnd=8
│ │ 目标位置 targetIndex=2
│ │ targetIndex == gapStart,间隙已在目标位置,无需移动
│ └──────────────────────────────────────────────────────
│
│ 【步骤3】在间隙位置插入元素
│ buffer[2] = 4
│ 插入后 buffer = [1][2][4][_][_][_][_][_]
│
│ 【步骤4】缩小间隙 (gapStart++)
│ gapStart: 2 → 3
│
│ 【插入完成】
│ 最终状态:
│ size = 3
│ gapStart = 3
│ gapEnd = 8
│ gapSize = 5
│ buffer = [1][2][4][_][_][_][_][_]
│ 逻辑内容 = [1, 2, 4]
└─────────────────────────────────────────────────────────────
插入 5 到位置 3
┌─────────────────────────────────────────────────────────────
│ 调用 insert(index=3, element=5)
├─────────────────────────────────────────────────────────────
│ 【进入 insert 方法】
│ 当前状态:
│ size = 3
│ gapStart = 3
│ gapEnd = 8
│ gapSize = 5
│ buffer = [1][2][4][_][_][_][_][_]
│
│ 【步骤1】检查是否需要扩容
│ gapSize (5) == 0 ? false
│ → 不需要扩容
│
│ 【步骤2】移动间隙到目标位置 (targetIndex=3)
│ ┌─ moveGap(targetIndex=3) ─────────────────────
│ │ 当前 gapStart=3, gapEnd=8
│ │ 目标位置 targetIndex=3
│ │ targetIndex == gapStart,间隙已在目标位置,无需移动
│ └──────────────────────────────────────────────────────
│
│ 【步骤3】在间隙位置插入元素
│ buffer[3] = 5
│ 插入后 buffer = [1][2][4][5][_][_][_][_]
│
│ 【步骤4】缩小间隙 (gapStart++)
│ gapStart: 3 → 4
│
│ 【插入完成】
│ 最终状态:
│ size = 4
│ gapStart = 4
│ gapEnd = 8
│ gapSize = 4
│ buffer = [1][2][4][5][_][_][_][_]
│ 逻辑内容 = [1, 2, 4, 5]
└─────────────────────────────────────────────────────────────
插入 6 到位置 4
┌─────────────────────────────────────────────────────────────
│ 调用 insert(index=4, element=6)
├─────────────────────────────────────────────────────────────
│ 【进入 insert 方法】
│ 当前状态:
│ size = 4
│ gapStart = 4
│ gapEnd = 8
│ gapSize = 4
│ buffer = [1][2][4][5][_][_][_][_]
│
│ 【步骤1】检查是否需要扩容
│ gapSize (4) == 0 ? false
│ → 不需要扩容
│
│ 【步骤2】移动间隙到目标位置 (targetIndex=4)
│ ┌─ moveGap(targetIndex=4) ─────────────────────
│ │ 当前 gapStart=4, gapEnd=8
│ │ 目标位置 targetIndex=4
│ │ targetIndex == gapStart,间隙已在目标位置,无需移动
│ └──────────────────────────────────────────────────────
│
│ 【步骤3】在间隙位置插入元素
│ buffer[4] = 6
│ 插入后 buffer = [1][2][4][5][6][_][_][_]
│
│ 【步骤4】缩小间隙 (gapStart++)
│ gapStart: 4 → 5
│
│ 【插入完成】
│ 最终状态:
│ size = 5
│ gapStart = 5
│ gapEnd = 8
│ gapSize = 3
│ buffer = [1][2][4][5][6][_][_][_]
│ 逻辑内容 = [1, 2, 4, 5, 6]
└─────────────────────────────────────────────────────────────
阶段1完成后的状态
物理数组: [1][2][4][5][6][_][_][_]
0 1 2 3 4 5 6 7
↑ ↑
gapStart gapEnd
(5) (8)
逻辑内容: [1, 2, 4, 5, 6]
0 1 2 3 4
阶段2: 在 2 的后面插入 3
目标: 在逻辑索引 2 处插入 3(即在 2 和 4 之间)
当前: [1, 2, 4, 5, 6]
目标: [1, 2, 3, 4, 5, 6]
┌─────────────────────────────────────────────────────────────
│ 调用 insert(index=2, element=3)
├─────────────────────────────────────────────────────────────
│ 【进入 insert 方法】
│ 当前状态:
│ size = 5
│ gapStart = 5
│ gapEnd = 8
│ gapSize = 3
│ buffer = [1][2][4][5][6][_][_][_]
│
│ 【步骤1】检查是否需要扩容
│ gapSize (3) == 0 ? false
│ → 不需要扩容
│
│ 【步骤2】移动间隙到目标位置 (targetIndex=2)
│ ┌─ moveGap(targetIndex=2) ─────────────────────
│ │ 当前 gapStart=5, gapEnd=8
│ │ 目标位置 targetIndex=2
│ │
│ │ targetIndex (2) < gapStart (5)
│ │ → 间隙需要【向左移动】
│ │
│ │ 计算: moveCount = gapStart - targetIndex = 5 - 2 = 3
│ │
│ │ 操作: 把间隙左边的 3 个元素移到间隙右边
│ │ copyInto(buffer, destOffset=5, startIndex=2, endIndex=5)
│ │ 即: 把 buffer[2..4] 复制到 buffer[5..7]
│ │ 把 [4][5][6] 移到后面
│ │
│ │ 移动前: [1][2][4][5][6][_][_][_]
│ │ ↑ ↑
│ │ 移动这3个元素
│ │
│ │ 复制后: [1][2][4][5][6][4][5][6]
│ │ (原位置) (新位置)
│ │
│ │ 清除原位置 buffer[2..4]
│ │ 清除后: [1][2][_][_][_][4][5][6]
│ │
│ │ 更新间隙位置:
│ │ gapStart: 5 → 2 (5 - 3 = 2)
│ │ gapEnd: 8 → 5 (8 - 3 = 5)
│ │
│ │ 移动完成: gapStart=2, gapEnd=5
│ └──────────────────────────────────────────────────────
│
│ 【步骤3】在间隙位置插入元素
│ buffer[2] = 3
│ 插入后 buffer = [1][2][3][_][_][4][5][6]
│
│ 【步骤4】缩小间隙 (gapStart++)
│ gapStart: 2 → 3
│
│ 【插入完成】
│ 最终状态:
│ size = 6
│ gapStart = 3
│ gapEnd = 5
│ gapSize = 2
│ buffer = [1][2][3][_][_][4][5][6]
│ 逻辑内容 = [1, 2, 3, 4, 5, 6]
└─────────────────────────────────────────────────────────────
关键步骤图解
插入 3 到位置 2 的间隙移动过程
初始状态 (gapStart=5, gapEnd=8):
┌───┬───┬───┬───┬───┬───┬───┬───┐
│ 1 │ 2 │ 4 │ 5 │ 6 │ _ │ _ │ _ │
└───┴───┴───┴───┴───┴───┴───┴───┘
0 1 2 3 4 5 6 7
↑ ↑
gapStart gapEnd
逻辑视图: [1, 2, 4, 5, 6]
↑
要在这里插入 3
═══════════════════════════════════════════════════════════
步骤1: 复制 buffer[2..4] 到 buffer[5..7]
┌───┬───┬───┬───┬───┬───┬───┬───┐
│ 1 │ 2 │ 4 │ 5 │ 6 │ 4 │ 5 │ 6 │
└───┴───┴───┴───┴───┴───┴───┴───┘
0 1 2 3 4 5 6 7
└───────────┘
复制到这里 ↗
═══════════════════════════════════════════════════════════
步骤2: 清除原位置 buffer[2..4]
┌───┬───┬───┬───┬───┬───┬───┬───┐
│ 1 │ 2 │ _ │ _ │ _ │ 4 │ 5 │ 6 │
└───┴───┴───┴───┴───┴───┴───┴───┘
0 1 2 3 4 5 6 7
↑ ↑
gapStart gapEnd
(2) (5)
═══════════════════════════════════════════════════════════
步骤3: 在 gapStart 位置插入 3
┌───┬───┬───┬───┬───┬───┬───┬───┐
│ 1 │ 2 │ 3 │ _ │ _ │ 4 │ 5 │ 6 │
└───┴───┴───┴───┴───┴───┴───┴───┘
0 1 2 3 4 5 6 7
↑
插入 3
═══════════════════════════════════════════════════════════
步骤4: gapStart++
┌───┬───┬───┬───┬───┬───┬───┬───┐
│ 1 │ 2 │ 3 │ _ │ _ │ 4 │ 5 │ 6 │
└───┴───┴───┴───┴───┴───┴───┴───┘
0 1 2 3 4 5 6 7
↑ ↑
gapStart gapEnd
(3) (5)
逻辑视图: [1, 2, 3, 4, 5, 6] ✓
变量追踪表
| 操作 | buffer 物理状态 | gapStart | gapEnd | gapSize | size | 逻辑内容 |
|---|---|---|---|---|---|---|
| 初始 | [_][_][_][_][_][_][_][_] | 0 | 8 | 8 | 0 | [] |
| insert(0,1) | [1][_][_][_][_][_][_][_] | 1 | 8 | 7 | 1 | [1] |
| insert(1,2) | [1][2][_][_][_][_][_][_] | 2 | 8 | 6 | 2 | [1,2] |
| insert(2,4) | [1][2][4][_][_][_][_][_] | 3 | 8 | 5 | 3 | [1,2,4] |
| insert(3,6) | [1][2][4][5][_][_][_][_] | 4 | 8 | 4 | 4 | [1,2,4,5] |
| insert(4,6) | [1][2][4][5][6][_][_][_] | 5 | 8 | 3 | 5 | [1,2,4,5,6] |
| insert(2,3) | ||||||
| └ moveGap(2) 前 | [1][2][4][5][6][_][_][_] | 5 | 8 | 3 | 5 | [1,2,4,5,6] |
| └ 复制后 | [1][2][4][5][6][4][5][6] | 5 | 8 | - | - | - |
| └ 清除后 | [1][2][_][_][_][4][5][6] | 2 | 5 | 3 | 5 | [1,2,4,5,6] |
| └ 插入 3 | [1][2][3][_][_][4][5][6] | 2 | 5 | - | - | - |
| └ gapStart++ | [1][2][3][_][_][4][5][6] | 3 | 5 | 2 | 6 | [1,2,3,4,5,6] |
总结
- 顺序插入时(如构建初始数组),间隙始终在末尾,无需移动,O(1)
- 中间插入时(如在位置 2 插入 3),需要移动间隙,复制元素,O(n)
- 间隙的作用:将复杂的数组插入操作(需要移动后续所有元素)转化为简单的间隙移动 + O(1) 插入