1145 字
6 分钟
260715GO数组

数组(顺序存储)基本原理#

一、数组两大分类#

  • 静态数组:原始形态,是一块固定长度、连续的内存空间,依靠索引直接访问内存。长度初始化后不可改变。
  • 动态数组:基于静态数组封装而来,内置 pushinsertremove 等常用 API,可自动完成扩容/缩容,简化增删操作。
    • 后续栈、队列、哈希表等很多数据结构底层都依赖动态数组实现
    • 算法刷题和开发日常一般直接使用动态数组(Go 的 slice),静态数组多用于理解底层原理

Go 静态数组定义#

// 定义长度固定为 10 的 int 静态数组
var arr [10]int
// 索引赋值
arr[0] = 1
arr[1] = 2
// 索引取值
a := arr[0]
  • 核心特性:随机访问 — 通过索引可 O(1) 时间直接读取/修改对应元素

二、静态数组:增删原理 & 时间复杂度#

1. 新增元素#

情况1:末尾追加(有空闲空间)#

直接对末尾空位索引赋值,无需移动元素

var arr [10]int
// 前4个位置存入元素
for i := 0; i < 4; i++ {
arr[i] = i
}
// 末尾追加元素
arr[4] = 4
arr[5] = 5
  • 时间复杂度:O(1)

情况2:中间插入(有空闲空间)#

需要把插入位置及之后的原有元素向后整体搬移一位(倒序遍历防止数据覆盖),腾出空位后插入新元素

package main
import "fmt"
func main() {
var arr [10]int
for i := 0; i < 4; i++ {
arr[i] = i
}
// 在索引 2 插入元素 666,后移后续元素
for i := 4; i > 2; i-- {
arr[i] = arr[i-1]
}
arr[2] = 666
fmt.Println(arr)
}
  • 时间复杂度:O(N)

情况3:数组空间已满#

需要手动扩容:新建一块更大的静态数组,复制原有全部数据,再进行新增操作

// 原数组已满
arr := make([]int, 10)
for i := 0; i < 10; i++ {
arr[i] = i
}
// 创建更大数组并复制原数据
newArr := make([]int, 20)
for i := 0; i < 10; i++ {
newArr[i] = arr[i]
}
// 在新数组末尾追加元素
newArr[10] = 10
  • 扩容涉及全量拷贝,单次扩容操作复杂度:O(N)

2. 删除元素#

情况1:删除末尾元素#

直接标记/截断末尾元素,无需搬移数据

var arr [10]int
for i := 0; i < 5; i++ {
arr[i] = i
}
// 删除末尾元素(示例标记为-1)
arr[4] = -1
  • 时间复杂度:O(1)

情况2:删除中间元素#

把被删元素后面的元素整体向前搬移一位(正序遍历),保持数组连续性

var arr [10]int
for i := 0; i < 5; i++ {
arr[i] = i
}
// 删除索引1的元素,后续元素前移
for i := 1; i < 4; i++ {
arr[i] = arr[i + 1]
}
arr[4] = -1
  • 时间复杂度:O(N)

3. 查 & 改#

  • 按索引查询元素:O(1)
  • 按索引修改元素:O(1)
  • 按元素值遍历查找(非索引查找):O(N)

4. 静态数组复杂度总览#

    • 末尾追加(有空位):O(1)
    • 中间插入:O(N)
    • 满数组扩容新增:O(N)
    • 删除末尾元素:O(1)
    • 删除中间元素:O(N)
  • 查(索引访问):O(1)
  • 改(索引修改):O(1)

三、动态数组(Go Slice)用法#

底层依旧依托静态数组,自动处理扩容、缩容和数据搬移,对外提供简洁 API

package main
import "fmt"
func main() {
// 创建初始长度为0的动态数组
arr := make([]int, 0)
// 末尾追加元素
for i := 0; i < 10; i++ {
arr = append(arr, i)
}
// 在索引 2 插入元素 666
arr = append(arr[:2], append([]int{666}, arr[2:]...)...)
// 在头部插入元素 -1
arr = append([]int{-1}, arr...)
// 删除末尾元素
arr = arr[:len(arr)-1]
// 删除索引 2 的元素
arr = append(arr[:2], arr[3:]...)
// 索引查询
a := arr[0]
fmt.Println(a)
// 索引修改
arr[0] = 100
// 根据值查找索引(遍历查找,复杂度 O(N))
index := -1
for i, v := range arr {
if v == 666 {
index = i
break
}
}
fmt.Println("666的索引:", index)
}

四、核心特点总结#

  1. ✅ 优点:支持索引随机访问,末尾增删效率极高(O(1)),结构简单
  2. ❌ 缺点:中间位置增删效率差(O(N)),会产生大量数据搬移;静态数组长度固定不够灵活
  3. 底层本质:连续内存存储,动态数组 = 静态数组 + 自动扩容/缩容 + 封装增删API
  4. 适用场景:读多写少、主要在尾部增删、频繁按索引随机访问的场景;不适合频繁在数组中间插入删除的场景
260715GO数组
https://fuwari.vercel.app/posts/260715go数组/
作者
anh
发布于
2026-07-15
许可协议
CC BY-NC-SA 4.0