当前位置: 首页 > news >正文

线性数据结构深度解析:数组、链表、栈与队列的实现与应用

一、数组:连续内存的高效访问

1.1 数组的核心特性与内存模型

数组是最基础的线性数据结构,其核心在于​​连续内存分配​​。这种存储方式带来了独特的性能特征:

# 数组的内存访问演示
import ctypesclass DynamicArray:def __init__(self):self._n = 0  # 当前元素数量self._capacity = 1  # 初始容量self._A = self._make_array(self._capacity)  # 底层数组def __len__(self):return self._ndef __getitem__(self, k):"""随机访问:时间复杂度O(1)"""if not 0 <= k < self._n:raise IndexError('索引越界')return self._A[k]  # 直接计算内存地址:base_address + k * element_sizedef append(self, obj):"""追加元素:均摊时间复杂度O(1)"""if self._n == self._capacity:self._resize(2 * self._capacity)  # 动态扩容self._A[self._n] = objself._n += 1def _resize(self, c):"""扩容操作:时间复杂度O(n)"""B = self._make_array(c)for k in range(self._n):B[k] = self._A[k]self._A = Bself._capacity = cdef _make_array(self, c):return (c * ctypes.py_object)()

​数组操作的复杂度分析:​

✅ ​​随机访问​​:O(1) - 通过索引直接计算内存地址

❌ ​​插入/删除​​:O(n) - 需要移动后续元素

⚠️ ​​动态扩容​​:均摊分析后追加操作仍为O(1)

1.2 多维数组的存储方式

理解多维数组的内存布局对性能优化至关重要:

# 二维数组的行优先 vs 列优先存储
def matrix_access_demo():matrix = [[1, 2, 3],[4, 5, 6],[7, 8, 9]]print("行优先遍历(缓存友好):")for i in range(3):for j in range(3):  # 内层循环连续访问内存print(matrix[i][j], end=' ')print()print("列优先遍历(缓存不友好):")for j in range(3):for i in range(3):  # 内层循环跳跃访问print(matrix[i][j], end=' ')print()# 实际应用:图像处理中的矩阵操作
def image_processing_example():# 假设一个3x3的灰度图像image = [[100, 120, 110],[130, 140, 125],[115, 135, 145]]# 行优先处理更高效for row in image:for pixel in row:process_pixel(pixel)  # 连续内存访问

1.3 动态数组的工程实践

​Python列表的实现原理:​

# 模拟Python列表的动态扩容策略
class PyListSimulator:def __init__(self):self.size = 0self.capacity = 4  # 初始容量self.data = [None] * self.capacityself.growth_factor = 2  # 增长因子def append(self, item):if self.size == self.capacity:self._grow()self.data[self.size] = itemself.size += 1def _grow(self):new_capacity = int(self.capacity * self.growth_factor)new_data = [None] * new_capacityfor i in range(self.size):new_data[i] = self.data[i]self.data = new_dataself.capacity = new_capacityprint(f"扩容:{self.capacity//self.growth_factor} -> {self.capacity}")

二、链表:灵活的非连续存储

2.1 链表的基本结构与类型

链表通过指针连接节点,提供了动态内存管理的灵活性:

class ListNode:"""链表节点定义"""def __init__(self, val=0, next=None):self.val = valself.next = nextclass LinkedList:"""单链表实现"""def __init__(self):self.head = Noneself.size = 0def get(self, index: int) -> int:"""按索引访问:时间复杂度O(n)"""if index < 0 or index >= self.size:return -1curr = self.headfor _ in range(index):curr = curr.nextreturn curr.valdef add_at_head(self, val: int) -> None:"""头插法:时间复杂度O(1)"""new_node = ListNode(val)new_node.next = self.headself.head = new_nodeself.size += 1def add_at_tail(self, val: int) -> None:"""尾插法:时间复杂度O(n)"""new_node = ListNode(val)if not self.head:self.head = new_nodeelse:curr = self.headwhile curr.next:curr = curr.nextcurr.next = new_nodeself.size += 1

