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

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

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

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

python 复制代码
# 数组的内存访问演示
import ctypes

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

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

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

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

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

1.2 多维数组的存储方式

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

python 复制代码
# 二维数组的行优先 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 复制代码
# 模拟Python列表的动态扩容策略
class PyListSimulator:
    def __init__(self):
        self.size = 0
        self.capacity = 4  # 初始容量
        self.data = [None] * self.capacity
        self.growth_factor = 2  # 增长因子
    
    def append(self, item):
        if self.size == self.capacity:
            self._grow()
        self.data[self.size] = item
        self.size += 1
    
    def _grow(self):
        new_capacity = int(self.capacity * self.growth_factor)
        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
        print(f"扩容:{self.capacity//self.growth_factor} -> {self.capacity}")

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

2.1 链表的基本结构与类型

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

python 复制代码
class ListNode:
    """链表节点定义"""
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class LinkedList:
    """单链表实现"""
    def __init__(self):
        self.head = None
        self.size = 0
    
    def get(self, index: int) -> int:
        """按索引访问:时间复杂度O(n)"""
        if index < 0 or index >= self.size:
            return -1
        curr = self.head
        for _ in range(index):
            curr = curr.next
        return curr.val
    
    def add_at_head(self, val: int) -> None:
        """头插法:时间复杂度O(1)"""
        new_node = ListNode(val)
        new_node.next = self.head
        self.head = new_node
        self.size += 1
    
    def add_at_tail(self, val: int) -> None:
        """尾插法:时间复杂度O(n)"""
        new_node = ListNode(val)
        if not self.head:
            self.head = new_node
        else:
            curr = self.head
            while curr.next:
                curr = curr.next
            curr.next = new_node
        self.size += 1

2.2 双链表与循环链表

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

python 复制代码
class DoublyListNode:
    def __init__(self, val=0):
        self.val = val
        self.prev = None
        self.next = None

class DoublyLinkedList:
    def __init__(self):
        self.head = None
        self.tail = None
        self.size = 0
    
    def add_first(self, val):
        """在链表头部添加节点"""
        new_node = DoublyListNode(val)
        if not self.head:
            self.head = self.tail = new_node
        else:
            new_node.next = self.head
            self.head.prev = new_node
            self.head = new_node
        self.size += 1
    
    def remove_last(self):
        """删除尾节点"""
        if not self.tail:
            return None
        removed = self.tail
        if self.head == self.tail:
            self.head = self.tail = None
        else:
            self.tail = self.tail.prev
            self.tail.next = None
        self.size -= 1
        return removed.val

2.3 链表经典算法题解

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

python 复制代码
def reverse_list(head):
    prev = None
    curr = head
    while curr:
        next_temp = curr.next  # 保存下一个节点
        curr.next = prev       # 反转指针
        prev = curr           # 移动prev
        curr = next_temp      # 移动curr
    return prev

​2. 快慢指针应用:​

python 复制代码
def has_cycle(head):
    """检测链表是否有环"""
    if not head or not head.next:
        return False
    
    slow = head
    fast = head.next
    
    while slow != fast:
        if not fast or not fast.next:
            return False
        slow = slow.next
        fast = fast.next.next
    
    return True

def middle_node(head):
    """找到链表的中间节点"""
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
    return slow

​3. LRU缓存实现:​

python 复制代码
class LRUCache:
    def __init__(self, capacity: int):
        self.capacity = capacity
        self.cache = {}
        self.head = DoublyListNode(0)  # 伪头节点
        self.tail = DoublyListNode(0)  # 伪尾节点
        self.head.next = self.tail
        self.tail.prev = self.head
    
    def _add_node(self, node):
        """在头部添加节点"""
        node.prev = self.head
        node.next = self.head.next
        self.head.next.prev = node
        self.head.next = node
    
    def _remove_node(self, node):
        """删除节点"""
        prev = node.prev
        next_node = node.next
        prev.next = next_node
        next_node.prev = prev
    
    def _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 -1
        self._move_to_head(node)
        return node.value
    
    def put(self, key: int, value: int) -> None:
        node = self.cache.get(key)
        if not node:
            new_node = DoublyListNode(value)
            new_node.key = key
            self.cache[key] = new_node
            self._add_node(new_node)
            
            if len(self.cache) > self.capacity:
                tail = self.tail.prev
                self._remove_node(tail)
                del self.cache[tail.key]
        else:
            node.value = value
            self._move_to_head(node)

三、栈:LIFO的线性结构

3.1 栈的基本操作与实现

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

cs 复制代码
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) == 0
    
    def size(self):
        return len(self._items)

class LinkedStack:
    """基于链表的栈实现"""
    class _Node:
        def __init__(self, item):
            self.item = item
            self.next = None
    
    def __init__(self):
        self._top = None
        self._size = 0
    
    def push(self, item):
        new_node = self._Node(item)
        new_node.next = self._top
        self._top = new_node
        self._size += 1
    
    def pop(self):
        if self.is_empty():
            raise Exception("栈为空")
        item = self._top.item
        self._top = self._top.next
        self._size -= 1
        return item
    
    def peek(self):
        if self.is_empty():
            raise Exception("栈为空")
        return self._top.item
    
    def is_empty(self):
        return self._top is None
    
    def size(self):
        return self._size

