Python双向循环链表实现方法分析


Posted in Python onJuly 30, 2018

本文实例讲述了Python双向循环链表实现方法。分享给大家供大家参考,具体如下:

最近身边的朋友在研究用python来实现数据结构。遇到一个问题就是双向循环链表的实现,改指向的时候总是发蒙。

我自己尝实现了一个python的双向循环链表。附上代码,希望对大家有帮助。

如果不懂什么是双向循环链表的伙伴,需要补习一下数据结构的基础之后哦~~~

在python当中 用一个类Node 来实现链表的节点,节点数据有三个变量:

  • prev:前驱指针: 用于指向当前节点前一个节点
  • next: 后继指针  用于指向当前节点后一个节点
  • item: 值, 用于存储该节点要存的数值

当前节点的前一个节点我们叫他前驱,后一个节点我们叫他后继。

在链表类当中,我们有一个变量head是链表的头指针

我们拿着链表的头head,就可以对他进行一些列操作:( 由于是双向循环链表,修改指针特别容易出错,我尽量说的细致,方便大家参考)

判断空:is_empty()

如果头指针head没有指向则链表是空的 否则不是空的

在头部添加元素: add(item)

1 新建一个节点 里面的值是item。

2 放入头部:

2.1 如果链表是空的,node的next和prev都指向自己,然后head再指向node

在尾部添加元素: append(item)

1 创建一个新节点node 里面的值是item

2 放入尾部:

2.1 如果链表空,则执行头部添加add就可以

2.2 链表非空:

2.2.1 node的next指向head

2.2.2 node的prev指向head的prev

2.2.3 head的prev元素的next指向node

2.2.4 head的prev指向改为node

2.2.5 head指向node  更换了头部

指定位置添加元素: insert( pos , item )

1 新建一个节点node 里面的值是item

2 找到合适的位置插进去:

2.1 如果pos <= 0 还小,那就执行头插方法 add()

2.2 如果pos >= 链表长度, 那就执行尾部插入 append()

2.3 如果pos位置在链表的中间:

2.3.1 定义一个临时变量temp 按照传入的pos找到要插入的位置的前一个元素

2.3.2 node的prev设为temp,node的next设为temp的next

2.3.3 temp的next指向的节点的prev改为node

2.3.4 temp的next改为node

得到链表长度: length()

1 我们设置一个临时变量temp初始设为head , 设置一个计数器count 初始为 0

2 令count自增1 然后temp改指向自己的下一个元素 一直到temp遇到None 为止,temp到了链表的最后一个元素

通过这样的方式,统计出一共有多少个节点返回

遍历链表数据: travelji()

1 设置一个临时变量temp初始化设为head

2 temp 每次输出自己指向元素的值,然后在指向自己的下一个元素,一直temp为None 说明到了列表的尾部

删除链表元素: remove( item )

1 开启temp临时变量 初始化为head ,

2  temp不断指向自己的下一个元素,每次指向一个元素都检查当前值是不是item,如果找到item则删除它返回True,如果没找到就到尾部了就返回False

2.1 删除过程:

2.1.1 temp的前一个元素的next改为temp的后一个元素

2.1.2 temp的后一个元素的prev改为前一个元素

查询是否有元素:search()

设置一个临时变量temp从head开始,不断指向自己下一个,每次都检查一下自己的值如果和item相同返回True结束

如果temp变成None 则到尾部了都没找到 返回False

上代码!

# -*- coding:utf-8 -*-
#!python3
#链表的节点
class Node(object):
 def __init__(self , item ):
  self.item = item #节点数值
  self.prev = None #用于指向前一个元素
  self.next = None #用于指向后一个元素
