【4】数据结构的循环链表章
目录标题
- 循环链表的定义
- 循环链表的初始化
- 循环链表的创建
- 循环链表的插入
- 循环链表的删除
- 循环链表总代码与调试
- 顺序表与链表的比较
- 链式存储方式的比较
循环链表的定义
- 循环链表的结点定义与单链表一致,只包含数据域(data)和指针域(next)。
- 定义:循环链表作为一种首尾相接的链表,其尾结点的后继指针又指向链表的第一个结点,形成一个闭环。
- 循环链表逻辑结构示意图
- 代码定义循环链表结点
class Node:
"""
定义循环链表结点类型
"""
def __init__(self, data):
# 存储结点中的数据域
self.data = data
# 指向后继结点的指针域next
self.next = None
循环链表的初始化
- 初始化循环链表
class CLinkedList:
"""
循环链表的定义
"""
def __init__(self):
"""
循环链表的初始化
"""
# 声明头指针,将头结点的后继结点指向自己
self.head = Node(None)
self.head.next = self.head
- 判断循环链表是否为空
def isEmpty(self):
"""
判断是否为空
:return: true or false
"""
return self.head.next is self.head
- 求循环链表的长度
def getLength(self):
"""
获取循环链表的长度
:return: 当前循环链表中元素的个数
"""
# length用来计算循环链表的长度
length = 0
# 声明cur指针,用于遍历链表
cur = self.head.next
# 若cur没有指向自己,则表明未遍历完成
while cur != self.head:
length += 1
cur = cur.next
return length
- 打印循环链表
def display(self):
"""
遍历循环链表,进行展示
:return:
"""
if self.isEmpty():
print("当前循环链表为空!")
return
print("循环链表的元素为:", end='')
# 遍历循环链表
cur = self.head.next
while cur != self.head:
print(cur.data, end='')
cur = cur.next
print()
循环链表的创建
-
使用尾插法实现循环链表的创建
-
核心思想:
- 查找到链表的尾结点
- 将尾结点的后继结点指针指向新结点
- 将新结点的后继指针指向头结点
-
代码实现
def append(self, data):
"""
建立循环链表
:param data: 待插入的元素
:return:
"""
# 查找尾结点
rear = self.head
while rear.next != self.head:
rear = rear.next
# 创建新结点
newNode = Node(data)
# 将尾结点的后继结点指针指向新结点
rear.next = newNode
# 将新结点的后继结点指针指向头结点
newNode.next = self.head
循环链表的插入
- 核心思想
- 声明指针pre与递增变量i变量循环链表,找到需插入位置的前一结点;
- 创建新结点,将元素值赋予结点;
- 将新结点的后继指针指向指针pre的后继结点;
- 将第index个结点的后继指针指向新结点
- 插入示意图
- 代码实现
def insert(self, index, data):
"""
在循环链表中任一位置插入元素
:param index: 待插入的位置
:param data: 待插入的元素值
:return:
"""
i = 1
# 声明指针pre,用于遍历循环链表
pre = self.head.next
# 遍历停止的条件,pre为空,或指向下标为index-1的结点
while pre != self.head and i != index-1:
pre = pre.next
i += 1
# index非法
if pre == self.head or i > self.getLength():
raise IndexError("index 非法")
# 创建新结点
newNode = Node(data)
# 将新结点的后继指针指向指针pre的后继结点
newNode.next = pre.next
# 将第index个结点的后继指针指向新结点
pre.next = newNode
循环链表的删除
-
核心思想
- 声明指针pre与递增变量i变量循环链表,找到需删除位置的前一结点;
- 保留被删元素的值,再对结点进行删除;
- 将pre的后继结点指向pre指针后继结点的后继结点;
- 实现被删结点的断连。
-
删除示意图
-
代码实现
def delete(self, index):
"""
在循环链表中任一位置删除元素
:param index: 删除下标index的元素
:return: 被删的元素值
"""
if self.isEmpty():
raise IndexError("当前循环链表为空!")
i = 1
# 声明指针pre,用来遍历循环链表
pre = self.head.next
# 遍历停止的条件,pre为空,或指向下标为index-1的结点
while pre != self.head and i != index - 1:
pre = pre.next
i += 1
# index非法
if pre == self.head or i > self.getLength():
raise IndexError("index 非法")
# 获取被删元素的值
data = pre.next.data
# 将要删结点从循环链表中断开
pre.next = pre.next.next
return data
循环链表总代码与调试
# 6.循环链表的实现
class Node:
"""
定义循环链表结点类型
"""
def __init__(self, data):
# 存储结点中的数据域
self.data = data
# 指向后继结点的指针域next
self.next = None
class CLinkedList:
"""
循环链表的定义
"""
def __init__(self):
"""
循环链表的初始化
"""
# 声明头指针,将头结点的后继结点指向自己
self.head = Node(None)
self.head.next = self.head
def isEmpty(self):
"""
判断是否为空
:return: true or false
"""
return self.head.next is self.head
def getLength(self):
"""
获取循环链表的长度
:return: 当前循环链表中元素的个数
"""
# length用来计算循环链表的长度
length = 0
# 声明cur指针,用于遍历链表
cur = self.head.next
# 若cur没有指向自己,则表明未遍历完成
while cur != self.head:
length += 1
cur = cur.next
return length
def display(self):
"""
遍历循环链表,进行展示
:return:
"""
if self.isEmpty():
print("当前循环链表为空!")
return
print("循环链表的元素为:", end='')
# 遍历循环链表
cur = self.head.next
while cur != self.head:
print(cur.data, end='')
cur = cur.next
print()
def append(self, data):
"""
建立循环链表
:param data: 待插入的元素
:return:
"""
# 查找尾结点
rear = self.head
while rear.next != self.head:
rear = rear.next
# 创建新结点
newNode = Node(data)
# 将尾结点的后继结点指针指向新结点
rear.next = newNode
# 将新结点的后继结点指针指向头结点
newNode.next = self.head
def insert(self, index, data):
"""
在循环链表中任一位置插入元素
:param index: 待插入的位置
:param data: 待插入的元素值
:return:
"""
i = 1
# 声明指针pre,用于遍历循环链表
pre = self.head.next
# 遍历停止的条件,pre为空,或指向下标为index-1的结点
while pre != self.head and i != index-1:
pre = pre.next
i += 1
# index非法
if pre == self.head or i > self.getLength():
raise IndexError("index 非法")
# 创建新结点
newNode = Node(data)
# 将新结点的后继指针指向指针pre的后继结点
newNode.next = pre.next
# 将第index个结点的后继指针指向新结点
pre.next = newNode
def delete(self, index):
"""
在循环链表中任一位置删除元素
:param index: 删除下标index的元素
:return: 被删的元素值
"""
if self.isEmpty():
raise IndexError("当前循环链表为空!")
i = 1
# 声明指针pre,用来遍历循环链表
pre = self.head.next
# 遍历停止的条件,pre为空,或指向下标为index-1的结点
while pre != self.head and i != index - 1:
pre = pre.next
i += 1
# index非法
if pre == self.head or i > self.getLength():
raise IndexError("index 非法")
# 获取被删元素的值
data = pre.next.data
# 将要删结点从循环链表中断开
pre.next = pre.next.next
return data
if __name__ == '__main__':
print('PyCharm')
# 循环链表调试
# 1.初始化
list = CLinkedList()
list.display()
# 2. 创建循环链表,尾插法
for i in range(10):
list.append(chr(ord('A') + i))
print('尾插法结果:', end='')
list.display()
# 3.获取循环链表长度
length = list.getLength()
print('循环链表长度', length)
# 4.在表中插入元素
list.insert(2, 'Y')
list.display()
# 5.在表中删除元素
data = list.delete(3)
print('被删除元素值为:', data)
list.display()
顺序表与链表的比较
- 空间上:顺序表存储空间静态分配;动态链表的存储空间为动态分配。
- 时间上:顺序表随机存取,链式表需从头指针开始取得。
- 插入删除上:顺序表平均需移动近一半元素;链式表只需修改指针。
- 操作上:顺序表的存储等操作较为简单,而链式表中指针的操作较为复杂,难操作。
链式存储方式的比较
- 带头结点的循环链表
- 带尾结点的循环链表