3.2 栈的经典应用场景

​1. 括号匹配校验:​

python 复制代码
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 False
            stack.pop()
        else:
            return False
    
    return not stack  # 栈应为空

# 测试用例
print(is_valid_parentheses("()[]{}"))  # True
print(is_valid_parentheses("([)]"))    # False

​2. 表达式求值:​

python 复制代码
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 = 0
    
    while i < len(expression):
        if expression[i] == ' ':
            i += 1
            continue
        
        if expression[i].isdigit():  # 处理数字
            j = i
            while j < len(expression) and expression[j].isdigit():
                j += 1
            values.append(int(expression[i:j]))
            i = j
        elif expression[i] == '(':  # 左括号
            operators.append(expression[i])
            i += 1
        elif expression[i] == ')':  # 右括号
            while operators and operators[-1] != '(':
                apply_operator(operators, values)
            operators.pop()  # 弹出左括号
            i += 1
        else:  # 运算符
            while (operators and operators[-1] != '(' and 
                   precedence[operators[-1]] >= precedence[expression[i]]):
                apply_operator(operators, values)
            operators.append(expression[i])
            i += 1
    
    while operators:
        apply_operator(operators, values)
    
    return values[0]

四、队列:FIFO的线性结构

4.1 队列的基本实现

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

python 复制代码
class ArrayQueue:
    def __init__(self, capacity=10):
        self._items = [None] * capacity
        self._front = 0
        self._rear = 0
        self._size = 0
    
    def enqueue(self, item):
        """入队:O(1)"""
        if self._size == len(self._items):
            self._resize(2 * len(self._items))
        self._items[self._rear] = item
        self._rear = (self._rear + 1) % len(self._items)
        self._size += 1
    
    def dequeue(self):
        """出队:O(1)"""
        if self.is_empty():
            raise Exception("队列为空")
        item = self._items[self._front]
        self._items[self._front] = None
        self._front = (self._front + 1) % len(self._items)
        self._size -= 1
        return item
    
    def _resize(self, capacity):
        old_items = self._items
        self._items = [None] * capacity
        walk = self._front
        for i in range(self._size):
            self._items[i] = old_items[walk]
            walk = (walk + 1) % len(old_items)
        self._front = 0
        self._rear = self._size

4.2 循环队列解决假溢出

​循环队列实现:​

python 复制代码
class CircularQueue:
    def __init__(self, k: int):
        self.queue = [None] * k
        self.head = 0
        self.tail = 0
        self.count = 0
        self.capacity = k
    
    def enqueue(self, value: int) -> bool:
        if self.is_full():
            return False
        self.queue[self.tail] = value
        self.tail = (self.tail + 1) % self.capacity
        self.count += 1
        return True
    
    def dequeue(self) -> bool:
        if self.is_empty():
            return False
        self.head = (self.head + 1) % self.capacity
        self.count -= 1
        return True
    
    def front(self) -> int:
        if self.is_empty():
            return -1
        return self.queue[self.head]
    
    def rear(self) -> int:
        if self.is_empty():
            return -1
        return self.queue[(self.tail - 1) % self.capacity]
    
    def is_empty(self) -> bool:
        return self.count == 0
    
    def is_full(self) -> bool:
        return self.count == self.capacity

4.3 双端队列与应用

​双端队列实现:​

python 复制代码
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) == 0
    
    def size(self):
        return len(self._items)

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

python 复制代码
def max_sliding_window(nums, k):
    from collections import deque
    if 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 手写实现练习

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

python 复制代码
# 练习1:实现带迭代器的链表
class LinkedListWithIterator:
    def __init__(self):
        self.head = None
    
    def __iter__(self):
        current = self.head
        while current:
            yield current.val
            current = 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特性,适合任务调度和缓冲场景

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

相关推荐
Zhu_S W5 小时前
Redis跳表:高效有序数据结构的深度剖析
数据结构·数据库·redis
是那盏灯塔5 小时前
【算法】——动态规划之01背包问题
数据结构·c++·算法·动态规划
jinmo_C++5 小时前
数据结构_深入理解堆(大根堆 小根堆)与优先队列:从理论到手撕实现
java·数据结构·算法
Excuse_lighttime6 小时前
排序数组(快速排序算法)
java·数据结构·算法·leetcode·eclipse·排序算法
南方的狮子先生7 小时前
【数据结构】(C++数据结构)查找算法与排序算法详解
数据结构·c++·学习·算法·排序算法·1024程序员节
学编程就要猛8 小时前
数据结构初阶:Java中的ArrayList
java·开发语言·数据结构
试试勇气8 小时前
算法工具箱之双指针
数据结构
在等晚安么8 小时前
力扣面试经典150题打卡
java·数据结构·算法·leetcode·面试·贪心算法
Dobby_059 小时前
【Go】C++转Go:数据结构练习(一)排序算法
数据结构·golang