Python 线性数据结构详解
文件信息
- 文件名: 01_线性数据结构.py
- 开发思路和开发过程 :
- 首先介绍数组(List)的基本操作
- 然后演示栈(Stack)的实现和应用
- 接着展示队列(Queue)的实现和应用
- 最后介绍双端队列(Deque)的使用
- 代码功能: 演示线性数据结构的实现和使用,包括数组、栈、队列和双端队列。
代码实现
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
文件名: 01_线性数据结构.py
开发思路和开发过程:
1. 首先介绍数组(List)的基本操作
2. 然后演示栈(Stack)的实现和应用
3. 接着展示队列(Queue)的实现和应用
4. 最后介绍双端队列(Deque)的使用
代码功能: 演示线性数据结构的实现和使用,包括数组、栈、队列和双端队列。
"""
print("=== 线性数据结构详解 ===\n")
# 1. 数组(List)
print("1. 数组(List):")
# 创建数组
arr = [1, 2, 3, 4, 5]
print(f"创建数组: {arr}")
# 访问元素
print(f"访问第一个元素 arr[0]: {arr[0]}")
print(f"访问最后一个元素 arr[-1]: {arr[-1]}")
# 修改元素
arr[2] = 10
print(f"修改索引2的元素为10: {arr}")
# 添加元素
arr.append(6) # 末尾添加
print(f"末尾添加元素6: {arr}")
arr.insert(0, 0) # 指定位置插入
print(f"在索引0处插入元素0: {arr}")
# 删除元素
arr.remove(10) # 删除指定值的第一个匹配项
print(f"删除值为10的元素: {arr}")
popped = arr.pop() # 弹出最后一个元素
print(f"弹出最后一个元素 {popped}: {arr}")
popped_at_index = arr.pop(0) # 弹出指定索引的元素
print(f"弹出索引0的元素 {popped_at_index}: {arr}")
# 切片操作
print(f"前3个元素 arr[:3]: {arr[:3]}")
print(f"从索引2开始的元素 arr[2:]: {arr[2:]}")
print(f"索引1到3的元素 arr[1:3]: {arr[1:3]}")
# 查找元素
index_of_4 = arr.index(4) # 查找元素索引
print(f"元素4的索引: {index_of_4}")
count_of_2 = arr.count(2) # 统计元素出现次数
print(f"元素2出现的次数: {count_of_2}")
print()
# 2. 栈(Stack) - 后进先出(LIFO)
print("2. 栈(Stack) - 后进先出(LIFO):")
class Stack:
"""栈的实现"""
def __init__(self):
self.items = []
def is_empty(self):
"""判断栈是否为空"""
return len(self.items) == 0
def push(self, item):
"""入栈"""
self.items.append(item)
def pop(self):
"""出栈"""
if self.is_empty():
raise IndexError("栈为空,不能执行出栈操作")
return self.items.pop()
def peek(self):
"""查看栈顶元素"""
if self.is_empty():
raise IndexError("栈为空,没有栈顶元素")
return self.items[-1]
def size(self):
"""获取栈的大小"""
return len(self.items)
def __str__(self):
return f"栈内容(底->顶): {self.items}"
# 使用栈
stack = Stack()
print(f"创建空栈: {stack}")
stack.push(1)
stack.push(2)
stack.push(3)
print(f"入栈1, 2, 3后: {stack}")
top_item = stack.peek()
print(f"栈顶元素: {top_item}")
popped_item = stack.pop()
print(f"出栈元素: {popped_item}")
print(f"出栈后: {stack}")
print(f"栈的大小: {stack.size()}")
# 栈的应用示例:括号匹配
def is_balanced_parentheses(expression):
"""检查括号是否匹配"""
stack = Stack()
opening = "([{"
closing = ")]}"
pairs = {"(": ")", "[": "]", "{": "}"}
for char in expression:
if char in opening:
stack.push(char)
elif char in closing:
if stack.is_empty():
return False
if pairs[stack.pop()] != char:
return False
return stack.is_empty()
# 测试括号匹配
expressions = ["()", "()[]{}", "(]", "([)]", "{[]}"]
for expr in expressions:
result = is_balanced_parentheses(expr)
print(f"'{expr}' 括号匹配: {result}")
print()
# 3. 队列(Queue) - 先进先出(FIFO)
print("3. 队列(Queue) - 先进先出(FIFO):")
from collections import deque
class Queue:
"""队列的实现"""
def __init__(self):
self.items = deque()
def is_empty(self):
"""判断队列是否为空"""
return len(self.items) == 0
def enqueue(self, item):
"""入队"""
self.items.append(item)
def dequeue(self):
"""出队"""
if self.is_empty():
raise IndexError("队列为空,不能执行出队操作")
return self.items.popleft()
def front(self):
"""查看队首元素"""
if self.is_empty():
raise IndexError("队列为空,没有队首元素")
return self.items[0]
def size(self):
"""获取队列的大小"""
return len(self.items)
def __str__(self):
return f"队列内容(首->尾): {list(self.items)}"
# 使用队列
queue = Queue()
print(f"创建空队列: {queue}")
queue.enqueue(1)
queue.enqueue(2)
queue.enqueue(3)
print(f"入队1, 2, 3后: {queue}")
front_item = queue.front()
print(f"队首元素: {front_item}")
dequeued_item = queue.dequeue()
print(f"出队元素: {dequeued_item}")
print(f"出队后: {queue}")
print(f"队列的大小: {queue.size()}")
# 队列的应用示例:任务调度模拟
def simulate_print_queue(tasks):
"""模拟打印队列"""
print_queue = Queue()
# 添加任务到队列
for task in tasks:
print_queue.enqueue(task)
print(f"任务 '{task}' 已添加到打印队列")
# 处理任务
while not print_queue.is_empty():
current_task = print_queue.dequeue()
print(f"正在打印: {current_task}")
# 测试任务调度
tasks = ["文档1.pdf", "图片2.png", "报告3.docx"]
print("打印队列模拟:")
simulate_print_queue(tasks)
print()
# 4. 双端队列(Deque)
print("4. 双端队列(Deque):")
# 使用collections.deque
dq = deque([1, 2, 3])
print(f"创建双端队列: {list(dq)}")
# 在两端添加元素
dq.appendleft(0) # 左端添加
dq.append(4) # 右端添加
print(f"左端添加0,右端添加4: {list(dq)}")
# 从两端删除元素
left_popped = dq.popleft() # 左端删除
right_popped = dq.pop() # 右端删除
print(f"从左端删除 {left_popped},从右端删除 {right_popped}: {list(dq)}")
# 旋转操作
dq.rotate(1) # 向右旋转1位
print(f"向右旋转1位: {list(dq)}")
dq.rotate(-2) # 向左旋转2位
print(f"向左旋转2位: {list(dq)}")
print("\n=== 线性数据结构详解结束 ===")
架构图
线性数据结构
├── 数组(List)
│ ├── 创建
│ ├── 访问
│ ├── 修改
│ ├── 添加
│ ├── 删除
│ ├── 切片
│ └── 查找
├── 栈(Stack)
│ ├── 入栈(push)
│ ├── 出栈(pop)
│ ├── 查看栈顶(peek)
│ ├── 判空(is_empty)
│ └── 大小(size)
├── 队列(Queue)
│ ├── 入队(enqueue)
│ ├── 出队(dequeue)
│ ├── 查看队首(front)
│ ├── 判空(is_empty)
│ └── 大小(size)
└── 双端队列(Deque)
├── 左右端添加
├── 左右端删除
└── 旋转操作
应用场景流程图
栈应用 - 括号匹配:
1. 遍历表达式
├── 字符类型判断
│ ├── 左括号 → 入栈
│ ├── 右括号 → 栈是否为空?
│ │ ├── 是 → 返回false
│ │ └── 否 → 出栈并匹配
│ │ ├── 匹配 → 继续遍历
│ │ └── 不匹配 → 返回false
│ └── 其他字符 → 继续遍历
└── 遍历完成 → 检查栈是否为空
├── 栈为空 → 返回true
└── 栈非空 → 返回false
特点对比
| 数据结构 | 主要操作时间复杂度 | 适用场景 |
|---|---|---|
| 数组 | 随机访问: O(1) 插入/删除: O(n) | 需要频繁访问元素 |
| 栈 | 插入/删除: O(1) 访问: O(n) | 后进先出场景 |
| 队列 | 入队/出队: O(1) 访问: O(n) | 先进先出场景 |
| 双端队列 | 两端操作: O(1) 中间操作: O(n) | 需要在两端操作元素 |