一、链表概述
链表是有元素组成的数据结构,每个元素都是单独对象,包含数据和指针信息
链表中的每个元素称为节点,如下所示,第一个节点称为Head(头节点),为链表的入口点,如果链表为空,则Head指向None,链表的最后一个节点指向None
如上图所示,链表是动态数据结构,无法直接访问数据,搜索任何项都需要从Head开始,必须遍历每个引用才能获取节点信息,链表占用更多内存
二、单链表
单链表是只包含数据和指向下一个引用的数据结构,最后一个节点对象没有引用
定义一个Node类,包括数据data和引用下一个引用reference, 默认下一个reference为None
每创建一个Node类, 将上一个Node类的reference指向当前创建,遍历链表需要从第一个节点开始,如presentNode = objNode1,依次获取当前节点的下一个引用,即为遍历,分配变量presentNode之后, 最后一个节点包含指针值,将推出while循环,因为指针值为None,代码实现如下所示
class Node:
def __init__(self, data=None):
"""
创建Node类,包括data(值)和reference(下一个指针)
:param data:
"""
self.data = data
self.reference = None
if __name__ == '__main__':
objNode1 = Node(1)
objNode2 = Node(2)
objNode3 = Node(3)
objNode4 = Node(4)
objNode1.reference = objNode2
objNode2.reference = objNode3
objNode3.reference = objNode4
presentNode = objNode1
while presentNode:
print("当前Node值为:", presentNode.data)
presentNode = presentNode.reference
将遍历信息封装,同时创建Linked_list类,目的是 对Node信息进行管理和操作,定义Linked_list类, 保存头节点位置,同时定义指针信息,如下图所示:
代码如下所示
class Node:
def __init__(self, data=None):
"""
创建Node类,包括data(值)和reference(下一个指针)
:param data:
"""
self.data = data
self.reference = None
class Linked_list:
def __init__(self):
self.head = None
def recursive(self):
"""
定义遍历节点类
:return:
"""
presentNode = self.head
while presentNode:
print("当前Node值为:", presentNode.data)
presentNode = presentNode.reference
if __name__ == '__main__':
objNode1 = Node(1)
objNode2 = Node(2)
objNode3 = Node(3)
objNode4 = Node(4)
linkObj = Linked_list()
linkObj.head = objNode1
linkObj.head.reference = objNode2
objNode2.reference = objNode3
objNode3.reference = objNode4
linkObj.recursive()
如果在链表添加头节点,只需令linkObj.head = new_node和new_node.reference = objNode1
如方法 insert_at_head(data),
-
首先需要创建一个新节点,此时并未指向任何信息
-
将当前新节点引用指向当前链表的头节点
-
然后将头节点指针指向当前节点,即可完成新节点添加
def insert_at_head(self, data):
"""
链表头部添加新数据
:param data:
:return:
"""
new_data = Node(data)
# 此处奇妙在,新节点的引用,指向当前链表的头节点,然后在将头节点指针前移,指向新节点即可
new_data.reference = self.head
self.head = new_data
如果在链表添加尾节点,需要遍历整个链表,找出当前尾节点,然后将当前尾节点引用,指向新的节点
def insert_at_end(self, data):
"""
链表尾部添加新数据
:param data:
:return:
"""
new_data = Node(data)
presentNode = self.head
while presentNode:
presentNode = presentNode.reference
presentNode.reference = new_data
在两个节点之间插入新节点,需要先获取当前节点的引用节点,并把引用节点赋值给待添加节点,同时将当前节点的引用指向待添加节点
def insert_at_middle(self, insert_node, data):
"""
在insert_node节点后添加新节点
:param insert_node:
:param data:
:return:
"""
new_node = Node(data)
new_node.reference = insert_node.reference
insert_node.reference = new_node
从链表删除节点
A->B->C
A.reference = B
B.reference = C
C.reference = D
删除B节点,则需遍历链表,当到达指向节点B的节点A时,将该值替换为存储在节点B的指针值,节点A指向节点C, 节点B从链表删除
def remove_node(self, remove_obj):
"""
删除remove_obj节点信息
:param remove_obj:
:return:
"""
presentNode = self.head
while presentNode:
if presentNode.reference == remove_obj:
presentNode.reference = remove_obj.reference
break
presentNode = presentNode.reference
三、双链表
双向链表包含3个部分,指向前一个节点指针、数据和指向下一个节点指针,如下图所示:
双向链表支持从前向后和从后向前遍历,从头开始,使用next移动到下一个节点,从尾开始,使用prev移动到上一个节点,代码如下所示
def recursiveAfter(self):
"""
从后向前遍历
:return:
"""
presentNode = self.tail
while presentNode.prev:
print("从前向后遍历,当前值value=", presentNode.data)
presentNode = presentNode.prev
def recursiveFront(self):
"""
从后向前遍历
:return:
"""
presentNode = self.head
while presentNode:
print("从后向前遍历,当前值value=", presentNode.data)
presentNode = presentNode.next
双向链表尾部追加节点,需要确保追加节点的prev指针指向上一个节点信息
def appendNode(self, data):
"""
在尾部添加节点
:param data:
:return:
"""
new_data = Node(data)
presentNode = self.head
while presentNode:
presentNode = presentNode.next
presentNode.next = new_data
new_data.prev = presentNode
删除节点信息,需要遍历双向链表两次,首先从链表头部开始使用next向后遍历,遇到删除对象,将当前节点的next更改为删除对象之后的节点,同时从后向前遍历,再次遇到删除对象,将当前节点的prev值更改为其之前的节点
def removeNode(self, removeObj):
"""
删除节点需要遍历两边链表
:param removeObj:
:return:
"""
presentNode = self.head
# 从前向后删除
while presentNode:
if presentNode.next == removeObj:
presentNode.next = removeObj.next
break
presentNode = presentNode.next
# 从后向前删除
presentNodeTail = self.tail
while presentNodeTail:
if presentNodeTail.prev == removeObj:
presentNodeTail.prev = removeObj.prev
break
presentNodeTail = presentNodeTail.prev
四、反向链表
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
反向列表的实现思路是
-
保存上一个节点的节点信息
-
反转节点指向,将当前节点的next指向上一个节点,比如原链表:1->2->3时,应改为3->2->1->NULL
-
继续处理后面的节点
如下图所示
代码实现思路,如下所示
def reverse(self):
"""
1->2->3->None
3->2->1->None
:return:
"""
previous = None
# 头节点
presentNode = self.head
# 下一个节点信息
while presentNode:
# 获取下一个节点
nextVal = presentNode.reference
# 将当前节点的next指向上一个节点
presentNode.reference = previous
previous = presentNode
presentNode = nextVal
# 最后一个节点赋值为头节点
self.head = previous