2.2 双链表与循环链表

​双向链表​​提供了前后双向遍历的能力:

class DoublyListNode:def __init__(self, val=0):self.val = valself.prev = Noneself.next = Noneclass DoublyLinkedList:def __init__(self):self.head = Noneself.tail = Noneself.size = 0def add_first(self, val):"""在链表头部添加节点"""new_node = DoublyListNode(val)if not self.head:self.head = self.tail = new_nodeelse:new_node.next = self.headself.head.prev = new_nodeself.head = new_nodeself.size += 1def remove_last(self):"""删除尾节点"""if not self.tail:return Noneremoved = self.tailif self.head == self.tail:self.head = self.tail = Noneelse:self.tail = self.tail.prevself.tail.next = Noneself.size -= 1return removed.val

2.3 链表经典算法题解

​1. 链表反转(迭代法):​

def reverse_list(head):prev = Nonecurr = headwhile curr:next_temp = curr.next  # 保存下一个节点curr.next = prev       # 反转指针prev = curr           # 移动prevcurr = next_temp      # 移动currreturn prev

​2. 快慢指针应用:​

def has_cycle(head):"""检测链表是否有环"""if not head or not head.next:return Falseslow = headfast = head.nextwhile slow != fast:if not fast or not fast.next:return Falseslow = slow.nextfast = fast.next.nextreturn Truedef middle_node(head):"""找到链表的中间节点"""slow = fast = headwhile fast and fast.next:slow = slow.nextfast = fast.next.nextreturn slow

​3. LRU缓存实现:​

class LRUCache:def __init__(self, capacity: int):self.capacity = capacityself.cache = {}self.head = DoublyListNode(0)  # 伪头节点self.tail = DoublyListNode(0)  # 伪尾节点self.head.next = self.tailself.tail.prev = self.headdef _add_node(self, node):"""在头部添加节点"""node.prev = self.headnode.next = self.head.nextself.head.next.prev = nodeself.head.next = nodedef _remove_node(self, node):"""删除节点"""prev = node.prevnext_node = node.nextprev.next = next_nodenext_node.prev = prevdef _move_to_head(self, node):"""移动节点到头部"""self._remove_node(node)self._add_node(node)def get(self, key: int) -> int:node = self.cache.get(key, None)if not node:return -1self._move_to_head(node)return node.valuedef put(self, key: int, value: int) -> None:node = self.cache.get(key)if not node:new_node = DoublyListNode(value)new_node.key = keyself.cache[key] = new_nodeself._add_node(new_node)if len(self.cache) > self.capacity:tail = self.tail.prevself._remove_node(tail)del self.cache[tail.key]else:node.value = valueself._move_to_head(node)

三、栈:LIFO的线性结构

3.1 栈的基本操作与实现

栈遵循​​后进先出​​原则,支持三种基本操作:

class ArrayStack:"""基于数组的栈实现"""def __init__(self):self._items = []def push(self, item):"""入栈:O(1)"""self._items.append(item)def pop(self):"""出栈:O(1)"""if self.is_empty():raise Exception("栈为空")return self._items.pop()def peek(self):"""查看栈顶:O(1)"""if self.is_empty():raise Exception("栈为空")return self._items[-1]def is_empty(self):return len(self._items) == 0def size(self):return len(self._items)class LinkedStack:"""基于链表的栈实现"""class _Node:def __init__(self, item):self.item = itemself.next = Nonedef __init__(self):self._top = Noneself._size = 0def push(self, item):new_node = self._Node(item)new_node.next = self._topself._top = new_nodeself._size += 1def pop(self):if self.is_empty():raise Exception("栈为空")item = self._top.itemself._top = self._top.nextself._size -= 1return itemdef peek(self):if self.is_empty():raise Exception("栈为空")return self._top.itemdef is_empty(self):return self._top is Nonedef size(self):return self._size

