数据结构 — 链表
链表
在電腦科學中,链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。由于不必须按顺序存储,链表在插入的时候可以达到O(1)的复杂度,比另一种线性表顺序表快得多(如列表和数组),但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1)。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。
单向链表
链表中最简单的一种是单向链表,它包含两个域,一个信息域和一个指针域。这个链接指向列表中的下一个节点,而最后一个节点则指向一个空值。
实现单向链表(python)
步骤:
- 创建节点
# 写一个节点类: class Node: def __init__(self,item=None): self.item = item # 节点中存储的值 self.next = None # 链接下一个节点的指针
- 链接多个节点,组成链表
class Node: def __init__(self,item=None): self.item = item self.next = None # 创建两个节点 a = Node(1) b = Node(2) # a链接b a.next = b
节点插入(头插法&&尾插法)
- 头插法:在链表的头部插入节点
-
把节点插入头部会遇到两种情况(self.head存储头部所在节点,self.tail存储尾部所在节点):1.链表为空;2.链表不为空。
-
当头节点和尾节点的指向都为空时,此时链表中没有节点,是一个空链表,在这种情况下插入‘节点a’,只需把头节点和尾节点同时指向‘节点a’。
-
-
当链表不为空时,将‘节点b’插入链表头部,并将头节点指向‘节点b’
- (头插法)代码实现如下:
# 链表类 class LinkList: class Node: def __init__(self,item=None): self.item = item self.next = None def __init__(self): self.head = None # 头节点 self.tail = None # 尾节点 # 头插法 def unshift(self, item): # 创建要插入的节点 cur_node = self.Node(item) # 链表为空时: if not bool(self.head): self.head = cur_node self.tail = cur_node # 不为空时: else: cur_node.next = self.head self.head = cur_node
-
- 尾插法:在链表的尾部插入节点
- 尾插法与头插法类似,1.链表为空;2.链表不为空。
- (尾插法)代码实现如下:
# 链表类 class LinkList: class Node: def __init__(self,item=None): self.item = item self.next = None def __init__(self): self.head = None # 头节点 self.tail = None # 尾节点 # 尾插法 def append(self,item): # 创建要插入的节点 cur_node = self.Node(item) # 链表为空时: if not bool(self.head): self.head = cur_node self.tail = cur_node # 不为空时: else: self.tail.next = cur_node self.tail = cur_node
- 尾插法与头插法类似,1.链表为空;2.链表不为空。
指定位置插入节点
初始时,节点a —> 节点b,创建节点c,接着节点c —> 节点b,最后,节点a —> 节点c (—>表示指向,a.next = b,节点a指向节点b)
# 链表类
class LinkList:
class Node:
def __init__(self, item=None):
self.item = item
self.next = None
def __init__(self):
self.head = None
self.tail = None
# 查看链表
def __repr__(self):
head = self.head
data = []
while head:
data.append(str(head.item))
head = head.next
del head
return f'<<< {",".join(data)} >>>'
# 头插法
def unshift(self, item):
cur_node = self.Node(item)
if not bool(self.head):
self.head = cur_node
self.tail = cur_node
else:
cur_node.next = self.head
self.head = cur_node
# 尾插法
def append(self,item):
cur_node = self.Node(item)
if not bool(self.head):
self.head = cur_node
self.tail = cur_node
else:
self.tail.next = cur_node
self.tail = cur_node
# 查看链表长度
def len(self):
head = self.head
length = 0
while head:
length += 1
head = head.next
del head
return length
def find_pre_node(self,index):
""" 作用:找到插入(待删除)位置所在节点的前一个节点
有三种情况:
1.插入(待删除)位置在头部
2.插入(待删除)位置在尾部
3.既不在头部,也不在尾部
---------------------------------
情况一:返回一个‘start’字符串,
让insert函数调用unshift()函数进行头插;
让delete函数调用shift()函数进行去头;
情况二:返回一个‘end’字符串,
让insert函数调用append()函数进行尾插;
让delete函数调用pop()函数进行去尾;
情况三:返回插入(待删除)位置所在节点的前一个节点
"""
if index == 0:
return 'start'
if index == self.len() - 1:
return 'end'
head = self.head
for i in range(index-1):
head = head.next
return head
def insert(self,item,index):
pre_node = self.find_pre_node(index)
if pre_node == 'start':
self.unshift(item)
return
elif pre_node == 'end':
self.append(item)
return
# index位置上所在的节点
next_node = pre_node.next
# 创建待插入的节点
insert_node = self.Node(item)
insert_node.next = next_node
pre_node.next = insert_node
节点删除(去头法&&去尾法)
- 去头法
- self.head由节点a指向节点b,实现节点a的删除效果
# 链表类 class LinkList: class Node: def __init__(self,item=None): self.item = item self.next = None def __init__(self): self.head = None # 头节点 self.tail = None # 尾节点 # 删除头节点 def shift(self): self.head = self.head.next
- 去尾法
- self.tail由节点c指向节点b,实现节点c的删除效果
# 链表类 class LinkList: class Node: def __init__(self,item=None): self.item = item self.next = None def __init__(self): self.head = None # 头节点 self.tail = None # 尾节点 # 查看链表长度 def len(self): head = self.head length = 0 while head: length += 1 head = head.next del head return length # 删除尾结点 def pop(self): head = self.head for i in range(self.len()-2): head = head.next self.tail = head self.tail.next = None
指定位置删除节点
# 链表类
class LinkList:
class Node:
def __init__(self,item=None):
self.item = item
self.next = None
def __init__(self):
self.head = None # 头节点
self.tail = None # 尾节点
# 查看链表长度
def len(self):
head = self.head
length = 0
while head:
length += 1
head = head.next
del head
return length
def find_pre_node(self,index):
""" 作用:找到插入(待删除)位置所在节点的前一个节点
有三种情况:
1.插入(待删除)位置在头部
2.插入(待删除)位置在尾部
3.既不在头部,也不在尾部
---------------------------------
情况一:返回一个‘start’字符串,
让insert函数调用unshift()函数进行头插;
让delete函数调用shift()函数进行去头;
情况二:返回一个‘end’字符串,
让insert函数调用append()函数进行尾插;
让delete函数调用pop()函数进行去尾;
情况三:返回插入(待删除)位置所在节点的前一个节点
"""
if index == 0:
return 'start'
if index == self.len() - 1:
return 'end'
head = self.head
for i in range(index-1):
head = head.next
return head
# 删除头节点
def shift(self):
self.head = self.head.next
# 删除尾结点
def pop(self):
head = self.head
for i in range(self.len()-2):
head = head.next
self.tail = head
self.tail.next = None
def delete(self,index):
pre_node = self.find_pre_node(index)
if pre_node == 'start':
self.shift()
return
elif pre_node == 'end':
self.pop()
return
delete_node = pre_node.next
next_node = pre_node.next.next
pre_node.next = next_node
del delete_node
完整代码:
class LinkList:
class Node:
def __init__(self, item=None):
self.item = item
self.next = None
def __init__(self):
self.head = None
self.tail = None
# 查看链表
def __repr__(self):
head = self.head
data = []
while head:
data.append(str(head.item))
head = head.next
del head
return f'<<< {",".join(data)} >>>'
# 头插法
def unshift(self, item):
cur_node = self.Node(item)
if not bool(self.head):
self.head = cur_node
self.tail = cur_node
else:
cur_node.next = self.head
self.head = cur_node
# 尾插法
def append(self, item):
cur_node = self.Node(item)
if not bool(self.head):
self.head = cur_node
self.tail = cur_node
else:
self.tail.next = cur_node
self.tail = cur_node
# 查看链表长度
def len(self):
head = self.head
length = 0
while head:
length += 1
head = head.next
del head
return length
def find_pre_node(self, index):
if index == 0:
return 'start'
if index == self.len() - 1:
return 'end'
head = self.head
for i in range(index - 1):
head = head.next
return head
def insert(self, item, index):
pre_node = self.find_pre_node(index)
if pre_node == 'start':
self.unshift(item)
return
elif pre_node == 'end':
self.append(item)
return
next_node = pre_node.next
insert_node = self.Node(item)
insert_node.next = next_node
pre_node.next = insert_node
# 删除头节点
def shift(self):
self.head = self.head.next
# 删除尾结点
def pop(self):
head = self.head
for i in range(self.len() - 2):
head = head.next
self.tail = head
self.tail.next = None
def delete(self, index):
pre_node = self.find_pre_node(index)
if pre_node == 'start':
self.shift()
return
elif pre_node == 'end':
self.pop()
return
delete_node = pre_node.next
next_node = pre_node.next.next
pre_node.next = next_node
del delete_node
如有疑问,或者有不足之处,欢迎在评论区下留言讨论