- 作者:老汪软件技巧
- 发表时间:2024-08-22 21:02
- 浏览量:
一种线性数据结构,每个元素对应链表上一个节点对象,每个节点通过地址(C/C++)或引用相连接,地址或引用记录下一个节点的内存地址,该元素可以通过地址或引用访问下一个元素
节点
链表的组成单位
包含两项数据:节点的值,下一个节点的引用
定义节点类
# 定义链表节点
class ListNode():
def __init__(self, val):
self.val = val
self.next = None
链表常用操作初始化链表
在得到节点定义类后,即可初始化一条节点:
初始化链表后,通常将头结点作为链表的代表,通过引用可访问到每个节点
#实例化
n0 = ListNode(0)
n1 = ListNode(1)
n2 = ListNode(2)
# 构建关系
n0.next = n1
n1.next = n2
n0.next.next.val
2
插入
链表插入节点相对容易,在相邻两个节点n0,n1之间插入一个新节点p,只需改变该两个节点引用的值即可,时间复杂度为O(1)
相比数组的插入时间复杂度为O(n),在大数据下方便许多
def insert(pre, current):
temp = pre.next
current.next = temp
pre.next = current
n3 = ListNode(3)
insert(n0,n3)
n0.next.val
3
删除
链表删除节点也十分方便,只需要改变一个节点的引用
存在一个n0->n1->n2的链表,删除n1时,只需要将n0的引用指向n2,此时n0节点已经指针n2,访问不到n1,意味着n1不在属于该链表了
def delete(current):
# 判断是否没有节点
if not current.next:
print('当前节点没有下一个节点了')
return None
temp = current.next
current.next = temp.next
delete(n1)
print(type(n1.next))
<class 'NoneType'>
查找
一种线性查找,需要遍历链表
def find(head, target):
"""
查找职位target的节点,返回索引
"""
index = 0
while head:
if head.val == target:
return index
else:
head = head.next
index += 1
print(f'未找到 {target} 所在未知')
return -1
index = find(n0, 2)
index
未找到 2 所在未知
-1
index_3 = find(n0, 3)
index_3
1
访问
链表查找需要从头开始,一次向后遍历节点值,直到找到目标值,也就是说查找链表的第i个位置需要循环i-1轮,时间复杂度为O(n)
相比数组的下标,在O(1)时间内访问数组中任意元素,效率较低
def access(head, index):
"""
访问第index个节点
"""
for _ in range(index):
# 节点不正确
if not head:
return None
# 下一个
head = head.next
return head
access(n0, 2).val
1
链表VS数组链表数组
存储方式
分散内存空间
连续内存空间
容量扩展
可灵活扩展
长度不可变
内存效率
元素占用内存少、但可能浪费空间
元素占用内存多
访问元素
O(n)
O(1)
添加元素
O(1)
O(n)
删除元素
O(1)
O(n)