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生成日历实例解析
Aug 21 Python
简单的Apache+FastCGI+Django配置指南
Jul 22 Python
Django与遗留的数据库整合的方法指南
Jul 24 Python
Python win32com 操作Exce的l简单方法(必看)
May 25 Python
Python实现按中文排序的方法示例
Apr 25 Python
基于python3 的百度图片下载器的实现代码
Nov 05 Python
Python __slots__的使用方法
Nov 15 Python
用 Django 开发一个 Python Web API的方法步骤
Dec 03 Python
python集合的新增元素方法整理
Dec 07 Python
Python创建文件夹与文件的快捷方法
Dec 08 Python
python中_del_还原数据的方法
Dec 09 Python
Python实战之大鱼吃小鱼游戏的实现
Apr 01 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模板技术原理【一】
2008/01/10 PHP
PHP+Mysql+Ajax+JS实现省市区三级联动
2014/05/23 PHP
Js获取事件对象代码
2010/08/05 Javascript
异步javascript的原理和实现技巧介绍
2012/11/08 Javascript
jquery禁止回车触发表单提交
2014/12/12 Javascript
JavaScript针对网页节点的增删改查用法实例
2015/02/02 Javascript
JS实现三个层重叠点击互相切换的方法
2015/10/06 Javascript
Bootstrap每天必学之响应式导航、轮播图
2016/04/25 Javascript
jQuery实现的省市县三级联动菜单效果完整实例
2016/08/01 Javascript
微信小程序 自定义对话框实例详解
2017/01/20 Javascript
详解React开发必不可少的eslint配置
2018/02/05 Javascript
js数据类型转换与流程控制操作实例分析
2019/12/18 Javascript
[02:12]探秘2016国际邀请赛中国区预选赛选手房间
2016/06/25 DOTA
[01:00:53]OG vs IG 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
[57:31]DOTA2-DPC中国联赛 正赛 SAG vs CDEC BO3 第一场 2月1日
2021/03/11 DOTA
python正则表达式抓取成语网站
2013/11/20 Python
Python yield使用方法示例
2013/12/04 Python
Python中的测试模块unittest和doctest的使用教程
2015/04/14 Python
听歌识曲--用python实现一个音乐检索器的功能
2016/11/15 Python
PyQt5每天必学之布局管理
2018/04/19 Python
判断python字典中key是否存在的两种方法
2018/08/10 Python
python利用跳板机ssh远程连接redis的方法
2019/02/19 Python
Python实现基于socket的udp传输与接收功能详解
2019/11/15 Python
用python爬取历史天气数据的方法示例
2019/12/30 Python
python re模块匹配贪婪和非贪婪模式详解
2020/02/11 Python
Python递归函数特点及原理解析
2020/03/04 Python
linux系统都有哪些运行级别
2016/03/26 面试题
普通院校学生的自荐信
2013/11/27 职场文书
青年志愿者事迹材料
2014/02/07 职场文书
安全施工责任书
2014/08/25 职场文书
小学感恩节活动总结
2015/03/24 职场文书
会议简报格式范文
2015/07/20 职场文书
消防宣传标语大全
2015/08/03 职场文书
JavaScript 防篡改对象的用法示例
2021/04/24 Javascript
Python多个MP4合成视频的实现方法
2021/07/16 Python
Win11 Build 22000.829更新补丁KB5015882发布(附更新修复内容汇总)
2022/07/15 数码科技