1 单链表概念
- 单链表是一种链式存取的数据结构,用一组地址任意的存储单元存放线性表中的数据元素。
- 链表中的数据是以结点来表示的,每个结点的构成:元素(数据元素的映象) + 指针(指示后继元素存储位置),元素就是存储数据的存储单元,指针就是连接每个结点的地址数据。
如图所示的是带头节点的单链表:
- 链式存储结构的线性表将采用一组任意的存储单元存放线性表中的数据元素。
- 由于不需要按顺序存储,链表在插入、删除数据元素时比顺序存储要快,但是在查找一个节点时则要比顺序存储要慢,使用链式存储可以克服顺序线性表需要预先知道数据大小的缺点,链表结构可以充分利用内存空间,实现灵活的内存动态管理。但是链式存储失去了数组随机存取的特点,同时增加了节点的指针域,空间开销较大。
2 单链表实现
2.1 定义结点
创建结点所拥有的两个属性值,元素element和指针next
# 创建单链表结点
class Node:
def __init__(self, element):
self.element = element # 定义节点的元素
self.next = None # 初始化节点指向
2.2 定义单链表(单链表头)
创建单链表,实际上就是创建单链表头(要注意表头只有一个属性,即next,不像结点还储存了element),通过指针next来添加新的结点。
# 单链表
class SingleLinkList:
# 初始化
def __init__(self):
self.next = None # 初始化header的指向
2.3 基础功能实现
基础功能的实现思路大致都相同:
- 进行检索操作时,依靠头结点的next指针来依次向后遍历。
- 进行增删改操作时,将需要操作的结点next指针断开,指向其他结点,始终保持链状结构。 这里以插入结点为例进行说明:
插入结点实质上就是把上一个结点的next指针指向新结点,再将新结点的next指针指向下一个结点:
以下是一些基础功能的实现代码:
# 单链表
class SingleLinkList:
# 初始化
def __init__(self):
self.next = None # 初始化header的指向
# 判断链表是否为空
def is_empty(self):
return self.next == None
# 判断链表长度
def length(self):
cur = self.next # 将cur指向第一个节点
len = 0 # 计数
while cur != None: # 遍历所有节点
len += 1 # 计数
cur = cur.next # cur指向下一个节点
return len
# 打印链表元素,存放在列表中
def traverse(self):
cur = self.next # 将cur指向第一个节点
list = [] # 新建空列表
while cur != None: # 遍历所有节点
list.append(cur.element) # 将元素填入列表
cur = cur.next # cur指向下一个节点
return list
# 在链表头部添加元素
def add(self, element):
node = Node(element) # 实例化节点
node.next = self.next # 将新节点指向原来header的next
self.next = node # 将header指向新节点
# 在链表尾部添加元素
def append(self, element):
node = Node(element) # 实例化节点
if self.is_empty(): # 判断链表是否为空
self.next = node # 若为空,将header指向新节点
else:
cur = self.next # 将cur指向原来header的next
while cur.next != None: # 遍历所有节点直到尾节点
cur = cur.next
cur.next = node # 将cur指向新节点
# 在链表的指定位置添加元素
def insert(self, idx, element):
if idx == 0: # 当idx=0,调用add()
self.add(element)
elif idx == self.length(): # 当idx=length,调用append()
self.append(element)
elif 0 < idx < self.length():
node = Node(element) # 实例化节点
cur = self.next # 将cur指向原来header的next
for _ in range(idx-1): # 找到需要插入元素的位置
cur = cur.next
node.next = cur.next # 将新节点指向cur的下一个元素
cur.next = node # 将cur指向新节点
else:
print("输入的idx不合法")
# 按索引返回节点元素(索引从0开始)
def find(self, idx):
if self.is_empty(): # 判断链表是否为空
print("链表为空")
cur = self.next # 将cur指向原来header的next
if idx == 0:
return cur.element # 直接返回当前元素
elif 0 < idx < self.length():
for _ in range(idx-1):
cur = cur.next
return cur.next.element # 返回指定位置的元素
else:
print("输入的idx不合法")
# 按索引删除节点(索引从0开始)
def remove(self, idx):
if self.is_empty(): # 判断链表是否为空
print("链表为空")
cur = self.next # 将cur指向原来header的next
if idx == 0: # 删除第一个元素
self.next = self.next.next
elif 0 < idx < self.length(): # 删除指定位置的元素
for _ in range(idx-1):
cur = cur.next
cur.next = cur.next.next # cur直接指向下下个元素
else:
print("输入的idx不合法")
# 按索引修改节点元素(索引从0开始)
def update(self, idx, element):
if self.is_empty(): # 判断链表是否为空
print("链表为空")
cur = self.next
if idx == 0:
cur.element = element # 修改第一个元素
elif 0 < idx < self.length():
for _ in range(idx-1):
cur = cur.next
cur.next.element = element # 修改指定位置的元素
else:
print("输入的idx不合法")
# 查找节点元素是否存在
def is_exist(self, element):
cur = self.next
while cur != None: # 遍历所有节点
if cur.element == element: # 若存在,返回ture
return True
cur = cur.next
return False
3 实例操作
# 创建单链表
ll = SingleLinkList()
# 头部增加元素
ll.add(2)
ll.add(5)
ll.add(4)
# 尾部增加元素
ll.append(10)
ll.append(34)
ll.append(50)
# 插入元素(按索引)
ll.insert(1,99)
# 删除元素(按索引)
ll.remove(1)
# 更新元素(按索引)
ll.update(3,88)
# 以列表的形式查看链表
ll.traverse()
# 输出结果
[4, 5, 2, 88, 34, 50]