链表(Linked List)是一种基础的数据结构,用于存储一系列有序的元素。与数组不同,链表中的元素存储在不连续的内存位置,元素通过指针(或引用)连接,允许动态地插入和删除元素。
一、链表的基本概念
1. 节点(Node)
链表的基本组成单元,通常包含两个部分:
数据部分:存储链表节点的数据。
指针部分:指向下一个节点的引用。
2. 头节点
链表的第一个节点,标识链表的开始。
3. 尾节点
链表的最后一个节点,其指针部分指向`None`(空),表示链表的结束。
二、链表的类型
1. 单链表(Singly Linked List)
每个节点只有一个指向下一个节点的指针。
优点:实现简单,插入和删除操作相对高效。
缺点:只能单向遍历,不能快速访问前一个节点。
2. 双链表(Doubly Linked List)
每个节点有两个指针,分别指向前一个节点和下一个节点。
优点:支持双向遍历,可以方便地进行插入和删除操作。
缺点:额外需要存储一个指向前节点的指针,增加了内存使用。
3. 循环链表(Circular Linked List)
链表的最后一个节点指向头节点,而不是指向`None`。可以是单向或双向。
优点:实现循环遍历。
缺点:可能会导致链表遍历时的复杂性增加。
三、链表的基本操作
1. 插入(Insert)
头部插入:在链表的最前面插入一个新节点。
尾部插入:在链表的最后添加一个新节点。
中间插入:在指定位置插入新的节点。
2. 删除(Delete)
从链表中删除指定位置的节点,更新相邻节点的指针。
3. 查找(Search)
遍历链表,查找指定值的节点。
4. 遍历(Traversal)
从头节点开始,依次访问链表中的每个节点。
四、链表的优缺点
优点:
动态大小:链表的大小可以在运行时动态调整,避免了数组固定大小的问题。
高效插入和删除:在已知节点位置时,插入和删除操作只需要更新指针,不必移动数据,时间复杂度为 O(1) 。
缺点:
随机访问效率低:链表不支持高效的随机访问,查找某个节点的时间复杂度为 O(n) 。
额外空间开销:每个节点需要额外的空间来存储指针,导致相对于数组来说,内存使用更高。
五、示例代码(Python)
以下是一个简单的单链表实现示例:
# 链表节点实现
class SingleNode(object):
def __init__(self, item):
# item: 存放元素(数据部分)
self.item = item
# next:标识下一个节点(指针部分)
self.next = None
# 单链表实现
class SingleLinkList(object):
def __init__(self, node=None):
# head:首节节点
self.head = node
# 判断是否为空
def is_empty(self):
if self.head is None:
return True
else:
return False
# 获取链表长度
def leng(self):
# 游标记录当前所在位置
cur = self.head
# 记录链表长度
count = 0
while cur is not None:
cur = cur.next
count += 1
return count
# 遍历
def travel(self):
# 游标标记当前所在的位置
cur = self.head
# 循环打印数据
while cur is not None:
print(cur.item)
cur = cur.next
# 头部增加节点
def add(self, item):
node = SingleNode(item)
node.next = self.head
self.head = node
# 尾部增加节点
def append(self, item):
# 尾部增加节点
node = SingleNode(item)
if self.is_empty():
# 如果链表为空
self.head = node
else:
# 如果链表不为空
cur = self.head
# 找到尾部节点
while cur.next is not None:
cur = cur.next
cur.next = node
def insert(self, postion, item):
if postion <= 0:
self.add(item)
elif postion >= self.leng():
self.append(item)
else:
# 游标
cur = self.head
# 计数
count = 0
# 新节点
node = SingleNode(item)
# 找到插入位置的前一个节点
while count < postion - 1:
cur = cur.next
count += 1
# 完成插入新节点
node.next = cur.next
cur.next = node
# 删除节点
def remove(self, item):
cur = self.head
pre = None
while cur is not None:
if cur.item == item:
if cur == self.head:
self.head = cur.next
else:
pre.next = cur.next
return
else:
pre = cur
cur = cur.next
# 查找节点是否存在
def search(self, item):
cur = self.head
while cur is not None:
if cur.item == item:
return True
cur = cur.next
return False
if __name__ == '__main__':
# 节点
node1 = SingleNode(10)
print(node1.item) # 10
print(node1.next) # None
# 链表
link1 = SingleLinkList()
print(link1.head) # None
link2 = SingleLinkList(node1)
print(link2.head.item) # 10
# 判断是否为空
print(link1.is_empty()) # True
print(link2.is_empty()) # False
# 获取链表长度
print(link1.leng())
print(link2.leng())
# 遍历
link2.travel()
# 头部增加节点
print('-' * 20)
link2.add(11)
link2.travel()
# 尾部添加节点
print('-' * 20)
link2.append(20)
link2.travel()
# 插入数据
print('-' * 20)
link2.insert(2, 30)
link2.travel()
# 删除节点
print('-' * 20)
link2.remove(30)
link2.travel()
# 查询节点是否存在
print('-'*20)
print(link2.search(10)) # True
print(link2.search(2)) # False
六、总结
链表是一种强大而灵活的数据结构,适合于需要频繁插入和删除操作的场景。理解链表的基本概念和操作对学习和实现其他更复杂的数据结构(如树、图)非常重要。