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标准库之随机数 (math包、random包)介绍
Nov 25 Python
python爬取51job中hr的邮箱
May 14 Python
Python 40行代码实现人脸识别功能
Apr 02 Python
python selenium执行所有测试用例并生成报告的方法
Feb 13 Python
Python中使用遍历在列表中添加字典遇到的坑
Feb 27 Python
python函数的万能参数传参详解
Jul 26 Python
Python笔试面试题小结
Sep 07 Python
python根据时间获取周数代码实例
Sep 30 Python
Python学习笔记之函数的参数和返回值的使用
Nov 20 Python
Python3并发写文件与Python对比
Nov 20 Python
pytorch 实现变分自动编码器的操作
May 24 Python
Python实现Excel文件的合并(以新冠疫情数据为例)
Mar 20 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连接mssql:pdo odbc sql server
2011/07/20 PHP
PHP合并两个数组的两种方式的异同
2012/09/14 PHP
php解析xml提示Invalid byte 1 of 1-byte UTF-8 sequence错误的处理方法
2013/11/14 PHP
PHPExcel笔记, mpdf导出
2016/05/03 PHP
基于Swoole实现PHP与websocket聊天室
2016/08/03 PHP
PHP的curl函数的用法总结
2019/02/14 PHP
使用PHP反射机制来构造&quot;CREATE TABLE&quot;的sql语句
2019/03/21 PHP
PHP中迭代器的简单实现及Yii框架中的迭代器实现方法示例
2020/04/26 PHP
Javascript和Ajax中文乱码吐血版解决方案
2009/12/21 Javascript
jQuery Ajax()方法使用指南
2014/11/19 Javascript
探讨:JavaScript ECAMScript5 新特性之get/set访问器
2016/05/05 Javascript
json传值以及ajax接收详解
2016/05/24 Javascript
JS for...in 遍历语句用法实例分析
2016/08/24 Javascript
js学习笔记之事件处理模型
2016/10/31 Javascript
详解Javascript中DOM的范围
2017/02/13 Javascript
JS实现css hover操作的方法示例
2017/04/07 Javascript
BootStrap selectpicker后台动态绑定数据的方法
2017/07/28 Javascript
深入浅析ES6 Class 中的 super 关键字
2017/10/20 Javascript
EasyUI实现下拉框多选功能
2017/11/07 Javascript
详解写好JS条件语句的5条守则
2019/02/28 Javascript
JavaScript设计模式之观察者模式与发布订阅模式详解
2020/05/07 Javascript
JavaScript手写数组的常用函数总结
2020/11/22 Javascript
测试、预发布后用python检测网页是否有日常链接
2014/06/03 Python
Python numpy.array()生成相同元素数组的示例
2018/11/12 Python
python执行scp命令拷贝文件及文件夹到远程主机的目录方法
2019/07/08 Python
使用Python进行防病毒免杀解析
2019/12/13 Python
Python逐行读取文件内容的方法总结
2020/02/14 Python
解决python3输入的坑——input()
2020/12/05 Python
一款利用css3的鼠标经过动画显示详情特效的实例教程
2014/12/29 HTML / CSS
开发人员所需要知道的HTML5性能分析面面观
2012/07/05 HTML / CSS
整理HTML5中支持的URL编码与字符编码
2016/02/23 HTML / CSS
.NET方向面试题
2014/11/20 面试题
财务管理专业毕业生求职信范文
2013/09/21 职场文书
妇女干部培训方案
2014/05/12 职场文书
2015年入党积极分子评语
2015/03/26 职场文书
浅析Python实现DFA算法
2021/06/26 Python