数据结构篇——链表(以Python为例)
一、链表介绍
链表(link list)的顺序是由链表中的指针决定的,其为动态结合提供了一种简单而灵活的表示方法。链表在存储单元上非连续、非顺序。其节点包含两个部分:数据域与指针域,数据域存储该节点的数据元素,指针域存储指向下一个节点的指针。
二、链表
1. 单向链表
单向链表又名单链表,是一种顺序存储的结构。head指针指向头节点,尾节点的指针指向None,item存储节点数据,next指向下一个节点。
class Node(object):
"""单链表的节点"""
def __init__(self, item):
# item存放数据元素
self.item = item
# 初始化节点的指针为None,next是指向一个节点的指针,
self.next = None
class SingleLinkList(object):
"""单链表类"""
def __init__(self):
self._head = None
def is_empty(self):
"""判断链表是否为空"""
# None 返回True,非None返回False.
return self._head is None
def length(self):
"""链表长度"""
# 初始指针指向head
cur = self._head
count = 0
# 指针指向None 表示到达尾部
while cur is not None:
count += 1
# 指针下移
cur = cur.next
return count
def items(self):
"""遍历链表"""
cur = self._head
while cur is not None:
# 调用生成器,返回一个迭代器
yield cur.item
# print(cur.item)
cur = cur.next
def add(self, item):
"""向链表头部添加元素"""
# 创建一个以item为元素的节点node
node = Node(item)
# 新节点的指针指向链表的原头部节点
node.next = self._head
# 头部节点的指针修改为新增加的节点
self._head = node
def append(self,item):
"""在链表尾部添加元素"""
# 创建一个以item为元素的节点node
node = Node(item)
# 先判断是否为空链表
if self._head is None:
"""若为空链表,则链表的头部指向新节点"""
self._head = node
else:
"""若不是空链表,则找到链表尾部,将尾部节点的next指向新节点"""
cur = self._head
while cur.next is not None:
cur = cur.next
cur.next = node
def insert(self, index, item):
"""在指定位置插入元素"""
if index <= 0: # 指定位置在第一个元素之前,在头部插入
self.add(item)
elif index > self.length() - 1: # 指定位置超出链表尾部,在尾部插入
self.append(item)
else:
node = Node(item)
cur = self._head
count = 0
while count < index-1:
cur = cur.next
count += 1
# 在插入节点时,先连接后面的节点,再连接前面的节点
node.next = cur.next
cur.next = node
def remove(self, item):
"""删除链表中的节点"""
if self.is_empty():
print("链表为空,不能删除此节点")
else:
# 当第一个元素为要删除的元素
if self._head.item == item:
self._head = self._head.next
else:
cur = self._head
pre = None # 用于记录被删除节点的前一个节点
while cur is not None: # 当删除的元素不是第一个元素时
# 找到指定的元素之后,将所删除节点的前一个结点指向所删除节点的后一个节点,并退出判断
if cur.item == item:
pre.next = cur.next
return
else:
pre = cur
cur = cur.next
def find(self, item):
"""查找元素是否存在"""
return item in self.items()
if __name__ == '__main__':
link_list = SingleLinkList()
node1 = Node(1)
node2 = Node(2)
node3 = Node(4)
node4 = Node(5)
# 将节点添加到链表,使得链表的头指针指向node1
link_list._head = node1
# 将第一个节点的指针指向下一个节点
node1.next = node2
node2.next = node3
node3.next = node4
# 判断链表是否为空
# print(link_list.is_empty())
# 计算链表长度
# print(link_list.length())
# 遍历链表
for i in link_list.items():
print(i, end=" ")
print("\n")
# 在链表头部增加节点
link_list.add(3)
for i in link_list.items():
print(i, end=" ")
print("\n")
# 在链表尾部增加节点
link_list.append(7)
for i in link_list.items():
print(i, end=" ")
print("\n")
# 在链表指定位置插入节点
link_list.insert(1, 8)
for i in link_list.items():
print(i, end=" ")
print("\n")
# 删除链表中的元素
link_list.remove(7)
for i in link_list.items():
print(i, end=" ")
print("\n")
# 查找元素是否在链表中
print(link_list.find(7))
2. 单向循环链表
单向循环链表在单向链表的基础上,将尾节点与头节点连接在一起了,即将尾节点的指针指向头节点,变成单向循环链表。
- 定义节点
class Node(object):
"""单循环链表的节点"""
def __init__(self, item):
# item存放链表元素
self.item = item
# 初始化节点的指针为None,next是指向下一个节点的指针,
self.next = None
- 定义链表
class SingleCycleLinkList(object):
"""单向循环链表类"""
def __init__(self):
self._head = None
def is_empty(self):
"""判断链表是否为空"""
return self._head is None
def length(self):
"""计算链表长度"""
count = 0
cur = self._head
if self._head is None: # 当链表为空时,返回0
return count
else:
while cur.next != self._head:
count += 1
cur = cur.next
return count+1
def items(self):
"""遍历链表"""
# 当链表为空时
if self.is_empty():
print("链表为空")
else:
cur = self._head
while cur.next != self._head:
# 调用生成器,返回一个迭代器
yield cur.item
cur = cur.next
yield cur.item # 最后一个节点的元素值未输出,因此,在此处输出
def add(self, item):
"""在链表头部添加节点"""
# 创建节点
node = Node(item)
# 链表头部指向新增加的节点
if self.is_empty(): # 当链表为空时
self._head = node
node.next = node
else:
cur = self._head
node.next = self._head # 将添加的节点指针指向头部
while cur.next != self._head: # 找到尾部节点,使得尾部节点的指针指向新添加的节点
cur = cur.next
cur.next = node
self._head = node # 修改head指向新增加的节点
def append(self, item):
"""在链表尾部添加节点"""
# 创建节点
node = Node(item)
if self.is_empty(): # 当链表为空时
self._head = node
node.next = node
else:
cur = self._head
node.next = cur # 新增加的节点指针指向头节点
while cur.next != self._head:
cur = cur.next
cur.next = node # 链表尾部节点指针指向新增加的节点
def insert(self, index, item):
"""在指定位置插入元素"""
# 创建节点
node = Node(item)
if index <= 0: # 指定位置在第一个元素之前,在头部插入
self.add(item)
elif index > self.length() - 1: # 指定位置超出链表尾部,在尾部插入
self.append(item)
else:
cur = self._head
count = 0
while count < index - 1:
count += 1
cur = cur.next
# 在插入节点时,先连接后面的节点,再连接前面的节点
node.next = cur.next
cur.next = node
def remove(self, item):
"""删除链表中的节点"""
if self.is_empty():
print("链表为空,不能删除此节点")
else:
cur = self._head
# 当第一个节点为要删除的元素时
if self._head.item == item:
# 当链表只有一个节点,即头节点时,将head指针指向None
if self._head.next == self._head:
self._head = None
# 当链表不止一个节点时
else:
while cur.next != self._head: # 遍历找到尾节点
cur = cur.next
self._head = self._head.next # 将head指针指向头节点的下一个节点,即原链表的第二个节点
cur.next = self._head # 将尾节点的指针指向更新后链表的头节点,即原链表的第二个节点
else:
# 当被删除的元素不是头节点时
pre = None
while cur.next != self._head: # 遍历链表,但是遍历不到尾节点就退出循环了
# 找到指定的元素之后,将所删除节点的前一个结点指向所删除节点的后一个节点,并退出判断
if cur.item == item:
pre.next = cur.next
return
else:
pre = cur
cur = cur.next
# while循环不能遍历到链表尾节点,在此处添加对尾节点的判断
if cur.item == item:
pre.next = cur.next
return
def find(self, item):
"""查找元素是否存在"""
return item in self.items()
- 链表的使用
if __name__ == '__main__':
# 创建一个链表
link_list = SingleCycleLinkList()
node1 = Node(1)
node2 = Node(2)
node3 = Node(3)
node4 = Node(4)
node5 = Node(5)
# 将节点添加至链表,使得链表的头指针指向节点
link_list._head = node1
node1.next = node2
node2.next = node3
node3.next = node4
node4.next = node5
node5.next = node1
# 判断链表是否为空
print(link_list.is_empty())
# 计算链表长度
print(link_list.length())
# 遍历链表
for item in link_list.items():
print(item, end=" ")
print("\n")
# 在链表头部添加节点
link_list.add(0)
for item in link_list.items():
print(item, end=" ")
print("\n")
# 在链表尾部添加节点
link_list.append(6)
for item in link_list.items():
print(item, end=" ")
print("\n")
# 在链表指定位置插入节点
link_list.insert(3, 30)
for item in link_list.items():
print(item, end=" ")
print("\n")
# 删除元素为item的节点
link_list.remove(0)
for item in link_list.items():
print(item, end=" ")
print("\n")
# 查找元素是否在链表中
print(link_list.find(3))
3. 双链表
双向链表在单向链表的基础上又多了一个指针域pre
,每个节点包含元素值item
,指向下一个节点的指针next
,指向上一个节点的指针pre
。当节点为头节点(head)时,pre
指向None,当节点为尾节点(tail)时,next
指向None。
class Node(object):
"""双向链表的节点"""
def __init__(self, item):
# item存放数据元素
self.item = item
# 初始化节点的指针为None,next是指向下一个节点的指针,
self.next = None
# 初始化节点的指针为None,pre是指向上一个节点的指针
self.pre = None
class BilateralLinkList(object):
"""双向链表类"""
def __init__(self):
self._head = None
def is_empty(self):
"""判断链表是否为空"""
return self._head is None
def length(self):
"""计算链表长度"""
count = 0
cur = self._head
# 遍历到尾节点的距离
while cur is not None:
count += 1
cur = cur.next
return count
def items(self):
"""遍历链表"""
if self.is_empty(): # 当链表为空时
print("链表为空链表,无法遍历...")
return
cur = self._head
while cur is not None:
# 调用生成器,返回一个迭代器
yield cur.item
cur = cur.next
def add(self, item):
"""在链表头部添加节点"""
# 创建一个以item为元素的节点node
node = Node(item)
if self.is_empty():
self._head = node
else:
self._head.pre = node # 原始头节点的pre指针指向新增加的节点
node.next = self._head # 新增加节点的next指针指向原始头节点
self._head = node # head指针指向新增加的节点,将此节点作为头节点
def append(self, item):
"""在链表尾部添加节点"""
# 创建一个以item为元素的节点node
node = Node(item)
if self.is_empty():
self._head = node
else:
cur = self._head
while cur.next is not None: # 遍历找到尾节点
cur = cur.next
cur.next = node # 原始尾节点的next指针指向新增加的节点
node.pre = cur # 新增加节点的pre指针指向原始尾节点
def insert(self, index, item):
"""在链表指定位置插入节点"""
# 创建一个以item为元素的节点node
node = Node(item)
# 当指定位置在头节点前面时
if index <= 0:
self.add(item)
# 当指定位置在尾节点后面时
elif index >= self.length():
self.append(item)
# 当指定位置在链表中间时
else:
cur = self._head
count = 0
while count < index:
count += 1
cur = cur.next
cur.pre.next = node # 插入点位置的前一个节点的next指针指向新增加的节点
node.pre = cur.pre # 插入点的pre指针指向插入点位置的前一个结点
node.next = cur # 插入点的next指针指向插入点位置的后一个节点
cur.pre = node # 插入点位置的后一个节点的pre指针指向新增加的节点
def remove(self, item):
"""删除链表中的节点"""
if self.is_empty():
print("链表为空,无法删除节点....")
else:
# 当删除的节点为头节点时
if self._head.item == item:
# 当链表只包含一个元素时
if self._head.next is None:
self._head = None
# 当链表不止一个元素时
else:
self._head.next.pre = None # 将第二个节点的pre指针指向None
self._head = self._head.next # 将head指针指向原始链表的第二个节点
else:
cur = self._head
# 当删除的节点不为头节点时
while cur.next is not None: # 遍历链表,但是遍历不到尾节点就退出循环了
if cur.item != item:
cur = cur.next
else:
cur.next.pre = cur.pre
cur.pre.next = cur.next
return
if cur.item == item: # 当要删除的节点为尾节点时
cur.pre.next = None
def find(self, item):
return item in self.items()
if __name__ == '__main__':
print("双向链表程序开始执行...")
link_list = BilateralLinkList()
# 在链表头部增加节点
list_head = [5, 4, 3, 2, 1, 0]
for i in list_head:
link_list.add(i)
# 判断链表是否为空
print(link_list.is_empty())
# 计算链表长度
print(link_list.length())
# 遍历链表元素
for item in link_list.items():
print(item, end=" ")
print("\n")
# 在链表尾部增加节点
list_tail = [6,7,8,9,10]
for i in list_tail:
link_list.append(i)
for item in link_list.items():
print(item, end=" ")
print("\n")
# 在链表指定位置中插入节点
link_list.insert(6, 30)
for item in link_list.items():
print(item, end=" ")
print("\n")
# 删除节点
link_list.remove(10)
for item in link_list.items():
print(item, end=" ")
print("\n")
# 查找元素是否存在
print(link_list.find(11))