设计Python代码验证⽤list类实现的动态数组与⽤ListNode类实现的链表的
运⾏⽤时差异。请⾄少测试以下三种操作:插⼊(包含头部插⼊、中间插⼊、尾部插⼊)、删除(包含
头部删除、中间删除、尾部删除)与随机访问。请说明在不同数据规模时各种操作的性能差异,解释如
何利⽤timeit模块测量操作性能,并观察实验结果是否与理论分析是否⼀致。以下是能符合理论时间复杂度的完整代码这个代码能否解决以上问题?是否还要测量空间复杂度说明性能差异?import timeit
import random
import time
import matplotlib.pyplot as plt
import matplotlib
from matplotlib import font_manager
import numpy as np
# 设置中文字体 - 更稳健的方法
def setup_chinese_font():
"""设置中文字体支持"""
try:
# 方法1: 直接设置支持中文的字体
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'SimSun', 'Arial Unicode MS']
plt.rcParams['axes.unicode_minus'] = False
# 测试是否成功
test_fig, test_ax = plt.subplots(figsize=(1, 1))
test_ax.text(0.5, 0.5, '测试', fontsize=12)
plt.close(test_fig)
print("中文字体设置成功")
return True
except:
print("中文字体设置失败,使用英文显示")
plt.rcParams['font.sans-serif'] = ['DejaVu Sans', 'Arial']
return False
# 在文件开头调用字体设置
chinese_supported = setup_chinese_font()
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 insert_head(self, val):
"""头部插入 O(1)"""
new_node = ListNode(val)
new_node.next = self.head
self.head = new_node
self.size += 1
def insert_tail(self, val):
"""尾部插入 O(n) - 需要遍历找到尾部"""
new_node = ListNode(val)
if self.head is None:
self.head = new_node
else:
current = self.head
while current.next is not None:
current = current.next
current.next = new_node
self.size += 1
def insert_mid(self, val, index):
"""中间插入 O(n)"""
if index <= 0:
self.insert_head(val)
return
if index >= self.size:
self.insert_tail(val)
return
new_node = ListNode(val)
current = self.head
for _ in range(index - 1):
current = current.next
new_node.next = current.next
current.next = new_node
self.size += 1
def delete_head(self):
"""头部删除 O(1)"""
if not self.head:
return None
val = self.head.val
self.head = self.head.next
self.size -= 1
return val
def delete_tail(self):
"""尾部删除 O(n) - 需要遍历找到尾部前一个节点"""
if not self.head:
return None
if self.head.next is None:
return self.delete_head()
current = self.head
while current.next.next is not None:
current = current.next
val = current.next.val
current.next = None
self.size -= 1
return val
def delete_mid(self, index):
"""中间删除 O(n)"""
if index <= 0:
return self.delete_head()
if index >= self.size - 1:
return self.delete_tail()
current = self.head
for _ in range(index - 1):
current = current.next
val = current.next.val
current.next = current.next.next
self.size -= 1
return val
def random_access(self, index):
"""随机访问 O(n)"""
if index < 0 or index >= self.size:
return None
current = self.head
for _ in range(index):
current = current.next
return current.val
def __len__(self):
return self.size
class OptimizedLinkedList:
"""优化的链表实现 - 使用尾指针优化尾部插入"""
def __init__(self):
self.head = None
self.tail = None
self.size = 0
def insert_head(self, val):
"""头部插入 O(1)"""
new_node = ListNode(val)
new_node.next = self.head
self.head = new_node
if self.tail is None:
self.tail = new_node
self.size += 1
def insert_tail(self, val):
"""尾部插入 O(1) - 使用尾指针优化"""
new_node = ListNode(val)
if self.tail is None:
self.head = self.tail = new_node
else:
self.tail.next = new_node
self.tail = new_node
self.size += 1
def insert_mid(self, val, index):
"""中间插入 O(n)"""
if index <= 0:
self.insert_head(val)
return
if index >= self.size:
self.insert_tail(val)
return
new_node = ListNode(val)
current = self.head
for _ in range(index - 1):
current = current.next
new_node.next = current.next
current.next = new_node
self.size += 1
def delete_head(self):
"""头部删除 O(1)"""
if not self.head:
return None
val = self.head.val
self.head = self.head.next
if self.head is None:
self.tail = None
self.size -= 1
return val
def delete_tail(self):
"""尾部删除 O(n) - 即使有尾指针,单链表也无法O(1)删除尾部"""
if not self.head:
return None
if self.head == self.tail:
return self.delete_head()
current = self.head
while current.next != self.tail:
current = current.next
val = self.tail.val
current.next = None
self.tail = current
self.size -= 1
return val
def delete_mid(self, index):
"""中间删除 O(n)"""
if index <= 0:
return self.delete_head()
if index >= self.size - 1:
return self.delete_tail()
current = self.head
for _ in range(index - 1):
current = current.next
val = current.next.val
current.next = current.next.next
self.size -= 1
return val
def random_access(self, index):
"""随机访问 O(n)"""
if index < 0 or index >= self.size:
return None
current = self.head
for _ in range(index):
current = current.next
return current.val
def __len__(self):
return self.size
def create_linked_list(size):
"""创建普通链表测试数据"""
ll = LinkedList()
for i in range(size):
ll.insert_tail(i)
return ll
def create_optimized_linked_list(size):
"""创建优化链表测试数据"""
ll = OptimizedLinkedList()
for i in range(size):
ll.insert_tail(i)
return ll
def get_user_sizes():
"""获取用户选择的数据规模"""
print("\n选择测试数据规模:")
print("1. 小规模测试 (100, 500, 1000)")
print("2. 中规模测试 (500, 1000, 2000)")
print("3. 自定义规模")
choice = input("请选择 (1-3): ").strip()
if choice == '1':
return [100, 500, 1000, 5000, 10000] # 修改为包含10000的规模
elif choice == '2':
return [500, 1000, 2000, 5000, 10000] # 修改为包含10000的规模
elif choice == '3':
try:
sizes_input = input("请输入数据规模 (用逗号分隔,如: 100,500,1000,5000,10000): ")
sizes = [int(x.strip()) for x in sizes_input.split(',')]
return [min(size, 10000) for size in sizes] # 提高最大规模限制到10000
except ValueError:
print("输入格式错误,使用默认的小规模测试")
return [100, 500, 1000, 5000, 10000] # 修改为包含10000的规模
else:
print("无效选择,使用默认的小规模测试")
return [100, 500, 1000, 5000, 10000] # 修改为包含10000的规模
def plot_performance_results(insert_results, delete_results, random_results):
"""绘制性能测试结果图表"""
print("\n正在生成性能图表...")
sizes = insert_results['sizes']
# 根据字体支持情况选择标签语言
if chinese_supported:
titles = {
'main': '动态数组 vs 链表性能对比',
'insert_head': '头部插入性能\nList: O(n) vs LinkedList: O(1)',
'insert_mid': '中间插入性能\nList: O(n) vs LinkedList: O(n)',
'insert_tail': '尾部插入性能\nList: O(1) vs LinkedList: O(n)',
'delete_head': '头部删除性能\nList: O(n) vs LinkedList: O(1)',
'delete_mid': '中间删除性能\nList: O(n) vs LinkedList: O(n)',
'delete_tail': '尾部删除性能\nList: O(1) vs LinkedList: O(n)',
'random_batch': '批量随机访问 (50次)\nList: O(1) vs LinkedList: O(n)',
'random_single': '单次随机访问\nList: O(1) vs LinkedList: O(n)',
'xlabel': '数据规模',
'ylabel': '平均操作时间 (秒)'
}
else:
titles = {
'main': 'Array vs LinkedList Performance Comparison',
'insert_head': 'Head Insert Performance\nList: O(n) vs LinkedList: O(1)',
'insert_mid': 'Middle Insert Performance\nList: O(n) vs LinkedList: O(n)',
'insert_tail': 'Tail Insert Performance\nList: O(1) vs LinkedList: O(n)',
'delete_head': 'Head Delete Performance\nList: O(n) vs LinkedList: O(1)',
'delete_mid': 'Middle Delete Performance\nList: O(n) vs LinkedList: O(n)',
'delete_tail': 'Tail Delete Performance\nList: O(1) vs LinkedList: O(n)',
'random_batch': 'Batch Random Access (50 times)\nList: O(1) vs LinkedList: O(n)',
'random_single': 'Single Random Access\nList: O(1) vs LinkedList: O(n)',
'xlabel': 'Data Size',
'ylabel': 'Average Operation Time (s)'
}
# 创建子图 - 调整布局
fig, axes = plt.subplots(2, 3, figsize=(20, 12))
if chinese_supported:
fig.suptitle('动态数组 vs 链表性能对比', fontsize=16, fontweight='bold')
else:
fig.suptitle('Array vs LinkedList Performance Comparison', fontsize=16, fontweight='bold')
# 插入操作对比
axes[0, 0].plot(sizes, insert_results['head_list'], 'o-', label='List', linewidth=2, markersize=6)
axes[0, 0].plot(sizes, insert_results['head_linked'], 's-', label='LinkedList', linewidth=2, markersize=6)
axes[0, 0].set_title(titles['insert_head'], fontsize=12)
axes[0, 0].set_xlabel(titles['xlabel'], fontsize=10)
axes[0, 0].set_ylabel(titles['ylabel'], fontsize=10)
axes[0, 0].legend(fontsize=9)
axes[0, 0].grid(True, alpha=0.3)
axes[0, 1].plot(sizes, insert_results['mid_list'], 'o-', label='List', linewidth=2, markersize=6)
axes[0, 1].plot(sizes, insert_results['mid_linked'], 's-', label='LinkedList', linewidth=2, markersize=6)
axes[0, 1].set_title(titles['insert_mid'], fontsize=12)
axes[0, 1].set_xlabel(titles['xlabel'], fontsize=10)
axes[0, 1].set_ylabel(titles['ylabel'], fontsize=10)
axes[0, 1].legend(fontsize=9)
axes[0, 1].grid(True, alpha=0.3)
axes[0, 2].plot(sizes, insert_results['tail_list'], 'o-', label='List', linewidth=2, markersize=6)
axes[0, 2].plot(sizes, insert_results['tail_linked'], 's-', label='LinkedList', linewidth=2, markersize=6)
axes[0, 2].set_title(titles['insert_tail'], fontsize=12)
axes[0, 2].set_xlabel(titles['xlabel'], fontsize=10)
axes[0, 2].set_ylabel(titles['ylabel'], fontsize=10)
axes[0, 2].legend(fontsize=9)
axes[0, 2].grid(True, alpha=0.3)
# 删除操作对比
axes[1, 0].plot(sizes, delete_results['head_list'], 'o-', label='List', linewidth=2, markersize=6)
axes[1, 0].plot(sizes, delete_results['head_linked'], 's-', label='LinkedList', linewidth=2, markersize=6)
axes[1, 0].set_title(titles['delete_head'], fontsize=12)
axes[1, 0].set_xlabel(titles['xlabel'], fontsize=10)
axes[1, 0].set_ylabel(titles['ylabel'], fontsize=10)
axes[1, 0].legend(fontsize=9)
axes[1, 0].grid(True, alpha=0.3)
axes[1, 1].plot(sizes, delete_results['mid_list'], 'o-', label='List', linewidth=2, markersize=6)
axes[1, 1].plot(sizes, delete_results['mid_linked'], 's-', label='LinkedList', linewidth=2, markersize=6)
axes[1, 1].set_title(titles['delete_mid'], fontsize=12)
axes[1, 1].set_xlabel(titles['xlabel'], fontsize=10)
axes[1, 1].set_ylabel(titles['ylabel'], fontsize=10)
axes[1, 1].legend(fontsize=9)
axes[1, 1].grid(True, alpha=0.3)
axes[1, 2].plot(sizes, delete_results['tail_list'], 'o-', label='List', linewidth=2, markersize=6)
axes[1, 2].plot(sizes, delete_results['tail_linked'], 's-', label='LinkedList', linewidth=2, markersize=6)
axes[1, 2].set_title(titles['delete_tail'], fontsize=12)
axes[1, 2].set_xlabel(titles['xlabel'], fontsize=10)
axes[1, 2].set_ylabel(titles['ylabel'], fontsize=10)
axes[1, 2].legend(fontsize=9)
axes[1, 2].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# 随机访问性能单独绘制
fig2, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6))
if chinese_supported:
fig2.suptitle('随机访问性能对比', fontsize=16, fontweight='bold')
else:
fig2.suptitle('Random Access Performance Comparison', fontsize=16, fontweight='bold')
ax1.plot(sizes, random_results['batch_list'], 'o-', label='List', linewidth=2, markersize=6)
ax1.plot(sizes, random_results['batch_linked'], 's-', label='LinkedList', linewidth=2, markersize=6)
ax1.set_title(titles['random_batch'], fontsize=12)
ax1.set_xlabel(titles['xlabel'], fontsize=10)
ax1.set_ylabel(titles['ylabel'], fontsize=10)
ax1.legend(fontsize=9)
ax1.grid(True, alpha=0.3)
ax2.plot(sizes, random_results['single_list'], 'o-', label='List', linewidth=2, markersize=6)
ax2.plot(sizes, random_results['single_linked'], 's-', label='LinkedList', linewidth=2, markersize=6)
ax2.set_title(titles['random_single'], fontsize=12)
ax2.set_xlabel(titles['xlabel'], fontsize=10)
ax2.set_ylabel(titles['ylabel'], fontsize=10)
ax2.legend(fontsize=9)
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
print("性能图表生成完成!")
def test_insert_operations(sizes):
"""使用timeit测试插入操作性能 - 修正版"""
if chinese_supported:
print("插入操作性能测试")
print("时间复杂度说明:")
print(" - 头部插入: List O(n) vs LinkedList O(1)")
print(" - 中间插入: List O(n) vs LinkedList O(n)")
print(" - 尾部插入: List O(1) vs LinkedList O(n)")
else:
print("Insert Operation Performance Test")
print("Time Complexity:")
print(" - Head Insert: List O(n) vs LinkedList O(1)")
print(" - Middle Insert: List O(n) vs LinkedList O(n)")
print(" - Tail Insert: List O(1) vs LinkedList O(n)")
print("=" * 80)
# 存储测试结果用于绘图
insert_results = {
'sizes': sizes,
'head_list': [],
'head_linked': [],
'mid_list': [],
'mid_linked': [],
'tail_list': [],
'tail_linked': []
}
for size in sizes:
if chinese_supported:
print(f"\n数据规模: {size}")
else:
print(f"\nData Size: {size}")
print("-" * 50)
# 动态调整测试次数 - 对于大尺寸减少操作次数
operations = min(500, max(50, 10000 // size * 100)) if size > 1000 else min(1000, max(100, size // 10))
# 头部插入测试
list_time = min(timeit.repeat(
"data.insert(0, -1)",
setup=f"data = list(range({size}))",
number=operations,
repeat=3
)) / operations
linked_time = min(timeit.repeat(
"ll.insert_head(-1)",
setup=f"""
from __main__ import create_linked_list
ll = create_linked_list({size})
""",
number=operations,
repeat=3
)) / operations
insert_results['head_list'].append(list_time)
insert_results['head_linked'].append(linked_time)
if chinese_supported:
print(f"头部插入 - List: {list_time:.8f}s, LinkedList: {linked_time:.8f}s")
else:
print(f"Head Insert - List: {list_time:.8f}s, LinkedList: {linked_time:.8f}s")
# 中间插入测试
mid_index = max(1, size // 2)
list_time = min(timeit.repeat(
f"data.insert({mid_index}, -1)",
setup=f"data = list(range({size}))",
number=operations,
repeat=3
)) / operations
linked_time = min(timeit.repeat(
f"ll.insert_mid(-1, {mid_index})",
setup=f"""
from __main__ import create_linked_list
ll = create_linked_list({size})
""",
number=operations,
repeat=3
)) / operations
insert_results['mid_list'].append(list_time)
insert_results['mid_linked'].append(linked_time)
if chinese_supported:
print(f"中间插入 - List: {list_time:.8f}s, LinkedList: {linked_time:.8f}s")
else:
print(f"Middle Insert - List: {list_time:.8f}s, LinkedList: {linked_time:.8f}s")
# 尾部插入测试
list_time = min(timeit.repeat(
"data.append(-1)",
setup=f"data = list(range({size}))",
number=operations,
repeat=3
)) / operations
linked_time = min(timeit.repeat(
"ll.insert_tail(-1)",
setup=f"""
from __main__ import create_linked_list
ll = create_linked_list({size})
""",
number=operations,
repeat=3
)) / operations
insert_results['tail_list'].append(list_time)
insert_results['tail_linked'].append(linked_time)
if chinese_supported:
print(f"尾部插入 - List: {list_time:.8f}s, LinkedList: {linked_time:.8f}s")
else:
print(f"Tail Insert - List: {list_time:.8f}s, LinkedList: {linked_time:.8f}s")
return insert_results
def test_delete_operations(sizes):
"""删除操作测试 - 修正版:统一操作次数"""
if chinese_supported:
print("\n\n删除操作性能测试")
print("时间复杂度说明:")
print(" - 头部删除: List O(n) vs LinkedList O(1)")
print(" - 中间删除: List O(n) vs LinkedList O(n)")
print(" - 尾部删除: List O(1) vs LinkedList O(n)")
else:
print("\n\nDelete Operation Performance Test")
print("Time Complexity:")
print(" - Head Delete: List O(n) vs LinkedList O(1)")
print(" - Middle Delete: List O(n) vs LinkedList O(n)")
print(" - Tail Delete: List O(1) vs LinkedList O(n)")
print("=" * 80)
delete_results = {
'sizes': sizes,
'head_list': [],
'head_linked': [],
'mid_list': [],
'mid_linked': [],
'tail_list': [],
'tail_linked': []
}
for size in sizes:
if chinese_supported:
print(f"\n数据规模: {size}")
else:
print(f"\nData Size: {size}")
print("-" * 50)
# 统一操作次数 - 根据数据规模动态调整,对于大尺寸减少操作次数
operations = min(200, max(20, 10000 // size * 50)) if size > 1000 else min(500, max(50, size // 20))
# 头部删除测试
list_head_time = min(timeit.repeat(
"if data: del data[0]",
setup="data = list(range(size))",
globals={'size': size},
number=operations,
repeat=3
)) / operations
linked_head_time = min(timeit.repeat(
"if ll.head: ll.delete_head()",
setup="""
from __main__ import LinkedList
ll = LinkedList()
for i in range(size):
ll.insert_tail(i)
""",
globals={'size': size},
number=operations,
repeat=3
)) / operations
delete_results['head_list'].append(list_head_time)
delete_results['head_linked'].append(linked_head_time)
if chinese_supported:
print(f"头部删除 - List: {list_head_time:.8f}s, LinkedList: {linked_head_time:.8f}s")
else:
print(f"Head Delete - List: {list_head_time:.8f}s, LinkedList: {linked_head_time:.8f}s")
# 中间删除测试
mid_index = size // 2 if size > 0 else 0
list_mid_time = min(timeit.repeat(
f"if len(data) > {mid_index}: del data[{mid_index}]",
setup="data = list(range(size))",
globals={'size': size},
number=operations,
repeat=3
)) / operations
linked_mid_time = min(timeit.repeat(
f"if ll.size > {mid_index}: ll.delete_mid({mid_index})",
setup="""
from __main__ import LinkedList
ll = LinkedList()
for i in range(size):
ll.insert_tail(i)
""",
globals={'size': size},
number=operations,
repeat=3
)) / operations
delete_results['mid_list'].append(list_mid_time)
delete_results['mid_linked'].append(linked_mid_time)
if chinese_supported:
print(f"中间删除 - List: {list_mid_time:.8f}s, LinkedList: {linked_mid_time:.8f}s")
else:
print(f"Middle Delete - List: {list_mid_time:.8f}s, LinkedList: {linked_mid_time:.8f}s")
# 尾部删除测试
list_tail_time = min(timeit.repeat(
"if data: data.pop()",
setup="data = list(range(size))",
globals={'size': size},
number=operations,
repeat=3
)) / operations
linked_tail_time = min(timeit.repeat(
"if ll.head: ll.delete_tail()",
setup="""
from __main__ import LinkedList
ll = LinkedList()
for i in range(size):
ll.insert_tail(i)
""",
globals={'size': size},
number=operations,
repeat=3
)) / operations
delete_results['tail_list'].append(list_tail_time)
delete_results['tail_linked'].append(linked_tail_time)
if chinese_supported:
print(f"尾部删除 - List: {list_tail_time:.8f}s, LinkedList: {linked_tail_time:.8f}s")
else:
print(f"Tail Delete - List: {list_tail_time:.8f}s, LinkedList: {linked_tail_time:.8f}s")
return delete_results
def test_random_access(sizes):
"""随机访问性能测试 - 修正版"""
if chinese_supported:
print("\n\n随机访问性能测试")
print("时间复杂度说明:")
print(" - 随机访问: List O(1) vs LinkedList O(n)")
else:
print("\n\nRandom Access Performance Test")
print("Time Complexity:")
print(" - Random Access: List O(1) vs LinkedList O(n)")
print("=" * 80)
random_results = {
'sizes': sizes,
'batch_list': [],
'batch_linked': [],
'single_list': [],
'single_linked': []
}
for size in sizes:
if chinese_supported:
print(f"\n数据规模: {size}")
else:
print(f"\nData Size: {size}")
print("-" * 50)
# 预创建测试数据
list_data = list(range(size))
linked_list = create_linked_list(size)
# 生成随机索引
random_indices = [random.randint(0, size-1) for _ in range(min(50, size))]
# 测试列表随机访问
list_time = min(timeit.repeat(
lambda: [list_data[i] for i in random_indices],
number=100,
repeat=3
)) / 100
# 测试链表随机访问
linked_time = min(timeit.repeat(
lambda: [linked_list.random_access(i) for i in random_indices],
number=100,
repeat=3
)) / 100
random_results['batch_list'].append(list_time)
random_results['batch_linked'].append(linked_time)
if chinese_supported:
print(f"批量随机访问 {len(random_indices)} 次 - List: {list_time:.8f}s, LinkedList: {linked_time:.8f}s")
else:
print(f"Batch Random Access {len(random_indices)} times - List: {list_time:.8f}s, LinkedList: {linked_time:.8f}s")
# 单次访问测试
test_index = max(0, min(size-1, size // 2))
# 列表单次访问
list_time = min(timeit.repeat(
lambda: list_data[test_index],
number=1000,
repeat=3
)) / 1000
# 链表单次访问
linked_time = min(timeit.repeat(
lambda: linked_list.random_access(test_index),
number=1000,
repeat=3
)) / 1000
random_results['single_list'].append(list_time)
random_results['single_linked'].append(linked_time)
if chinese_supported:
print(f"单次访问测试 - List: {list_time:.8f}s, LinkedList: {linked_time:.8f}s")
else:
print(f"Single Access Test - List: {list_time:.8f}s, LinkedList: {linked_time:.8f}s")
return random_results
def main():
"""主函数"""
if chinese_supported:
print("动态数组 vs 链表性能测试 - 时间复杂度修正版")
print("注意:本测试使用普通单链表(无尾指针),链表尾部插入为O(n)")
else:
print("Array vs LinkedList Performance Test - Time Complexity Fixed Version")
print("Note: This test uses standard singly linked list (no tail pointer), LinkedList tail insertion is O(n)")
print("=" * 80)
# 获取用户选择的数据规模
sizes = get_user_sizes()
if chinese_supported:
print(f"\n使用数据规模: {sizes}")
else:
print(f"\nUsing Data Sizes: {sizes}")
start_time = time.time()
# 运行测试并收集结果
insert_results = test_insert_operations(sizes)
delete_results = test_delete_operations(sizes)
random_results = test_random_access(sizes)
# 绘制性能图表
plot_performance_results(insert_results, delete_results, random_results)
end_time = time.time()
if chinese_supported:
print(f"\n所有测试完成!总耗时: {end_time - start_time:.2f} 秒")
else:
print(f"\nAll tests completed! Total time: {end_time - start_time:.2f} seconds")
if __name__ == "__main__":
main()