#双向循环链表
class DoubleCircleLinkList(object):
 def __init__(self):
  self.__head = None #初始化的时候头节点设为空、
 #判断链表是否为空,head为None 的话则链表是空的
 def is_empty(self):
  return self.__head is None
 #头部添加元素的方法
 def add(self,item):
  node = Node(item) #新建一个节点node 里面的值是item
  # 如果链表是空的,则node的next和prev都指向自己(因为是双向循环),head指向node
  if self.is_empty():
   self.__head = node
   node.next = node
   node.prev = node
  # 否则链表不空
  else:
   node.next = self.__head #node的next设为现在的head
   node.prev = self.__head.prev #node的prev 设为现在head的prev
   self.__head.prev.next = node #现在head的前一个元素的next设为node
   self.__head.prev = node #现在head的前驱 改为node
   self.__head = node #更改头部指针
 #尾部添加元素方法
 def append(self , item):
  #如果当前链表是空的 那就调用头部插入方法
  if self.is_empty():
   self.add(item)
  #否则链表不为空
  else :
   node = Node(item) #新建一个节点node
   #因为是双向循环链表,所以head的prev其实就是链表的尾部
   node.next = self.__head #node的下一个设为头
   node.prev = self.__head.prev #node的前驱设为现在头部的前驱
   self.__head.prev.next = node #头部前驱的后继设为node
   self.__head.prev = node #头部自己的前驱改为node
 #获得链表长度 节点个数
 def length(self):
  #如果链表是空的 就返回0
  if self.is_empty():
   return 0
  #如果不是空的
  else:
   cur = self.__head #临时变量cur表示当前位置 初始化设为头head
   count = 1 #设一个计数器count,cur每指向一个节点,count就自增1 目前cur指向头,所以count初始化为1
   #如果cur.next不是head,说明cur目前不是最后一个元素,那么count就1,再让cur后移一位
   while cur.next is not self.__head:
    count += 1
    cur = cur.next
   #跳出循环说明所有元素都被累加了一次 返回count就是一共有多少个元素
   return count
 #遍历链表的功能
 def travel(self):
  #如果当前自己是空的,那就不遍历
  if self.is_empty():
   return
  #链表不空
  else :
   cur = self.__head #临时变量cur表示当前位置,初始化为链表的头部
   #只要cur的后继不是头说明cur不是最后一个节点,我们就输出当前值,并让cur后移一个节点
   while cur.next is not self.__head:
    print( cur.item,end=" " )
    cur = cur.next
   #当cur的后继是head的时候跳出循环了,最后一个节点还没有打印值 在这里打印出来
   print( cur.item )
 #置顶位置插入节点
 def insert(self, pos , item ):
  #如果位置<=0 则调用头部插入方法
  if pos <= 0:
   self.add(item)
  #如果位置是最后一个或者更大 就调用尾部插入方法
  elif pos > self.length() - 1 :
   self.append(item)
  #否则插入位置就是链表中间
  else :
   index = 0 #设置计数器,用于标记我们后移了多少步
   cur = self.__head #cur标记当前所在位置
   #让index每次自增1 ,cur后移,当index=pos-1的时候说明cur在要插入位置的前一个元素,这时候停下
   while index < pos - 1 :
    index += 1
    cur = cur.next
   #跳出循环,cur在要插入位置的前一个元素,将node插入到cur的后面
   node = Node(item) #新建一个节点
   node.next = cur.next #node的后继设为cur的后继
   node.prev = cur #node的前驱设为cur
   cur.next.prev = node #cur后继的前驱改为node
   cur.next = node #cur后继改为node
 #删除节点操作
 def remove(self,item):
  #如果链表为空 直接不操作
  if self.is_empty():
   return
  #链表不为空
  else:
   cur = self.__head #临时变量标记位置,从头开始
   #如果头结点就是 要删除的元素
   if cur.item == item:
    #如果只有一个节点 链表就空了 head设为None
    if self.length() == 1:
     self.__head = None
    #如果多个元素
    else:
     self.__head = cur.next #头指针指向cur的下一个
     cur.next.prev= cur.prev #cur后继的前驱改为cur的前驱
     cur.prev.next = cur.next #cur前驱的后继改为cur的后继
   #否则 头节点不是要删除的节点 我们要向下遍历
   else:
    cur = cur.next #把cur后移一个节点
    #循环让cur后移一直到链表尾元素位置,期间如果找得到就删除节点,找不到就跳出循环,
    while cur is not self.__head:
     #找到了元素cur就是要删除的
     if cur.item == item:
      cur.prev.next = cur.next #cur的前驱的后继改为cur的后继
      cur.next.prev = cur.prev #cur的后继的前驱改为cur的前驱
     cur = cur.next
 #搜索节点是否存在
 def search(self , item):
  #如果链表是空的一定不存在
  if self.is_empty():
   return False
  #否则链表不空
  else:
   cur = self.__head #设置临时cur从头开始
   # cur不断后移,一直到尾节点为止
   while cur.next is not self.__head:
    #如果期间找到了就返回一个True 结束运行
    if cur.item == item:
     return True
    cur = cur.next
   # 从循环跳出来cur就指向了尾元素 看一下为元素是不是要找的 是就返回True
   if cur.item ==item:
    return True
   #所有元素都不是 就返回False 没找到
   return False
if __name__ == "__main__":
 dlcl = DoubleCircleLinkList()
 print(dlcl.search(7))
 dlcl.travel()
 dlcl.remove(1)
 print(dlcl.length())
 print(dlcl.is_empty())
 dlcl.append(55)
 print(dlcl.search(55))
 dlcl.travel()
 dlcl.remove(55)
 dlcl.travel()
 print(dlcl.length())
 dlcl.add(3)
 print(dlcl.is_empty())
 dlcl.travel()
 dlcl.add(4)
 dlcl.add(5)
 dlcl.append(6)
 dlcl.insert(-10,1)
 dlcl.travel()
 print(dlcl.length())
 dlcl.remove(6)
 dlcl.travel()
 print(dlcl.search(7) )
 dlcl.append(55)
 dlcl.travel()

