顺序表用Python3定义与增删改查

顺序表用Python3定义与增删改查


一、顺序表的设计

核心要素:

属性 含义
data 底层数组,存元素
size 当前元素个数
capacity 当前容量

关键点

  • 元素存在 data[0..size-1],后面的位置空着。
  • 插入/删除需要搬移元素
  • 容量不够时扩容

二、完整代码

python 复制代码
class SeqList:
    """顺序表(动态数组实现)"""

    def __init__(self, capacity=10):
        if capacity <= 0:
            raise ValueError("容量必须大于 0")
        self.data = [None] * capacity   # 底层数组
        self.size = 0                   # 当前元素个数
        self.capacity = capacity        # 当前容量

    # ---------- 内部辅助 ----------
    def _resize(self, new_capacity):
        """扩容/缩容:把原数据搬到新数组"""
        new_data = [None] * new_capacity
        for i in range(self.size):
            new_data[i] = self.data[i]
        self.data = new_data
        self.capacity = new_capacity

    def _check_index(self, index):
        """检查访问索引是否合法"""
        if index < 0 or index >= self.size:
            raise IndexError(f"索引 {index} 越界,合法范围 [0, {self.size - 1}]")

    def _check_insert_index(self, index):
        """检查插入索引是否合法(可以等于 size)"""
        if index < 0 or index > self.size:
            raise IndexError(f"插入索引 {index} 越界,合法范围 [0, {self.size}]")

    # ---------- 增 ----------
    def insert(self, index, value):
        """在 index 位置插入 value,O(n)"""
        self._check_insert_index(index)

        # 容量不够,扩容为原来的 2 倍
        if self.size == self.capacity:
            self._resize(self.capacity * 2)

        # 从后往前搬移,给新元素腾位置
        for i in range(self.size, index, -1):
            self.data[i] = self.data[i - 1]

        self.data[index] = value
        self.size += 1

    def append(self, value):
        """尾部追加,均摊 O(1)"""
        self.insert(self.size, value)

    def prepend(self, value):
        """头部插入,O(n)"""
        self.insert(0, value)

    # ---------- 删 ----------
    def delete(self, index):
        """删除 index 位置元素,返回被删的值,O(n)"""
        self._check_index(index)

        value = self.data[index]

        # 从前往后搬移,覆盖被删元素
        for i in range(index, self.size - 1):
            self.data[i] = self.data[i + 1]

        self.data[self.size - 1] = None   # 末尾置空
        self.size -= 1

        # 缩容:元素太少时,容量减半(可选优化)
        if self.size > 0 and self.size <= self.capacity // 4:
            self._resize(max(self.capacity // 2, 10))

        return value

    def remove(self, value):
        """按值删除第一个匹配项,O(n)"""
        index = self.index_of(value)
        if index == -1:
            raise ValueError(f"值 {value} 不存在")
        return self.delete(index)

    def pop(self):
        """删除尾部,返回被删的值,O(1)"""
        if self.size == 0:
            raise IndexError("顺序表为空")
        return self.delete(self.size - 1)

    def clear(self):
        """清空"""
        self.data = [None] * self.capacity
        self.size = 0

    # ---------- 改 ----------
    def update(self, index, value):
        """修改 index 位置的值,O(1)"""
        self._check_index(index)
        self.data[index] = value

    # ---------- 查 ----------
    def get(self, index):
        """按索引获取值,O(1)"""
        self._check_index(index)
        return self.data[index]

    def index_of(self, value):
        """按值查找索引,找不到返回 -1,O(n)"""
        for i in range(self.size):
            if self.data[i] == value:
                return i
        return -1

    def contains(self, value):
        """判断是否包含某值,O(n)"""
        return self.index_of(value) != -1

    # ---------- 其他 ----------
    def is_empty(self):
        return self.size == 0

    def length(self):
        return self.size

    def __len__(self):
        return self.size

    def __getitem__(self, index):
        """支持 lst[index] 访问"""
        return self.get(index)

    def __setitem__(self, index, value):
        """支持 lst[index] = value"""
        self.update(index, value)

    def __contains__(self, value):
        """支持 value in lst"""
        return self.contains(value)

    def __iter__(self):
        """支持 for x in lst"""
        for i in range(self.size):
            yield self.data[i]

    def __str__(self):
        return "[" + ", ".join(str(self.data[i]) for i in range(self.size)) + "]"

    def __repr__(self):
        return f"SeqList({self})"

三、测试代码

python 复制代码
if __name__ == "__main__":
    sl = SeqList()

    # ---------- 增 ----------
    sl.append(10)
    sl.append(20)
    sl.append(30)
    print(sl)              # [10, 20, 30]

    sl.insert(1, 15)
    print(sl)              # [10, 15, 20, 30]

    sl.prepend(5)
    print(sl)              # [5, 10, 15, 20, 30]

    # ---------- 查 ----------
    print(sl.get(0))       # 5
    print(sl[2])           # 15
    print(sl.index_of(20)) # 3
    print(20 in sl)        # True
    print(len(sl))         # 5

    # ---------- 改 ----------
    sl.update(0, 100)
    print(sl)              # [100, 10, 15, 20, 30]

    sl[1] = 200
    print(sl)              # [100, 200, 15, 20, 30]

    # ---------- 删 ----------
    sl.delete(0)
    print(sl)              # [200, 15, 20, 30]

    sl.remove(15)
    print(sl)              # [200, 20, 30]

    sl.pop()
    print(sl)              # [200, 20]

    # ---------- 遍历 ----------
    for x in sl:
        print(x, end=" ")  # 200 20
    print()

    # ---------- 清空 ----------
    sl.clear()
    print(sl)              # []
    print(sl.is_empty())   # True

    # ---------- 扩容测试 ----------
    sl2 = SeqList(capacity=2)
    for i in range(10):
        sl2.append(i)
    print(sl2)             # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    print(sl2.capacity)    # 16(扩容过程:2→4→8→16)

四、关键操作图解

1. 插入 insert(2, 99)

ini 复制代码
原数组: [10, 20, 30, 40, _]
size=4

从后往前搬移:
[10, 20, 30, 40, _]
[10, 20, 30, 40, 40]   ← data[4] = data[3]
[10, 20, 30, 30, 40]   ← data[3] = data[2]
[10, 20, 99, 30, 40]   ← data[2] = 99

结果: [10, 20, 99, 30, 40]
size=5

2. 删除 delete(1)

ini 复制代码
原数组: [10, 20, 30, 40, 50]
size=5

从前往后搬移:
[10, 20, 30, 40, 50]
[10, 30, 30, 40, 50]   ← data[1] = data[2]
[10, 30, 40, 40, 50]   ← data[2] = data[3]
[10, 30, 40, 50, 50]   ← data[3] = data[4]

末尾置空:
[10, 30, 40, 50, None]

结果: [10, 30, 40, 50]
size=4

3. 扩容

ini 复制代码
容量满: [10, 20, 30, 40]  capacity=4

申请新数组(2 倍): [None] * 8
搬移: [10, 20, 30, 40, None, None, None, None]
插入: [10, 20, 30, 40, 50, None, None, None]
capacity=8

五、复杂度总结

操作 时间复杂度 说明
按索引访问 get O(1) 连续内存,直接定位
按索引修改 update O(1) 直接定位
尾部追加 append O(1) 均摊 偶尔扩容,均摊下来 O(1)
头部插入 prepend O(n) 所有元素后移
中间插入 insert O(n) 部分元素后移
删除 delete O(n) 部分元素前移
按值查找 index_of O(n) 遍历
按值删除 remove O(n) 查找 + 删除

六、顺序表 vs 链表

对比项 顺序表 链表
内存 连续 分散
随机访问 O(1) O(n)
头部插入/删除 O(n) O(1)
尾部插入 O(1) 均摊 O(n)(无尾指针)
中间插入/删除 O(n) O(n)(定位)+ O(1)(改指针)
按值查找 O(n) O(n)
扩容 需要搬移 不需要
内存开销 可能浪费 额外指针开销
缓存友好

选择原则

  • 频繁随机访问 → 顺序表。
  • 频繁头部/中间增删 → 链表。
  • 大多数场景 → Python 的 list 就够用。

七、常见坑

说明 正确做法
插入位置越界 插入可以等于 size 判断 index > size
访问位置越界 访问必须小于 size 判断 index >= size
删除后忘记 size -= 1 长度错误 删完减 1
删除后忘记置空 内存泄漏 data[size-1] = None
扩容忘记搬移 数据丢失 逐个复制
缩容太频繁 性能抖动 用 1/4 阈值,不要用 1/2
list 模拟时混淆 size 和 len 概念混淆 size 是逻辑长度,capacity 是物理容量

为什么缩容阈值用 1/4 而不是 1/2?

  • 如果用 1/2,在临界点反复插入删除会导致频繁扩容缩容(抖动)。
  • 用 1/4,留出缓冲,避免抖动。

八、一句话总结

问题 答案
顺序表是什么? 用连续内存存储的线性表
核心属性? data(数组)、size(元素个数)、capacity(容量)
增? insertappendprepend,容量不够扩容
删? deleteremovepop,搬移元素
改? update,O(1)
查? get(O(1))、index_of(O(n))
最大优势? 随机访问 O(1)
最大劣势? 中间插入/删除 O(n)
和 list 关系? Python 的 list 就是动态顺序表
和链表区别? 顺序表连续、随机访问快;链表分散、增删快

核心记住:顺序表 = 连续内存 + size + capacity。随机访问 O(1),中间增删 O(n),容量不够要扩容。手写一遍能彻底理解 Python list 的底层原理。

相关推荐
子林super1 小时前
Python非空判断与类型检查写法
github
子林super1 小时前
Python list与array关键区别及使用场景
github
子林super1 小时前
Python中None与null的区别
github
u1301303 小时前
GitHub 热榜项目:周榜(2026-09-20)
人工智能·github
u1301305 小时前
GitHub 热榜项目:日榜(2026-09-20)
人工智能·github
逛逛GitHub5 小时前
外网 3500 万人围观的 Jev 模型,有这 10 个神奇玩法。
github
m4Rk_5 小时前
【论文阅读】Agent 记忆机制(76):SEEM——从碎片检索到完整事件重建
论文阅读·人工智能·学习·开源·github
YuePeng+6 小时前
我给 Claude Code 装了这个 SKILL,它开始自己写管理后台了
github
daxiangxm6 小时前
【趣味休息】“围住小猫在线玩”-“困住小猫”,又回来了
数据结构·人工智能·vscode·github·php