Python链表详细笔记
目录
链表(链接列表)简介
代码实现
以class类创建节点
以class类创建链表
生成简单链表
输出简单链表
通过函数生成链表
输出函数生成链表
通过函数输出链表
通过函数插入节点(在给定节点之后添加节点)
通过函数删除节点
搜索链表中的元素
对于按位置查值
对于按位置查找
实战练习
反转链表
交换链接列表中的节点而不只交换值
链表(链接列表)简介
与数组一样,Linked List链表是一种线性数据结构。与数组不同,链表元素不存储在连续的位置; 元素使用指针链接。
为何链接列表? 数组可用于存储类似类型的线性数据,但数组具有以下限制。 1)数组的大小是固定的:所以我们必须事先知道元素数量的上限。而且,通常,分配的存储器等于上限而与使用无关。 2)在元素数组中插入新元素是昂贵的,因为必须为新元素创建空间并创建空间必须移动现有元素。
相对于阵列的优点 1)动态大小 2)易于插入/删除
相对于阵列的缺点: 1)不允许随机访问。我们必须从第一个节点开始按顺序访问元素。因此,我们不能使用其默认实现有效地使用链表进行二进制搜索。 2)列表的每个元素都需要指针的额外内存空间。 3)不缓存友好。由于数组元素是连续的位置,因此存在引用的位置,在链接列表的情况下不存在。
表示: 链表由指向链表的第一个节点的指针表示。第一个节点称为头部。如果链接列表为空,则head的值为NULL。 列表中的每个节点至少由两部分组成: 1)数据 2)指向下一个节点的指针(或参考)
代码实现
以class类创建节点
每个节点包含当前节点所要存的数据data,和指向下一节点的pnxet指针。pnext指针默认给空值。
class Node:
def __init__(self, data, pnext=None):
self.data = data
self.pnext = pnext
以class类创建链表
链表初始时候有一个空的phead头指针,和表示链表长度的length。
class Link:
def __init__(self):
self.phead = None
self.length = 0
生成简单链表
先实例化链表Link,然后实例化节点Node,最后把节点链接起来
if __name__ == '__main__':
link = Link() # 实例化链表Link
first = Node(1) # 实例化节点Node1
second = Node(2) # 实例化节点Node2
third = Node(3) # 实例化节点Node3
link.phead = Node(None) # 实例化空节点Node
link.phead.pnext = first # 链接节点head-1
first.pnext = second # 链接节点1-2
second.pnext = third # 链接节点2-3
third.pnext = None # 链接节点3-end
'''
list.head first second third
| | | |
| | | |
+----+------+ +----+------+ +----+------+ +----+------+
|None| None |---->| 1 | None |---->| 2 | None |---->| 3 | None |
+----+------+ +----+------+ +----+------+ +----+------+
'''
输出简单链表
输出当前节点的data,再将pnext指针指向下一个链表,循环直至末尾
temp = link.phead.pnext
while temp:
print(temp.data)
temp = temp.pnext
# Output:
# 1 2 3
通过函数生成链表
先创建一个phead头结点,注意该节点内不放数据。然后依次从所给的入参循环创建节点,并将节点链接,再将长度length+1。最后记得将末尾节点的pnext指针指向空None,并返回所生成链表的phead头指针。
class Link:
def __init__(self):
self.phead = None
self.length = 0
def creat(self, datas):
self.phead = Node(None) # 创建空的头部,不存数据
pend = self.phead # 借用临时量,方便后续操作
for i in datas: # 依次从所给入参中拿数据
node = Node(i) # 创建节点
pend.pnext = node # 上一节点的pnext指针,指向这个新创建的节点
pend = node # 这个节点赋值给临时量,方便进行下一轮循环
self.length += 1 # 链表长度+1
pend.pnext = None # 末尾节点的pnxet指针为空,表示后面无数据
return self.phead # 返回生成的链表的头指针
输出函数生成链表
输出当前节点的data,再将pnext指针指向下一个链表,循环直至末尾
if __name__ == '__main__':
link = Link() # 实例化链表Link
new = link.creat([1,2,3,4,5,6])
new = new.pnext
while new:
print(new.data)
new = new.pnext
# Output:
# 1 2 3 4 5 6
通过函数输出链表
可以通过节点是否为None来判断是否到末尾,也可通过之前的self.length来判断
class Link:
def __init__(self):
self.phead = None
self.length = 0
def display(self):
cursor = self.phead.pnext # 定位到第一个节点
for i in range(self.length): # 根据长度判断是否到末尾
print(cursor.data) # 输出节点数据
cursor = cursor.pnext # 指向下一节点
if __name__ == '__main__':
link = Link() # 实例化链表Link
new = link.creat([1,2,3,4,5,6])
link.display()
# Output:
# 1 2 3 4 5 6
通过函数插入节点(在给定节点之后添加节点)
该函数需要指定插入的位置index,和要插入的数据val。先从头结点开始循环遍历,直到到达了位置index,再创建val对应的节点,以上图为例,先将新建节点E的pnext指针指向下一节点C,再将上一节点B的pnext指针指向节点E。最后记得将length+1。
class Link:
def insert(self, index, val):
cursor = self.phead # 定位到头节点
for i in range(index): # 跳过index个节点
cursor = cursor.pnext
node = Node(val) # 创建新节点
node.pnext = cursor.pnext # 新建节点的pnext = 上一节点的pnext
cursor.pnext = node # 上一节点的pnext = 新建节点
self.length += 1 # 链表长度+1
if __name__ == '__main__':
link = Link() # 实例化链表Link
new = link.creat([1,2,3])
link.display()
link.insert(3,0)
link.display()
# Output:
# 1 2 3
# 1 2 3 0
通过函数删除节点
该函数需要指定待删除节点所在位置index。先找到要删除的节点的上一个节点,更改上一个节点到下一个节点,释放要删除的节点的内存。在C语言中为malloc()和free()对应使用,python中可使用del。
如果要删除的节点是root,只需将其删除即可。要删除中间节点,我们必须有指向要删除的节点之前的节点的指针。因此,如果位置不为零,我们运行循环位置-1次并获得指向前一节点的指针。
class Link:
def delete(self, index):
if index > self.length or index <= 0:
print('Out of index')
return
cursor = self.phead # 定位到头节点
for i in range(index-1): # 跳过index-1个节点
cursor = cursor.pnext
nextnode = cursor.pnext.pnext # 存储需要删除的节点的下一个节点
del cursor.pnext # 删除节点
cursor.pnext = nextnode # 连接上一节点与下一节点
self.length -= 1 # 链表长度-1
if __name__ == '__main__':
link = Link() # 实例化链表Link
new = link.creat([1,2,3,4,5,6])
link.display()
link.delete(4)
link.display()
link.delete(10)
# Output:
# 1 2 3 4 5 6
# 1 2 3 5 6
# Out of index
搜索链表中的元素
搜索元素分为按位置index查找值data,和按值data查找位置index。
对于按位置查值
循环链表,直至找到值,并返回位置index,否则提示输出。
class Link:
def searchByval(self, val):
cursor = self.phead.pnext
index = 0
while cursor:
index += 1
if val == cursor.data:
print(index) # 输出值
return index # 返回值
cursor = cursor.pnext # 指向下一个节点
print("No available value") # 输出提示
return None # 返回值
if __name__ == '__main__':
link = Link() # 实例化链表Link
new = link.creat([9,5,7,4,2,6])
link.display()
link.searchByval(3)
link.searchByval(4)
# Output:
# 9 5 7 4 2 6
# No available value
# 4
对于按位置查找
先判断index是否在链表长度length内,然后循环值index,输出值data,否则输出提示。
class Link:
def searchByindex(self, index):
if index > self.length or index <= 0:
print('Out of index') # 输出提示
return None
cursor = self.phead # 定位到头节点
for i in range(index):
cursor = cursor.pnext
print(cursor.data) # 输出值
return cursor.data # 返回值
if __name__ == '__main__':
link = Link() # 实例化链表Link
new = link.creat([9,5,7,4,2,6])
link.display()
link.searchByindex(3)
link.searchByindex(10)
# Output:
# 9 5 7 4 2 6
# 7
# Out of index
实战练习
反转链表
示例:
输入:以下链表的头部 1-> 2-> 3-> 4-> NULL 输出:链接列表应更改为, 4-> 3-> 2-> 1-> NULL 输入:以下链表的头部 1-> 2-> 3-> 4-> 5-> NULL 输出:链接列表应更改为, 5-> 4-> 3-> 2-> 1-> NULL 输入:NULL 输出:NULL 输入:1-> NULL 输出:1-> NULL
迭代法
- 初始化三个指针prev为NULL,curr为head,next为NULL。
- 通过链表迭代。在循环中,执行以下操作。 //在更改当前节点的下一个节点之前, //存储下一个节点 next = curr-> next //现在改变当前节点的下一节点 //这是实际逆转发生的地方 curr-> next = prev //将prev和curr向前移动一步 prev = curr curr = next
总结为:先存储当前节点的下一节点,再反转当前节点的pnext指针,最后重置head头部。 注意:若head指向Null而不放数据,则prev、curr、next应相应改变
class Link:
def reverse(self):
prev = self.phead # 上一指针
curr = self.phead.pnext # 当前指针
next = self.phead # 下一指针
while curr:
next = curr.pnext # 先存储下一节点
curr.pnext = prev # 反转pnext指针指向
prev = curr # 反转完成后,上一节点后移
curr = next # 反转完成后,当前节点后移
self.phead.pnext = prev # 重置节点
if __name__ == '__main__':
link = Link() # 实例化链表Link
new = link.creat([1,2,3,4,5,6])
link.display()
link.reverse()
link.display()
# Output:
# 1 2 3 4 5 6
# 6 5 4 3 2 1
交换链接列表中的节点而不只交换值
给定一个链表和两个键,交换两个给定键的节点。应通过更改链接来交换节点。在数据包含许多字段的许多情况下,交换节点数据可能是昂贵的。
可以假设链表中的所有键都是不同的。
例子:
输入:10-> 15-> 12-> 13-> 20-> 14,x = 3,y = 5 输出:10-> 15-> 20-> 13-> 12-> 14 输入:10-> 15-> 12-> 13-> 20-> 14,x = 1,y = 5 输出:20-> 15-> 12-> 13-> 10-> 14 输入:10-> 15-> 12-> 13-> 20-> 14,x = 3,y = 4 输出:10-> 15-> 13-> 12-> 20-> 14
这可能看起来很简单,但这是一个有趣的问题,因为它有以下案例需要处理。
- x和y可以相邻也可以不相邻。
- x或y可以是头节点。
- x或y可以是最后一个节点。
- 链接列表中可能不存在x和/或y。
它首先在给定的链表中搜索x和y。如果其中任何一个不存在,那么返回。在搜索x和y时,跟踪当前和之前的指针。首先更改前一个指针的下一个,然后更改当前指针的下一个。
class Link:
def swapNodes(self, x, y):
if x > self.length or y > self.length: # 判断是否在内
print("invalid")
return None
ma = max(x, y) # 较大者
mi = min(x, y) # 较小者
cursor = self.phead # 指向头部
curr_x = self.phead.pnext # 指向第一个节点
pre_x = self.phead # 指向头部
for i in range(ma-1): # 遍历较大者
cursor = cursor.pnext
if i == mi - 2: # 遍历较小者
pre_x = cursor # x节点的上一节点
curr_x = cursor.pnext # x节点
pre_y = cursor # y节点的上一节点
curr_y = cursor.pnext # y节点
pre_x.pnext, pre_y.pnext = pre_y.pnext, pre_x.pnext # 交换指针
curr_x.pnext, curr_y.pnext = curr_y.pnext, curr_x.pnext # 交换指针
if __name__ == '__main__':
link = Link() # 实例化链表Link
new = link.creat([1,2,3,4,5,6])
link.display()
link.swapNodes(1, 4)
link.display()
# Output:
# 1 2 3 4 5 6
# 4 2 3 1 5 6
未完待续...
欢迎关注↓↓↓
- 微信公众号:xfxuezhang
- [机智的机器在学习] TensorFlow实现Kmeans聚类
- [机智的机器在学习] 利用TensorFlow实现多元线性回归分类器
- [数据结构和算法]《算法导论》动态规划笔记(1)
- [数据结构和算法]《算法导论》动态规划笔记(2)
- [算法与数据结构] 《算法导论》堆排序笔记
- [数据结构与算法] 链表的其他类型
- [数据结构与算法] 链接表总结
- [数据结构与算法] 线性表总结
- [数据结构与算法] Python实现二分查找
- [机智的机器在学习] 机器学习中的归一化和正则化问题
- [情人节] jieba分词介绍
- 左手用R右手Python系列——异常捕获与容错处理
- 【观点】漫谈推荐系统及数据库技术(二)——分布式数据库技术
- BizTalk 2013R2 WCF-LOB Oracle Adapter安装配置/问题&解决方法
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- php-7.3.6 编译安装过程
- PHP查找一列有序数组是否包含某值的方法
- python 从文件夹抽取图片另存的方法
- laravel框架使用极光推送消息操作示例
- 对pycharm 修改程序运行所需内存详解
- Python小工具之消耗系统指定大小内存的方法
- Thinkphp框架+Layui实现图片/文件上传功能分析
- PHP实现单例模式建立数据库连接的方法分析
- 解决Python2.7中IDLE启动没有反应的问题
- PHP中mysqli_get_server_version()的实例用法
- 在unittest中使用 logging 模块记录测试数据的方法
- 分享8个Laravel模型时间戳使用技巧小结
- 基于python实现名片管理系统
- 记一个OLED编程中文显示函数的坑(留意变量数据类型的范围)
- tp5框架基于Ajax实现列表无刷新排序功能示例