运行结果:

False
0
True
True
55
0
False
3
1 5 4 3 6
5
1 5 4 3
False
1 5 4 3 55

各种数据结构主要是思想,不同的人实现方式都不一定一样,同一个人多次实现也不一定一样。所以以上代码仅供参考~

如果有更简洁的方式,欢迎大家批评指正哦~

希望本文所述对大家Python程序设计有所帮助。

Python 相关文章推荐
Python Socket编程入门教程
Jul 11 Python
python爬虫自动创建文件夹的功能
Aug 01 Python
对python中的argv和argc使用详解
Dec 15 Python
用python一行代码得到数组中某个元素的个数方法
Jan 28 Python
python快速编写单行注释多行注释的方法
Jul 31 Python
python编写猜数字小游戏
Oct 06 Python
pytorch标签转onehot形式实例
Jan 02 Python
Python识别验证码的实现示例
Sep 30 Python
一文带你了解Python 四种常见基础爬虫方法介绍
Dec 04 Python
python实现调用摄像头并拍照发邮箱
Apr 27 Python
Python内置类型集合set和frozenset的使用详解
Apr 26 Python
tensorflow更改变量的值实例
Jul 30 #Python
Python使用分布式锁的代码演示示例
Jul 30 #Python
利用Python如何批量修改数据库执行Sql文件
Jul 29 #Python
利用Python如何批量更新服务器文件
Jul 29 #Python
python高阶爬虫实战分析
Jul 29 #Python
python3.5基于TCP实现文件传输
Mar 20 #Python
python3基于TCP实现CS架构文件传输
Jul 28 #Python
You might like
PHP 进程锁定问题分析研究
2009/11/24 PHP
php操作SVN版本服务器类代码
2011/11/27 PHP
PHP判断远程图片是否存在的几种方法
2014/05/04 PHP
PHP永久登录、记住我功能实现方法和安全做法
2015/04/27 PHP
php+redis实现消息队列功能示例
2019/09/19 PHP
解决Laravel无法使用COOKIE和SESSION的问题
2019/10/16 PHP
在IE上直接编辑网页内容的js代码(IE地址栏js)
2009/04/27 Javascript
JavaScript 学习笔记(九)call和apply方法
2010/01/11 Javascript
jquery实用代码片段集合
2010/08/12 Javascript
Nodejs中读取中文文件编码问题、发送邮件和定时任务实例
2015/01/01 NodeJs
JS实现鼠标箭头变成一个燃烧烛光效果的方法
2015/02/28 Javascript
基于JavaScript实现网页倒计时自动跳转代码
2015/12/28 Javascript
jQuery+css实现非常漂亮的水平导航菜单效果
2016/07/27 Javascript
js+canvas实现动态吃豆人效果
2017/03/22 Javascript
Node层模拟实现multipart表单的文件上传示例
2018/01/02 Javascript
浅谈vuex 闲置状态重置方案
2018/01/04 Javascript
微信小程序实现商城倒计时
2020/11/01 Javascript
微信小程序实现日期格式化和倒计时
2020/11/01 Javascript
layui监听select变化,以及设置radio选中的方法
2019/09/24 Javascript
vue.config.js常用配置详解
2019/11/14 Javascript
详解Vue3 Composition API中的提取和重用逻辑
2020/04/29 Javascript
Python中str.format()详解
2017/03/12 Python
Django中数据库的数据关系:一对一,一对多,多对多
2018/10/21 Python
3行Python代码实现图像照片抠图和换底色的方法
2019/10/10 Python
python简单实现最大似然估计&amp;scipy库的使用详解
2020/04/15 Python
Python 串口通信的实现
2020/09/29 Python
Gtech官方网站:地毯清洁器、吸尘器及园艺设备
2018/05/23 全球购物
美国折扣香水网站:The Perfume Spot
2020/12/12 全球购物
一套Delphi的笔试题一
2016/02/14 面试题
司机岗位职责
2013/11/15 职场文书
个人简历中的自我评价怎么写
2014/01/26 职场文书
幼儿教师自我剖析材料
2014/09/29 职场文书
元旦晚会主持词开场白
2015/05/28 职场文书
城南旧事观后感
2015/06/11 职场文书
德能勤绩工作总结
2015/08/11 职场文书
使用Navicat Premium工具将oracle数据库迁移到MySQL
2021/05/27 Oracle