安卓Compose原理二之GapBuffer

26 阅读11分钟

数组的插入删除时间复杂度是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 = 0gapStart = 0gapEnd = 8gapSize = 8buffer = [_][_][_][_][_][_][_][_]
│
│ 【步骤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 = 1gapStart = 1gapEnd = 8gapSize = 7buffer = [1][_][_][_][_][_][_][_]
│     逻辑内容 = [1]
└─────────────────────────────────────────────────────────────

插入 2 到位置 1

┌─────────────────────────────────────────────────────────────
│ 调用 insert(index=1, element=2)
├─────────────────────────────────────────────────────────────
│ 【进入 insert 方法】
│   当前状态:
│     size = 1gapStart = 1gapEnd = 8gapSize = 7buffer = [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 = 2gapStart = 2gapEnd = 8gapSize = 6buffer = [1][2][_][_][_][_][_][_]
│     逻辑内容 = [1, 2]
└─────────────────────────────────────────────────────────────

插入 4 到位置 2

┌─────────────────────────────────────────────────────────────
│ 调用 insert(index=2, element=4)
├─────────────────────────────────────────────────────────────
│ 【进入 insert 方法】
│   当前状态:
│     size = 2gapStart = 2gapEnd = 8gapSize = 6buffer = [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 = 3gapStart = 3gapEnd = 8gapSize = 5buffer = [1][2][4][_][_][_][_][_]
│     逻辑内容 = [1, 2, 4]
└─────────────────────────────────────────────────────────────

插入 5 到位置 3

┌─────────────────────────────────────────────────────────────
│ 调用 insert(index=3, element=5)
├─────────────────────────────────────────────────────────────
│ 【进入 insert 方法】
│   当前状态:
│     size = 3gapStart = 3gapEnd = 8gapSize = 5buffer = [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 = 4gapStart = 4gapEnd = 8gapSize = 4buffer = [1][2][4][5][_][_][_][_]
│     逻辑内容 = [1, 2, 4, 5]
└─────────────────────────────────────────────────────────────

插入 6 到位置 4

┌─────────────────────────────────────────────────────────────
│ 调用 insert(index=4, element=6)
├─────────────────────────────────────────────────────────────
│ 【进入 insert 方法】
│   当前状态:
│     size = 4gapStart = 4gapEnd = 8gapSize = 4buffer = [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 = 5gapStart = 5gapEnd = 8gapSize = 3buffer = [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 = 5gapStart = 5gapEnd = 8gapSize = 3buffer = [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 = 6gapStart = 3gapEnd = 5gapSize = 2buffer = [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 物理状态gapStartgapEndgapSizesize逻辑内容
初始[_][_][_][_][_][_][_][_]0880[]
insert(0,1)[1][_][_][_][_][_][_][_]1871[1]
insert(1,2)[1][2][_][_][_][_][_][_]2862[1,2]
insert(2,4)[1][2][4][_][_][_][_][_]3853[1,2,4]
insert(3,6)[1][2][4][5][_][_][_][_]4844[1,2,4,5]
insert(4,6)[1][2][4][5][6][_][_][_]5835[1,2,4,5,6]
insert(2,3)
└ moveGap(2) 前[1][2][4][5][6][_][_][_]5835[1,2,4,5,6]
└ 复制后[1][2][4][5][6][4][5][6]58---
└ 清除后[1][2][_][_][_][4][5][6]2535[1,2,4,5,6]
└ 插入 3[1][2][3][_][_][4][5][6]25---
└ gapStart++[1][2][3][_][_][4][5][6]3526[1,2,3,4,5,6]

总结

  1. 顺序插入时(如构建初始数组),间隙始终在末尾,无需移动,O(1)
  2. 中间插入时(如在位置 2 插入 3),需要移动间隙,复制元素,O(n)
  3. 间隙的作用:将复杂的数组插入操作(需要移动后续所有元素)转化为简单的间隙移动 + O(1) 插入