3.2 栈的经典应用场景

​1. 括号匹配校验:​

def is_valid_parentheses(s: str) -> bool:stack = []mapping = {')': '(', '}': '{', ']': '['}for char in s:if char in mapping.values():  # 左括号入栈stack.append(char)elif char in mapping:  # 右括号匹配if not stack or stack[-1] != mapping[char]:return Falsestack.pop()else:return Falsereturn not stack  # 栈应为空# 测试用例
print(is_valid_parentheses("()[]{}"))  # True
print(is_valid_parentheses("([)]"))    # False

​2. 表达式求值:​

def evaluate_expression(expression: str) -> int:def apply_operator(operators, values):operator = operators.pop()right = values.pop()left = values.pop()if operator == '+': values.append(left + right)elif operator == '-': values.append(left - right)elif operator == '*': values.append(left * right)elif operator == '/': values.append(int(left / right))precedence = {'+': 1, '-': 1, '*': 2, '/': 2}values = []operators = []i = 0while i < len(expression):if expression[i] == ' ':i += 1continueif expression[i].isdigit():  # 处理数字j = iwhile j < len(expression) and expression[j].isdigit():j += 1values.append(int(expression[i:j]))i = jelif expression[i] == '(':  # 左括号operators.append(expression[i])i += 1elif expression[i] == ')':  # 右括号while operators and operators[-1] != '(':apply_operator(operators, values)operators.pop()  # 弹出左括号i += 1else:  # 运算符while (operators and operators[-1] != '(' and precedence[operators[-1]] >= precedence[expression[i]]):apply_operator(operators, values)operators.append(expression[i])i += 1while operators:apply_operator(operators, values)return values[0]

四、队列:FIFO的线性结构

4.1 队列的基本实现

​基于数组的简单队列:​

class ArrayQueue:def __init__(self, capacity=10):self._items = [None] * capacityself._front = 0self._rear = 0self._size = 0def enqueue(self, item):"""入队:O(1)"""if self._size == len(self._items):self._resize(2 * len(self._items))self._items[self._rear] = itemself._rear = (self._rear + 1) % len(self._items)self._size += 1def dequeue(self):"""出队:O(1)"""if self.is_empty():raise Exception("队列为空")item = self._items[self._front]self._items[self._front] = Noneself._front = (self._front + 1) % len(self._items)self._size -= 1return itemdef _resize(self, capacity):old_items = self._itemsself._items = [None] * capacitywalk = self._frontfor i in range(self._size):self._items[i] = old_items[walk]walk = (walk + 1) % len(old_items)self._front = 0self._rear = self._size

4.2 循环队列解决假溢出

​循环队列实现:​

class CircularQueue:def __init__(self, k: int):self.queue = [None] * kself.head = 0self.tail = 0self.count = 0self.capacity = kdef enqueue(self, value: int) -> bool:if self.is_full():return Falseself.queue[self.tail] = valueself.tail = (self.tail + 1) % self.capacityself.count += 1return Truedef dequeue(self) -> bool:if self.is_empty():return Falseself.head = (self.head + 1) % self.capacityself.count -= 1return Truedef front(self) -> int:if self.is_empty():return -1return self.queue[self.head]def rear(self) -> int:if self.is_empty():return -1return self.queue[(self.tail - 1) % self.capacity]def is_empty(self) -> bool:return self.count == 0def is_full(self) -> bool:return self.count == self.capacity

4.3 双端队列与应用

​双端队列实现:​

class Deque:def __init__(self):self._items = []def add_front(self, item):self._items.insert(0, item)def add_rear(self, item):self._items.append(item)def remove_front(self):if self.is_empty():raise Exception("双端队列为空")return self._items.pop(0)def remove_rear(self):if self.is_empty():raise Exception("双端队列为空")return self._items.pop()def is_empty(self):return len(self._items) == 0def size(self):return len(self._items)

