最近身边的朋友在研究用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

上代码!

 #链表的节点
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()

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

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

python实现 双向循环链表的更多相关文章

  1. python实现双向循环链表

    参考https://www.cnblogs.com/symkmk123/p/9693872.html#4080149 # -*- coding:utf-8 -*- # __author__ :kusy ...

  2. Linux内核2.6.14源码分析-双向循环链表代码分析(巨详细)

    Linux内核源码分析-链表代码分析 分析人:余旭 分析时间:2005年11月17日星期四 11:40:10 AM 雨 温度:10-11度 编号:1-4 类别:准备工作 Email:yuxu97101 ...

  3. 双向链表、双向循环链表的JS实现

    关于链表简介.单链表.单向循环链表.JS中的使用以及扩充方法:  单链表.循环链表的JS实现 关于四种链表的完整封装: https://github.com/zhuwq585/Data-Structu ...

  4. C语言通用双向循环链表操作函数集

    说明 相比Linux内核链表宿主结构可有多个链表结构的优点,本函数集侧重封装性和易用性,而灵活性和效率有所降低.     可基于该函数集方便地构造栈或队列集.     本函数集暂未考虑并发保护. 一  ...

  5. 双向循环链表的Java版本实现

    1.单项循环列表 单向循环链表是单链表的另一种形式,其结构特点是链表中最后一个结点的指针不再是结束标记,而是指向整个链表的第一个结点,从而使单链表形成一个环.和单链表相比,循环单链表的长处是从链尾到链 ...

  6. c语言编程之双向循环链表

    双向循环链表就是形成两个环,注意每个环的首尾相连基本就可以了. 程序中采用尾插法进行添加节点. #include<stdio.h> #include<stdlib.h> #de ...

  7. Linux内核中的通用双向循环链表

    开发中接触Linux越来越多,休息放松之余,免不了翻看翻看神秘的Linux的内核.看到双向链表时,觉得挺有意思的,此文记下. 作为众多基础数据结构中的一员,双向循环链表在各种“教科书”中的实现是相当的 ...

  8. java与数据结构(4)---java实现双向循环链表

    线性表之链式存储结构双向循环链表 双向循环链表:每个结点包含了数据.直接前驱地址指针和直接后驱地址指针,头结点的直接前驱指向尾结点,尾结点的直接后驱指向头结点,头尾相连构成一个可正可反的圆环.可以形象 ...

  9. 基于visual Studio2013解决算法导论之025双向循环链表

     题目 双向循环链表 解决代码及点评 #include <stdio.h> #include <stdlib.h> #include <time.h> #in ...

随机推荐

  1. 【前端单元测试入门03】Sinon

    前端测试存在的问题 在讲Sinon之前,我们得先讲一下在学习了Mocha.chai以及enzyme之后,我们的前端测试还存在的一些问题. 比如前台测试需要与后台交互,获取后台数据后再根据相应数据进行测 ...

  2. linux中的颜色控制

    \033[031m  xxx  \033[0m  ---------------------->中间的xxx部分显示为红色,不接后面的\033[0m,则以后显示的都是红色,\033表示开始和结束 ...

  3. shell脚本中文件测试

    shell脚本中文件测试 author:headsen chen  2017-10-17  14:35:19 个人原创,转载请注明作者,否则 依法追究法律责任 [ -f  filename  ]   ...

  4. [HAOI2016] 放棋子及错排问题

    题目 Description 给你一个N*N的矩阵,每行有一个障碍,数据保证任意两个障碍不在同一行,任意两个障碍不在同一列,要求你在这个矩阵上放N枚棋子(障碍的位置不能放棋子),要求你放N个棋子也满足 ...

  5. shiro(二)自定义realm,模拟数据库查询验证

    自定义一个realm类,实现realm接口 package com; import org.apache.shiro.authc.*; import org.apache.shiro.realm.Re ...

  6. java创建运行以及项目结构

    一 创建java project 再src下添加class,选择一个class添加main方法作为程序的入口 二.项目结构: src下添加不同的包,命名方法为com.jikexueyuan.hello ...

  7. linux服务器添加一块新硬盘不用重新启动机器的操作

    Linux系统添加一块新硬盘不用关闭系统即可加载硬盘信息的操作 因之前换过硬盘重装系统,硬盘上的数据没有拷贝出来,开发人员问我要备份,炸了.我只好联系机房让他把之前换掉的硬盘插回服务器.但是插好之后f ...

  8. postman简单教程-环境变量,全局变量的设置及作用

    讲postman环境变量设置之前,先讲一个小插曲,环境变量.全局变量的区别在于Globals,只能用一组,而Environmen可以设置多组,所以我更喜欢设置环境变量 1.环境变量-Environme ...

  9. [poj3904]Sky Code_状态压缩_容斥原理

    Sky Code poj-3904 题目大意:给你n个数,问能选出多少满足题意的组数. 注释:如果一个组数满足题意当且仅当这个组中有且只有4个数,且这4个数的最大公约数是1,$1\le n\le 10 ...

  10. 设计模式之 原型模式详解(clone方法源码的简单剖析)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. 原型模式算是JAVA中最简单 ...