Python与数据结构[0] -> 链表/LinkedList[1] -> 双链表与循环双链表的 Python 实现
双链表 / Doubly Linked List
目录
1 双链表
双链表和单链表的不同之处在于,双链表需要多增加一个域(C语言),即在Python中需要多增加一个属性,用于存储指向前一个结点的信息。
Doubly linked list:
node_1 <---> node_2 <---> node_3
完整代码
from linked_list import LinkedList, test class NodeDual:
def __init__(self, val=None, nxt=None, pre=None):
self.value = val
self.next = nxt
self.prev = pre def __str__(self):
return '<NodeDual, prev=%s, value=%s, next=%s>' % (self.prev.value if self.prev else self.prev,
self.value,
self.next.value if self.next else self.next) class DoublyLinkedList(LinkedList):
"""
Doubly linked list:
node_1 <---> node_2 <---> node_3
"""
def __str__(self):
def _traversal(self):
node = self.header
while node and node.next:
yield node
node = node.next
yield node
return '<->\n'.join(map(lambda x: str(x), _traversal(self))) def init(self, iterable=()):
if not iterable:
return
self.header = NodeDual(iterable[0]) # header value
pre = None
node = self.header
for i in iterable[1:]: # add all node
node.prev = pre
node.next = NodeDual(i)
pre = node
node = node.next
node.prev = pre def find_previous(self, item):
return self.find(item).prev def delete(self, item):
pre = self.find_previous(item)
if pre:
pre.next = pre.next.next
pre.next.prev = pre def insert(self, item, index):
if abs(index) > self.length:
return
if index < 0:
self.insert(item, self.length+index+1)
return
elif index == 0:
self.insert(self.header.value, 1)
self.header.value = item
return
node = self.header
i = 0
while i < index-1:
node = node.next
i += 1
n = node.next
node.next = NodeDual(item, nxt=n, pre=node)
if n:
n.prev = node.next if __name__ == '__main__':
test(DoublyLinkedList())
分段解释
双链表可以的基本特性与单链表相同,因此可以继承单链表。首先导入前面写好的单链表类和测试函数。
from linked_list import LinkedList, test
然后定义一个双向结点,包含前后两个属性,用于存放前后结点的信息。同时重定义__str__方法,在显示结点时显示该结点的前后结点及自身值,从而方便查看。
class NodeDual:
def __init__(self, val=None, nxt=None, pre=None):
self.value = val
self.next = nxt
self.prev = pre def __str__(self):
return '<NodeDual, prev=%s, value=%s, next=%s>' % (self.prev.value if self.prev else self.prev,
self.value,
self.next.value if self.next else self.next)
定义双链表类,基类为单链表,构造函数可以使用单链表的构造函数。
class DoublyLinkedList(LinkedList):
"""
Doubly linked list:
node_1 <---> node_2 <---> node_3
"""
def __str__(self):
def _traversal(self):
node = self.header
while node and node.next:
yield node
node = node.next
yield node
return '<->\n'.join(map(lambda x: str(x), _traversal(self)))
init方法,与单链表不同的地方在于,添加结点时需要同时修改结点的前后属性(引用指针)。
def init(self, iterable=()):
if not iterable:
return
self.header = NodeDual(iterable[0]) # header value
pre = None
node = self.header
for i in iterable[1:]: # add all node
node.prev = pre
node.next = NodeDual(i)
pre = node
node = node.next
node.prev = pre
find_previous方法,查找前一个结点的方法将变得很简单,只需要找到需要找的结点后,通过结点获取前一个结点即可。
def find_previous(self, item):
return self.find(item).prev
删除和插入类似于单链表的思路,只不过需要多处理一个前驱结点引用。
def delete(self, item):
pre = self.find_previous(item)
if pre:
pre.next = pre.next.next
pre.next.prev = pre def insert(self, item, index):
if abs(index) > self.length:
return
if index < 0:
self.insert(item, self.length+index+1)
return
elif index == 0:
self.insert(self.header.value, 1)
self.header.value = item
return
node = self.header
i = 0
while i < index-1:
node = node.next
i += 1
n = node.next
node.next = NodeDual(item, nxt=n, pre=node)
if n:
n.prev = node.next
同样利用测试单链表的函数对双链表进行测试,
if __name__ == '__main__':
test(DoublyLinkedList())
得到结果
Show linked list:
None Init linked list:
<NodeDual, prev=None, value=1, next=2><->
<NodeDual, prev=1, value=2, next=3><->
<NodeDual, prev=2, value=3, next=4><->
<NodeDual, prev=3, value=4, next=5><->
<NodeDual, prev=4, value=5, next=6><->
<NodeDual, prev=5, value=6, next=xd><->
<NodeDual, prev=6, value=xd, next=8><->
<NodeDual, prev=xd, value=8, next=9><->
<NodeDual, prev=8, value=9, next=None> Insert element:
<NodeDual, prev=None, value=1, next=2><->
<NodeDual, prev=1, value=2, next=3><->
<NodeDual, prev=2, value=3, next=4><->
<NodeDual, prev=3, value=4, next=5><->
<NodeDual, prev=4, value=5, next=6><->
<NodeDual, prev=5, value=6, next=xd><->
<NodeDual, prev=6, value=xd, next=xxd><->
<NodeDual, prev=xd, value=xxd, next=8><->
<NodeDual, prev=xxd, value=8, next=9><->
<NodeDual, prev=8, value=9, next=None> Append element:
<NodeDual, prev=None, value=1, next=2><->
<NodeDual, prev=1, value=2, next=3><->
<NodeDual, prev=2, value=3, next=4><->
<NodeDual, prev=3, value=4, next=5><->
<NodeDual, prev=4, value=5, next=6><->
<NodeDual, prev=5, value=6, next=xd><->
<NodeDual, prev=6, value=xd, next=xxd><->
<NodeDual, prev=xd, value=xxd, next=8><->
<NodeDual, prev=xxd, value=8, next=9><->
<NodeDual, prev=8, value=9, next=10><->
<NodeDual, prev=9, value=10, next=None> Find element:
xd Find previous element:
6 Delete element:
<NodeDual, prev=None, value=1, next=2><->
<NodeDual, prev=1, value=2, next=3><->
<NodeDual, prev=2, value=3, next=4><->
<NodeDual, prev=3, value=4, next=5><->
<NodeDual, prev=4, value=5, next=6><->
<NodeDual, prev=5, value=6, next=xxd><->
<NodeDual, prev=6, value=xxd, next=8><->
<NodeDual, prev=xxd, value=8, next=9><->
<NodeDual, prev=8, value=9, next=10><->
<NodeDual, prev=9, value=10, next=None> Find element not exist:
None Insert element to header:
<NodeDual, prev=None, value=cc, next=1><->
<NodeDual, prev=cc, value=1, next=2><->
<NodeDual, prev=1, value=2, next=3><->
<NodeDual, prev=2, value=3, next=4><->
<NodeDual, prev=3, value=4, next=5><->
<NodeDual, prev=4, value=5, next=6><->
<NodeDual, prev=5, value=6, next=xxd><->
<NodeDual, prev=6, value=xxd, next=8><->
<NodeDual, prev=xxd, value=8, next=9><->
<NodeDual, prev=8, value=9, next=10><->
<NodeDual, prev=9, value=10, next=None> Clear linked list:
None Current length: 0 Is empty: True
2 循环双链表
循环双链表类似于双链表,但是将表的头尾两个结点相连,形成了一个循环链表结构,即头结点的前一个结点为尾结点,尾结点的下一个结点为头结点。
Doubly linked list with loop:
________________________________________________________
| |
<===> node_1 <---> node_2 <---> node_3 <---> node_4 <===>
|________________________________________________________|
首先导入需要的结点和双链表类以及测试函数,
from linked_list_doubly import NodeDual, DoublyLinkedList, test
接着定义循环双链表类,对链表的显示输出同样要先遍历链表,而这里的遍历函数需要额外增加一个判断条件,即当再次遇到头结点时,遍历停止,否则将无限循环遍历下去。
class DoublyLinkedListLoop(DoublyLinkedList):
"""
Doubly linked list with loop:
________________________________________________________
| |
<===> node_1 <---> node_2 <---> node_3 <---> node_4 <===>
|________________________________________________________|
"""
def __str__(self):
def _traversal(self):
node = self.header
while node and node.next is not self.header:
yield node
node = node.next
yield node
return '<->\n'.join(map(lambda x: str(x), _traversal(self)))
循环双链表的生成函数比双链表多了一个步骤,即将双链表的头尾结点相接。
def init(self, iterable=()):
if not iterable:
return
self.header = NodeDual(iterable[0]) # header value
pre = None
node = self.header
for i in iterable[1:]: # add all node
node.prev = pre
node.next = NodeDual(i)
pre = node
node = node.next
node.prev = pre node.next = self.header
self.header.prev = node
用于获取表长度的属性方法同样需要更改,增加一个头结点判断来终止循环遍历。
@property
def length(self):
if self.header is None:
return 0
node = self.header
i = 1
while node.next is not self.header:
node = node.next
i += 1
return i
两个查找函数也是同样需要加入头结点判断来停止循环。
def find(self, item):
node = self.header
while node.next is not self.header and node.value != item:
node = node.next
if node.value == item:
return node
return None def find_previous(self, item):
node = self.header
while node.next is not self.header and node.next.value != item:
node = node.next
if node.next is not self.header and node.next.value == item:
return node
return None
最后用测试函数进行测试,
if __name__ == '__main__':
test(DoublyLinkedListLoop())
测试结果为
Show linked list:
None Init linked list:
<NodeDual, prev=9, value=1, next=2><->
<NodeDual, prev=1, value=2, next=3><->
<NodeDual, prev=2, value=3, next=4><->
<NodeDual, prev=3, value=4, next=5><->
<NodeDual, prev=4, value=5, next=6><->
<NodeDual, prev=5, value=6, next=xd><->
<NodeDual, prev=6, value=xd, next=8><->
<NodeDual, prev=xd, value=8, next=9><->
<NodeDual, prev=8, value=9, next=1> Insert element:
<NodeDual, prev=9, value=1, next=2><->
<NodeDual, prev=1, value=2, next=3><->
<NodeDual, prev=2, value=3, next=4><->
<NodeDual, prev=3, value=4, next=5><->
<NodeDual, prev=4, value=5, next=6><->
<NodeDual, prev=5, value=6, next=xd><->
<NodeDual, prev=6, value=xd, next=xxd><->
<NodeDual, prev=xd, value=xxd, next=8><->
<NodeDual, prev=xxd, value=8, next=9><->
<NodeDual, prev=8, value=9, next=1> Append element:
<NodeDual, prev=10, value=1, next=2><->
<NodeDual, prev=1, value=2, next=3><->
<NodeDual, prev=2, value=3, next=4><->
<NodeDual, prev=3, value=4, next=5><->
<NodeDual, prev=4, value=5, next=6><->
<NodeDual, prev=5, value=6, next=xd><->
<NodeDual, prev=6, value=xd, next=xxd><->
<NodeDual, prev=xd, value=xxd, next=8><->
<NodeDual, prev=xxd, value=8, next=9><->
<NodeDual, prev=8, value=9, next=10><->
<NodeDual, prev=9, value=10, next=1> Find element:
xd Find previous element:
6 Delete element:
<NodeDual, prev=10, value=1, next=2><->
<NodeDual, prev=1, value=2, next=3><->
<NodeDual, prev=2, value=3, next=4><->
<NodeDual, prev=3, value=4, next=5><->
<NodeDual, prev=4, value=5, next=6><->
<NodeDual, prev=5, value=6, next=xxd><->
<NodeDual, prev=6, value=xxd, next=8><->
<NodeDual, prev=xxd, value=8, next=9><->
<NodeDual, prev=8, value=9, next=10><->
<NodeDual, prev=9, value=10, next=1> Find element not exist:
None Insert element to header:
<NodeDual, prev=10, value=cc, next=1><->
<NodeDual, prev=cc, value=1, next=2><->
<NodeDual, prev=1, value=2, next=3><->
<NodeDual, prev=2, value=3, next=4><->
<NodeDual, prev=3, value=4, next=5><->
<NodeDual, prev=4, value=5, next=6><->
<NodeDual, prev=5, value=6, next=xxd><->
<NodeDual, prev=6, value=xxd, next=8><->
<NodeDual, prev=xxd, value=8, next=9><->
<NodeDual, prev=8, value=9, next=10><->
<NodeDual, prev=9, value=10, next=cc> Clear linked list:
None Current length: 0 Is empty: True
相关阅读
1. 单链表
Python与数据结构[0] -> 链表/LinkedList[1] -> 双链表与循环双链表的 Python 实现的更多相关文章
- Python与数据结构[0] -> 链表/LinkedList[0] -> 单链表与带表头单链表的 Python 实现
单链表 / Linked List 目录 单链表 带表头单链表 链表是一种基本的线性数据结构,在C语言中,这种数据结构通过指针实现,由于存储空间不要求连续性,因此插入和删除操作将变得十分快速.下面将利 ...
- Python与数据结构[0] -> 链表/LinkedList[2] -> 链表有环与链表相交判断的 Python 实现
链表有环与链表相交判断的 Python 实现 目录 有环链表 相交链表 1 有环链表 判断链表是否有环可以参考链接, 有环链表主要包括以下几个问题(C语言描述): 判断环是否存在: 可以使用追赶方法, ...
- python基础笔记-0
python中数据结构,主要有列表.元组.字典.集合. python中最基本数据结构是序列(sequence).序列中每个元素被分配一个序号——即元素位置,也成为索引.第一个索引是0,第二个是1,以此 ...
- C语言版本:循环单链表的实现
SClist.h #ifndef __SCLIST_H__ #define __SCLIST_H__ #include<cstdio> #include<malloc.h> # ...
- Python与数据结构[1] -> 栈/Stack[0] -> 链表栈与数组栈的 Python 实现
栈 / Stack 目录 链表栈 数组栈 栈是一种基本的线性数据结构(先入后出FILO),在 C 语言中有链表和数组两种实现方式,下面用 Python 对这两种栈进行实现. 1 链表栈 链表栈是以单链 ...
- python实现数据结构单链表
#python实现数据结构单链表 # -*- coding: utf-8 -*- class Node(object): """节点""" ...
- Java数据结构-线性表之单链表LinkedList
线性表的链式存储结构,也称之为链式表,链表:链表的存储单元能够连续也能够不连续. 链表中的节点包括数据域和指针域.数据域为存储数据元素信息的域,指针域为存储直接后继位置(一般称为指针)的域. 注意一个 ...
- 数据结构之链表(LinkedList)(三)
数据结构之链表(LinkedList)(二) 环形链表 顾名思义 环形列表是一个首尾相连的环形链表 示意图 循环链表的特点是无须增加存储量,仅对表的链接方式稍作改变,即可使得表处理更加方便灵活. 看一 ...
- 数据结构之链表(LinkedList)(二)
数据结构之链表(LinkedList)(一) 双链表 上一篇讲述了单链表是通过next 指向下一个节点,那么双链表就是指不止可以顺序指向下一个节点,还可以通过prior域逆序指向上一个节点 示意图: ...
随机推荐
- FTP使用心得
1、创建文件夹的函数,一次只能创建一层。 2、没有现成的判断文件夹是否存在的函数,如果文件夹不存在就创建,会报异常。有以下封装好的函数。可以直接调用。 1 2 3 4 5 6 7 8 9 10 11 ...
- WIN10把照片查看器设为默认看图软件
WIN10默认是PHOTO,没有以前WIN7的照片查看器好用,要改回来的方法如下: 在注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Photo ...
- mysql:用户管理、索引、视图、函数、存储过程
#创建一个用户并设置密码,注意IP地址要是登录mysql电脑的IP地址 USE mysql CREATE USER lisi@'192.168.149.1' IDENTIFIED BY "1 ...
- 使用 JsonPath 完成接口自动化测试中参数关联和数据验证(Python语言)
背景: 接口自动化测试实现简单.成本较低.收益较高,越来越受到企业重视 restful风格的api设计大行其道 json成为主流的轻量级数据交换格式 痛点: 接口关联 也称为关联参数.在应用业务接口中 ...
- corosync.conf
##totem定义集群内各节点间是如何通信的,totem本是一种协议,专用于corosync专用于各节点间的协议,协议是有版本的 totem { ##版本号 version: ##安全认证on|off ...
- 聊聊、Mybatis API
API Mybatis 到底解决了什么问题,持久化框架是什么,没出现 Mybatis 之前我们又是怎么来操作数据库的呢?对于 Java语言 来说,JDBC标准 是比较底层的了,但并非最底层的,可以说 ...
- docker 踩坑笔记之 psql: could not connect to server
最近在用docker跑rails,也遇到了一些坑,这里记录一下. 首先build项目: docker-compose build 然后就开始报错了: psql: could not connect t ...
- InnoDB 存储引擎的线程与内存池
InnoDB 存储引擎的线程与内存池 InnoDB体系结构如下: 后台线程: 1.后台线程的主要作用是负责刷新内存池中的数据,保证缓冲池中的内存缓存的是最近的数据: 2.另外,将以修改的数据文件刷 ...
- [bzoj4372] 烁烁的游戏 [动态点分治+线段树+容斥原理]
题面 传送门 思路 观察一下题目,要求的是修改"距离点$u$的距离一定的点权值",那这个就不能用传统的dfs序类算法+线段树维护,因为涉及到向父亲回溯的问题 看到和树上距离相关的东 ...
- 使用python读取mysql数据库并进行数据的操作
(一)环境的配置 使用python调用mysql数据库要引进一些库. 目前我使用的python版本是python3.6.引进库为pymysql 其他对应的库可以有以下选择: mysqldb,oursq ...