​滑动窗口最大值问题:​

def max_sliding_window(nums, k):from collections import dequeif not nums:return []result = []dq = deque()  # 存储索引for i in range(len(nums)):# 移除超出窗口范围的元素if dq and dq[0] < i - k + 1:dq.popleft()# 移除比当前元素小的元素while dq and nums[dq[-1]] < nums[i]:dq.pop()dq.append(i)# 当窗口形成时记录最大值if i >= k - 1:result.append(nums[dq[0]])return result

五、学习建议与实践指南

5.1 手写实现练习

​建议完成的实现练习:​

# 练习1:实现带迭代器的链表
class LinkedListWithIterator:def __init__(self):self.head = Nonedef __iter__(self):current = self.headwhile current:yield current.valcurrent = current.next# 练习2:实现最小栈
class MinStack:def __init__(self):self.stack = []self.min_stack = []  # 辅助栈记录最小值def push(self, x: int) -> None:self.stack.append(x)if not self.min_stack or x <= self.min_stack[-1]:self.min_stack.append(x)def pop(self) -> None:if self.stack.pop() == self.min_stack[-1]:self.min_stack.pop()def top(self) -> int:return self.stack[-1]def get_min(self) -> int:return self.min_stack[-1]

总结

线性数据结构是算法学习的基石,掌握它们的特性和应用场景至关重要:

​数组​​:连续内存,随机访问高效,适合读多写少的场景

链表​​:动态内存,插入删除高效,适合频繁修改的场景

栈​​:LIFO特性,适合需要"撤销"操作的场景

​队列​​:FIFO特性,适合任务调度和缓冲场景

理解每种结构的​​时间复杂度特征​​和​​适用场景​​,能够帮助我们在实际编程中做出正确的选择。下一阶段我们将进入非线性数据结构的学习,包括树、堆、图等更复杂的数据结构。

http://www.dtcms.com/a/541938.html

相关文章:

  • 顺德网站建设公司做网站送的企业邮箱能用吗
  • 兼职做国外网站钻前怀化网络推广公司
  • 如何做好楼宇自控系统设计?以服务人们需求为核心的路径
  • 做分析图网站桂林网站开发公司
  • 三亚网站建设费用郫县建设局网站
  • 网至普的营销型网站建设网页设计基础怎么制作水平导航条
  • SRE 进阶:AI 驱动的集群全自动化排查指南(零人工干预版)
  • 2025年接单经验和软件外包平台一览
  • 可以免费商用国外印花图案设计网站wordpress虚线框可序列
  • wordpress建立数据库错误关键词优化怎么做
  • 网站建设网银开通请别人做网站签订合同
  • 在 C 语言中判断字符串非空:str str[0] vs strlen
  • 使用 iText 9 为 PDF 添加文字水印的完整实战
  • cms仿站四川建设网官网app
  • Linux系统日志持久化配置完全指南:让日志在重启后不丢失
  • 江苏省建设工程注册中心网站外贸求购信息网
  • 双峰网站建设安徽中兴建设工程有限公司网站
  • Spring进阶 - Spring事务理论+实战,一文吃透事务
  • 3 VTK中的数据结构
  • IROS 2025 视触觉结合磁硅胶的MagicGel传感器
  • BETAFLIGHT CLI教程 带有串口软件进入cli模式教程
  • 做临时工看哪个网站网上服务系统
  • 哪家做网站性价比高如何做外贸业务
  • 做网站注册公司一个空间可以做几个网站
  • 网站建设咨询服务合同wordpress国外主题修改
  • 做淘宝要用的网站手游网站源码下载
  • Mysql基础知识之SQL语句——库表管理操作
  • 类似于建设通的网站巴中做网站 微信开发
  • dede装修网站模板预付网站建设服务费如何入账
  • Python异常处理详解:从概念到实战,让程序优雅应对错误