数据结构
1、概述
存储、组织数据的方式,包括列表、元组、集合、字典、队列、栈、链表。
2、分类
线性结构
1.概述
所有节点 只有一个 直接前驱节点 和 一个 直接后继节点
2.存储分类
- 顺序表:连续的存储
存储结构:信息区,数据区
存储方式:1. 一体式存储:替换只能 整体搬迁
2. 分离式存储
扩充方式:1. 增加 固定数目 的存储位置
2. 容量加倍
- 链表:非连续 的存储
结构:由节点(Node)组成,用 “链条” 连接起来
节点组成:1. 数值域 item(元素域):存数据的
2. 地址域 next(链接域):存下个节点的地址
3. 变量 head 指向链表的 头节点(首节点)
链表分类:单向链表、单向循环链表、双向链表、双向循环链表
3、单向链表代码实现
需求1:定义节点类,单向链表类,并设置初始化
# 1、定义SingleNode类,表示节点类
class SingleNode:
# 初始化节点
def __init__(self, item):
self.item = item # 元素域:存储具体数据
self.next = None # 链接域:存储下个节点地址
# 2、定义SingleLinkedList类,表示(单向)链表
class SingleLinkedList:
# 2.1 初始化链表
def __init__(self, node=None):
# head(默认)指向 链表中的第1个节点
self.head = node
需求2:在链表类中,定义函数:判断链表是否为空,为空返回True
# 2.2 判断链表 是否为空
def is_empty(self):
# 写法 1: if、else方法
# if self.head == None:
# return True
# else:
# return False
# 写法 2: 三元
# return True if self.head == None else False
# 写法 3: 最终版
return self.head == None
需求3:在链表类中,定义函数:查看链表长度
# 2.3 查看链表长度
def length(self):
# 1. 定义 当前节点 cur,初始值为 头节点
cur = self.head
# 2. 定义计数器, 记录: 节点个数
count = 0
# 3. 判断 cur(当前节点)是否为None, 如果不是, 就一直循环
while cur is not None:
# 4. 进这里, 说明是1个非空节点, 计数器 + 1
count += 1
# 5. 当前节点判断后, cur指向下1个节点
cur = cur.next
# 6. 返回计数结果
return count
需求4:在链表类中,定义函数:遍历链表并打印结果
# 2.4 遍历链表
def travel(self):
# 1、定义cur变量,用于记录:链表中的 每个节点
cur = self.head
# 2. 判断当前节点是否为空, 不为空, 就一直循环
while cur is not None:
# 3. 不为空,就打印节点信息
print(cur.item)
# 4. cur指向下1个节点
cur = cur.next
需求5:在链表类中,定义函数:在头部 添加元素
# 2.5 在链表 头部 添加元素
def add(self, item):
# 1、根据输入,创建新节点
new_node = SingleNode(item)
# 2、设置新节点的 地址域 为 头节点
new_node.next = self.head
# 3、更新 head指向 新的头节点
self.head = new_node
需求6:在链表类中,定义函数:在尾部 添加元素
# 2.6 在链表 尾部 添加元素
def append(self, item):
# 1、根据输入,创建新节点
new_node = SingleNode(item)
# 2. 判断链表是否为空
if self.head == None:
# 链表为空, 则新节点就是头部节点
self.head = new_node
else:
# 3. 链表不为空,获取链表的最后1个节点
# 3.1 创建cur变量, 默认指向头部节点
cur = self.head
# 3.2 只要当前节点的地址域不为 None, 就一直获取
while cur.next is not None:
# 更新当前节点
cur = cur.next
# 3.3 循环结束, 说明获取的节点就是最后1个节点(它的地址域为None)
# 设置当前(最后1个节点)的地址域为: 新的节点
cur.next = new_node
需求7:在链表类中,定义函数:在指定位置 添加元素
# 2.7 在 指定位置 添加元素
def insert(self, pos, item): # pos为指定位置
# 1. 指定位置若 <= 0 ,就在开头添加
if pos <= 0:
self.add(item)
# 2. 指定位置若 >= 链表长度,就在结尾添加
elif pos >= self.length():
self.append(item)
# 3. 否则,即在链表中间 添加
else:
# 4. 创建新节点
new_node = SingleNode(item)
# 5. 创建cur变量, 指向: 插入位置前的那个节点. 默认: 头节点
cur = self.head
# 6. 定义count变量, 用于: 计数, 获取插入位置前的值
count = 0
# 7. 获取插入位置前的那个元素
while count < pos - 1:
cur = cur.next
count += 1 # 计数器 + 1
# 8. 设置新节点的地址域为: 当前节点的地址域
new_node.next = cur.next
# 9. 设置当前节点的地址域为: 新的节点
cur.next = new_node
需求8:在链表类中,定义函数:根据节点内容 删除指定节点
# 2.8 删除指定节点
def remove(self, item):
# 1. 定义变量 cur, 从头节点开始, 获取被删除的节点
cur = self.head
# 2. 定义变量 pre, 表示: 被删除节点的 前置节点
pre = None
# 3. 只要 cur不为空, 我们就一直遍历, 获取每个节点
while cur is not None:
# 4. 判断当前节点的数值域 是否和 要删除的元素值 相同
# 4.1 相同, 则要被删除
if cur.item == item:
# 4.1.1 如果是头部节点, 直接用 head 指向 cur.next即可
if cur == self.head:
self.head = cur.next
# 4.1.2 如果不是头部节点, 用 pre的地址域 指向 当前节点的地址域(即下个节点) 完成删除
else:
pre.next = cur.next
# 核心细节: 删除元素后, 循环终止.
break
else:
# 4.2 如果不同, 说明当前节点不是要被删除的节点, 我们继续判断下 1个节点
pre = cur # 当前节点(检验过) 充当前置节点
cur = cur.next
需求9:在链表类中,定义函数:查找节点是否存在,存在返回True
# 2.9 查找节点是否存在
def search(self, item):
# 1. 定义变量 cur, 记录每个节点, 初值为: 头部节点.
cur = self.head
# 2. 如果 cur节点不为空, 我们就一直遍历
while cur is not None:
# 3. 判断当前节点的item值, 是否和要查找的item值一致
if cur.item == item:
# 找到啦!返回 True
return True
# 4. 没找到,继续判断下一个节点
cur = cur.next
# 5. 整个循环结束, 没有找到, 返回 False
return False
需求10:在 main方法中测试结果
# 3. 在 main方法中测试
if __name__ == '__main__':
# 3.1 创建单个节点
sn1 = SingleNode('小林')
print(sn1.item) # 当前节点的: 元素域值
print(sn1.next) # 当前节点的: 地址域值
# 3.2 创建链表
linked_list = SingleLinkedList(sn1)
print(f'目前的头节点是:{linked_list.head}')
# 3.3 判断链表是否为空
print(linked_list.is_empty())
# 3.4 打印链表的长度(元素个数)
print(f'链表长度为:{linked_list.length()}')
# 3.5 打印链表内容
linked_list.travel()
# 3.6 演示在链表 头部 添加
linked_list.add('小陈')
linked_list.add('小月')
# 3.7 演示在链表 尾部 添加
linked_list.append('小雪')
linked_list.append('小念')
# 3.8 演示在链表 中间 添加
linked_list.insert(3, '小龙')
# 再次查看链表内容
linked_list.travel()
# 3.9 演示 删除
linked_list.remove('小龙')
# 3.10 演示 查找
print(linked_list.search('小林'))
完整代码如下:
# 1、定义SingleNode类,表示节点类
class SingleNode:
# 初始化节点
def __init__(self, item):
self.item = item # 元素域:存储具体数据
self.next = None # 链接域:存储下个节点地址
# 2、定义SingleLinkedList类,表示(单向)链表
class SingleLinkedList:
# 2.1 初始化链表
def __init__(self, node=None):
# head(默认)指向 链表中的第1个节点
self.head = node
# 2.2 判断链表 是否为空
def is_empty(self):
return self.head == None
# 2.3 查看链表长度
def length(self):
# 1. 定义 当前节点 cur,初始值为 头节点
cur = self.head
# 2. 定义计数器, 记录: 节点个数
count = 0
# 3. 判断 cur(当前节点)是否为None, 如果不是, 就一直循环
while cur is not None:
# 4. 进这里, 说明是1个非空节点, 计数器 + 1
count += 1
# 5. 当前节点判断后, cur指向下1个节点
cur = cur.next
# 6. 返回计数结果
return count
# 2.4 遍历链表
def travel(self):
# 1、定义cur变量,用于记录:链表中的 每个节点
cur = self.head
# 2. 判断当前节点是否为空, 不为空, 就一直循环
while cur is not None:
# 3. 不为空,就打印节点信息
print(cur.item)
# 4. cur指向下1个节点
cur = cur.next
# 2.5 在链表 头部 添加元素
def add(self, item):
# 1、根据输入,创建新节点
new_node = SingleNode(item)
# 2、设置新节点的 地址域 为 头节点
new_node.next = self.head
# 3、更新 head指向 新的头节点
self.head = new_node
# 2.6 在链表 尾部 添加元素
def append(self, item):
# 1、根据输入,创建新节点
new_node = SingleNode(item)
# 2. 判断链表是否为空
if self.head == None:
# 链表为空, 则新节点就是头部节点
self.head = new_node
else:
# 3. 链表不为空,获取链表的最后1个节点
# 3.1 创建cur变量, 默认指向头部节点
cur = self.head
# 3.2 只要当前节点的地址域不为 None, 就一直获取
while cur.next is not None:
# 更新当前节点
cur = cur.next
# 3.3 循环结束, 说明获取的节点就是最后1个节点(它的地址域为None)
# 设置当前(最后1个节点)的地址域为: 新的节点
cur.next = new_node
# 2.7 在 指定位置 添加元素
def insert(self, pos, item): # pos为指定位置
# 1. 指定位置若 <= 0 ,就在开头添加
if pos <= 0:
self.add(item)
# 2. 指定位置若 >= 链表长度,就在结尾添加
elif pos >= self.length():
self.append(item)
# 3. 否则,即在链表中间 添加
else:
# 4. 创建新节点
new_node = SingleNode(item)
# 5. 创建cur变量, 指向: 插入位置前的那个节点. 默认: 头节点
cur = self.head
# 6. 定义count变量, 用于: 计数, 获取插入位置前的值
count = 0
# 7. 获取插入位置前的那个元素
while count < pos - 1:
cur = cur.next
count += 1 # 计数器 + 1
# 8. 设置新节点的地址域为: 当前节点的地址域
new_node.next = cur.next
# 9. 设置当前节点的地址域为: 新的节点
cur.next = new_node
# 2.8 删除指定节点
def remove(self, item):
# 1. 定义变量 cur, 从头节点开始, 获取被删除的节点
cur = self.head
# 2. 定义变量 pre, 表示: 被删除节点的 前置节点
pre = None
# 3. 只要 cur不为空, 我们就一直遍历, 获取每个节点
while cur is not None:
# 4. 判断当前节点的数值域 是否和 要删除的元素值 相同
# 4.1 相同, 则要被删除
if cur.item == item:
# 4.1.1 如果是头部节点, 直接用 head 指向 cur.next即可
if cur == self.head:
self.head = cur.next
# 4.1.2 如果不是头部节点, 用 pre的地址域 指向 当前节点的地址域(即下个节点) 完成删除
else:
pre.next = cur.next
# 核心细节: 删除元素后, 循环终止.
break
else:
# 4.2 如果不同, 说明当前节点不是要被删除的节点, 我们继续判断下 1个节点
pre = cur # 当前节点(检验过) 充当前置节点
cur = cur.next
# 2.9 查找节点是否存在
def search(self, item):
# 1. 定义变量 cur, 记录每个节点, 初值为: 头部节点.
cur = self.head
# 2. 如果 cur节点不为空, 我们就一直遍历
while cur is not None:
# 3. 判断当前节点的item值, 是否和要查找的item值一致
if cur.item == item:
# 找到啦!返回 True
return True
# 4. 没找到,继续判断下一个节点
cur = cur.next
# 5. 整个循环结束, 没有找到, 返回 False
return False
# 3. 在 main方法中测试
if __name__ == '__main__':
# 3.1 创建单个节点
sn1 = SingleNode('小林')
print(sn1.item) # 当前节点的: 元素域值
print(sn1.next) # 当前节点的: 地址域值
# 3.2 创建链表
linked_list = SingleLinkedList(sn1)
print(f'目前的头节点是:{linked_list.head}')
# 3.3 判断链表是否为空
print(linked_list.is_empty())
# 3.4 打印链表的长度(元素个数)
print(f'链表长度为:{linked_list.length()}')
# 3.5 打印链表内容
linked_list.travel()
# 3.6 演示在链表 头部 添加
linked_list.add('小陈')
linked_list.add('小月')
# 3.7 演示在链表 尾部 添加
linked_list.append('小雪')
linked_list.append('小念')
# 3.8 演示在链表 中间 添加
linked_list.insert(3, '小龙')
linked_list.travel()
# 3.9 演示 删除
linked_list.remove('小龙')
# 3.10 演示 查找
print(linked_list.search('小林'))
感谢阅读!一起努力练习吧~