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两种遍历字典(dict)的方法比较
May 29 Python
用Python进行行为驱动开发的入门教程
Apr 23 Python
Django自定义认证方式用法示例
Jun 23 Python
Python搜索引擎实现原理和方法
Nov 27 Python
opencv与numpy的图像基本操作
Mar 08 Python
在python下使用tensorflow判断是否存在文件夹的实例
Jun 10 Python
Python实现的远程文件自动打包并下载功能示例
Jul 12 Python
pytorch获取vgg16-feature层输出的例子
Aug 20 Python
Python3 使用pillow库生成随机验证码
Aug 26 Python
Pandas缺失值2种处理方式代码实例
Jun 13 Python
浅谈TensorFlow之稀疏张量表示
Jun 30 Python
Python matplotlib绘制雷达图
Apr 13 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或asp创建网页桌面快捷方式的代码
2010/03/23 PHP
PHP按行读取文件时删除换行符的3种方法
2014/05/04 PHP
php实现字符串首字母大写和单词首字母大写的方法
2015/03/14 PHP
PHP使用FFmpeg获取视频播放总时长与码率等信息
2016/09/13 PHP
PHP 面向对象程序设计之类属性与类常量实现方法分析
2020/04/13 PHP
JavaScript 未结束的字符串常量常见解决方法
2010/01/24 Javascript
Javascript 键盘事件的组合使用实现代码
2012/05/04 Javascript
异步动态加载JS并运行(示例代码)
2013/12/13 Javascript
JavaScript使用slice函数获取数组部分元素的方法
2015/04/06 Javascript
jQuery中toggle()函数的使用实例
2015/04/17 Javascript
深入探讨前端框架react
2015/12/09 Javascript
JavaScript实现99乘法表及隔行变色实例代码
2016/02/24 Javascript
Angularjs 动态添加指令并绑定事件的方法
2017/04/13 Javascript
vue.js 上传图片实例代码
2017/06/22 Javascript
ES6学习笔记之map、set与数组、对象的对比
2018/03/01 Javascript
element-ui 的el-button组件中添加自定义颜色和图标的实现方法
2018/10/26 Javascript
[01:47]2018年度DOTA2最具人气解说-完美盛典
2018/12/16 DOTA
[42:24]完美世界DOTA2联赛循环赛 LBZS vs DM BO2第一场 11.01
2020/11/02 DOTA
跟老齐学Python之永远强大的函数
2014/09/14 Python
python和opencv实现抠图
2018/07/18 Python
python实现一个简单的ping工具方法
2019/01/31 Python
PyQt QCombobox设置行高的方法
2019/06/20 Python
python实现人工智能Ai抠图功能
2019/09/05 Python
Python 线性回归分析以及评价指标详解
2020/04/02 Python
如何基于Python Matplotlib实现网格动画
2020/07/20 Python
2分钟教你实现环形/扇形菜单(基础版)
2020/01/15 HTML / CSS
公务员年总结的自我评价
2013/10/25 职场文书
元旦寄语大全
2014/04/10 职场文书
学校爱心捐款倡议书
2014/05/13 职场文书
学校食堂食品安全责任书
2014/07/28 职场文书
医院志愿者活动总结
2015/05/06 职场文书
生日赠语
2015/06/23 职场文书
浙江省杭州市平均工资标准是多少?
2019/07/09 职场文书
简单且有用的Python数据分析和机器学习代码
2021/07/02 Python
使用jpa之动态插入与修改(重写save)
2021/11/23 Java/Android
Python&Matlab实现灰狼优化算法的示例代码
2022/03/21 Python