Python实现双向链表


Posted in Python onMay 25, 2022

单向链表和环形链表都只是单向的,只能单向遍历,不能根据后面的节点获取前面的节点,除非进行反转操作。

双向链表每个节点都有两个指针,这两个指针分别指向前后两个节点,这样就可以从任意一个节点从两个方向获取其他的所有节点,非常方便。但是由于每个节点有两个指针,所以双向链表比较消耗空间。

在设计双向链表时,通常会加上一个链表头指针,该链表头指针的数据字段不存放任何数据。

双向链表的可以是环形的,也可以不是环形的,如果是环形的话,那么最后一个节点的一个指针将指向链表头,链表头的一个指针将指向最后一个节点;如果不是环形的话,那么最后一个节点的一个指针和链表头的一个指针都将指向None。

我在这里实现的是一个环形的双向链表,这样我就可以从链表头开始,从两个方向中任意选择一个方向来进行操作。

我在这里主要实现了环形双向链表的:双向新增,双向遍历,双向插入,双向删除。

Python实现双向链表

如图为双向环形链表示意图,每一个节点都被两个指针所指向,同时每个节点也指向了两个节点。

实现代码如下:

class Player:
    """节点类"""
    def __init__(self):
        """初始化姓名,分数,指针"""
        self.name = ''
        self.score = 0
        self.rlink = None
        self.llink = None
 
 
def ergodic(head, num=None, is_print=False, left=False):
    """遍历函数,num是遍历到哪一个位置序号,is_print是否触发打印方法,left表示是否由head开始往左遍历"""
    ptr = head
    count = 0
    while True:
        if num == count:
            break
 
        if not left:
            if ptr.rlink != head:
                ptr = ptr.rlink
            else:
                break
        else:
            if ptr.llink != head:
                ptr = ptr.llink
            else:
                break
        count += 1
        if is_print:
            print('No.'+str(count), ptr.llink.name if ptr.llink != head else 'head', '<---',
                  ptr.name, ptr.score, '--->', ptr.rlink.name if ptr.rlink != head else 'head')
    return ptr  # 返回遍历完成后的最后一个节点
 
 
head = Player()  # 初始化一个链表头指针,不用来存放任何数据
head.rlink = head  # 初始化右指针
head.llink = head  # 初始化左指针
 
 
while True:
    select = input("(1).新增   (2).查看   (3).插入   (4).删除   (5).离开\n输入:")
    if select == "1":  # 新增节点,分为右新增和左新增
        direction = input("(1).右新增   (2).左新增\n输入:")
        if direction not in ("1", "2"):
            print("输入错误")
            continue
        new_data = Player()
        new_data.name = input("姓名:")
        new_data.score = input("分数:")
        if direction == "1":  # 右新增
            ptr = ergodic(head)  # 从head开始向右遍历获取最后一个节点
            ptr.rlink = new_data
            new_data.llink = ptr
            new_data.rlink = head
            head.llink = new_data
        else:  # 左新增
            ptr = ergodic(head, left=True)  # 从head开始向左遍历获取最后一个节点
            ptr.llink = new_data
            new_data.rlink = ptr
            new_data.llink = head
            head.rlink = new_data
 
    elif select == "2":  # 遍历查看所有节点,分为右遍历和左遍历
        direction = input("(1).右遍历   (2).左遍历\n输入:")
        if direction == "1":  # 右遍历
            ergodic(head, is_print=True)
        elif direction == "2":  # 左遍历
            ergodic(head, is_print=True, left=True)
        else:
            print("输入错误")
 
    elif select == '3':  # 插入节点,分为右插入和左插入
        direction = input("(1).右插入   (2).左插入\n输入:")
        if direction not in ("1", "2"):
            print("输入错误")
            continue
        try:
            num = int(input("请输入需要插入的节点位置序号:"))  # 输入序号必须是大于0的正整数,如果输入大于最后一个节点的序号则插入到最后一个节点之后
            if num < 1:
                print("输入必须为大于0的正整数")
                continue
        except ValueError:
            print("输入有误")
            continue
        insert_data = Player()
        insert_data.name = input("姓名:")
        insert_data.score = input("分数:")
        if direction == "1":  # 右插入
            ptr = ergodic(head, num - 1)  # 获取需要插入位置的前一个节点,新插入的节点就在这个节点的后面
            insert_data.llink = ptr
            insert_data.rlink = ptr.rlink
            ptr.rlink = insert_data
            insert_data.rlink.llink = insert_data
        else:  # 左插入
            ptr = ergodic(head, num - 1, left=True)
            insert_data.rlink = ptr
            insert_data.llink = ptr.llink
            ptr.llink = insert_data
            insert_data.llink.rlink = insert_data
 
    elif select == '4':  # 删除节点,分为右删除和左删除
        direction = input("(1).右删除   (2).左删除\n输入:")
        if direction not in ("1", "2"):
            print("输入错误")
            continue
        try:
            num = int(input("请输入需要删除的节点位置序号:"))  # 输入序号必须是大于0的正整数,如果输入大于最后一个节点的序号则删除最后一个节点
            if num < 1:
                print("输入必须为大于0的正整数")
                continue
        except ValueError:
            print("输入有误")
            continue
        if direction == "1":  # 右删除
            ptr = ergodic(head, num)  # 获取需要删除的节点
        else:  # 左删除
            ptr = ergodic(head, num, left=True)
        ptr.llink.rlink = ptr.rlink
        ptr.rlink.llink = ptr.llink
 
    elif select == '5':
        print("成功离开")
        break
    else:
        print("输入错误,请重试")

部分运行效果如下:

Python实现双向链表

以上就是本文的全部内容,希望对大家的学习有所帮助。


Tags in this post...

Python 相关文章推荐
Python内置函数Type()函数一个有趣的用法
Feb 18 Python
用Python代码来绘制彭罗斯点阵的教程
Apr 03 Python
Python中的两个内置模块介绍
Apr 05 Python
使用Python的Twisted框架编写简单的网络客户端
Apr 16 Python
python判断计算机是否有网络连接的实例
Dec 15 Python
详解python的argpare和click模块小结
Mar 31 Python
python实现雪花飘落效果实例讲解
Jun 18 Python
django框架cookie和session用法实例详解
Dec 10 Python
在echarts中图例legend和坐标系grid实现左右布局实例
May 16 Python
Django ORM实现按天获取数据去重求和例子
May 18 Python
Python爬虫新手入门之初学lxml库
Dec 20 Python
Python实现曲线拟合的最小二乘法
Feb 19 Python
python区块链持久化和命令行接口实现简版
May 25 #Python
python区块链实现简版工作量证明
May 25 #Python
pycharm无法安装cv2模块问题
May 20 #Python
python中 Flask Web 表单的使用方法
May 20 #Python
Python OpenGL基本配置方式
May 20 #Python
Python面试不修改数组找出重复的数字
May 20 #Python
Python 中面向接口编程
May 20 #Python
You might like
PHP error_log()将错误信息写入一个文件(定义和用法)
2013/10/25 PHP
PHP采用自定义函数实现遍历目录下所有文件的方法
2014/08/19 PHP
thinkphp3.2.3版本的数据库增删改查实现代码
2016/09/22 PHP
PHP实现正则表达式分组捕获操作示例
2018/02/03 PHP
Laravel程序架构设计思路之使用动作类
2018/06/07 PHP
基于Laravel(5.4版本)的基本增删改查操作方法
2019/10/11 PHP
在 Laravel 6 中缓存数据库查询结果的方法
2019/12/11 PHP
tp5.1 框架join方法用法实例分析
2020/05/26 PHP
php实现断点续传大文件示例代码
2020/06/19 PHP
js判断上传文件类型判断FileUpload文件类型代码
2014/05/20 Javascript
Bootstrap每天必学之工具提示(Tooltip)插件
2016/04/26 Javascript
jQuery Easyui 验证两次密码输入是否相等
2016/05/13 Javascript
Vue2几种常见开局方式详解
2017/09/09 Javascript
微信小程序实现的动态设置导航栏标题功能示例
2019/01/31 Javascript
Vue-CLI 3.X 部署项目至生产服务器的方法
2019/03/22 Javascript
用Vue.js方法创建模板并使用多个模板合成
2019/06/28 Javascript
vue登录页面cookie的使用及页面跳转代码
2019/07/10 Javascript
react MPA 多页配置详解
2019/10/18 Javascript
javascript 内存模型实例详解
2020/04/18 Javascript
Nodejs实现WebSocket代码实例
2020/05/19 NodeJs
[44:15]DOTA2上海特级锦标赛主赛事日 - 5 败者组决赛Liquid VS EG第二局
2016/03/06 DOTA
python海龟绘图实例教程
2014/07/24 Python
研究Python的ORM框架中的SQLAlchemy库的映射关系
2015/04/25 Python
Python中time模块与datetime模块在使用中的不同之处
2015/11/24 Python
python的random模块及加权随机算法的python实现方法
2017/01/04 Python
python实现冒泡排序算法的两种方法
2018/03/10 Python
Python 实用技巧之利用Shell通配符做字符串匹配
2019/08/23 Python
python+playwright微软自动化工具的使用
2021/02/02 Python
基于Html5 canvas实现裁剪图片和马赛克功能及又拍云上传图片 功能
2019/07/09 HTML / CSS
瑞典时尚耳机品牌:Urbanears
2017/07/26 全球购物
校园十大歌手策划书
2014/02/01 职场文书
药剂专业个人求职信范文
2014/04/29 职场文书
写字楼租赁意向书
2014/07/30 职场文书
公司借条范本
2015/05/25 职场文书
Golang 获取文件md5校验的方法以及效率对比
2021/05/08 Golang
解决Springboot PostMapping无法获取数据的问题
2022/05/06 Java/Android