概念
每个节点有两个链接:一个指向前一个节点,当此节点为第一个节点时,指向空值;而另一个指向下一个节点,当此节点为最后一个节点时,指向空值。
特点:
节点包含三个域,一个元素域,两个链接域(前驱和后继),第0个节点没有前驱,最后一个节点没有后继,在单链表的基础上,增加向前指向的考虑。
结构
python代码实现
class Node(object):
"""实现双向链表节点"""
def __init__(self, item):
# item存放数据元素
self.item = item
# next代表后一个节点
self.next = None
# prev代表前一个节点
self.prev = None
class DoubleLinkList(object):
"""双向链表"""
def __init__(self):
# 表示首节点
self.head = None
# 链表是否为空
def is_empty(self):
return self.head is None
# 链表长度
def length(self):
# cur初始时指向头节点
cur = self.head
n = 0
# 当未到达尾节点None时
while cur is not None:
n += 1
# 将cur后移一个节点
cur =cur.next
return n
# 遍历整个链表
def travel(self):
cur = self.head
while cur is not None:
print(cur.item, end='-')
cur = cur.next
# 输出链表
print()
# 链表头部添加元素
def add(self, item):
# 调用Node类,实例node对象
node = Node(item)
# 先让新增加的节点next指向原首节点
node.next = self.head
# 然后让head指向新节点
self.head = node
# 原首节点存在时,原首节点向前指向新节点,实现双向
if node.next is not None:
node.next.prev = node
# 链表尾部添加元素
def append(self, item):
# 若链表为空,则直接在头部添加
if self.is_empty():
self.add(item)
return
# 1、链表不为空,需要遍历查找尾节点
cur = self.head
while cur.next is not None:
cur = cur.next
# 至此cur指向当前链表的尾节点
# 2、让cur的next指向新节点
node = Node(item)
cur.next = node
# 3、新节点向前指向cur
node.prev = cur
# 指定位置添加元素
def insert(self, pos, item):
# 需要对添加的位置进行分类讨论
# 如果添加位置<=0,则直接在头部添加
if pos <= 0:
self.add(item)
# 位置大于链表长度,则直接添加到尾部
elif pos >= self.length():
self.append(item)
else:
# 1 遍历查找待插入位置的前一个节点cur
cur = self.head
for i in range(pos-1):
cur = cur.next
# 至此,cur指向的就是待插入位置的前一个节点
# 2 新节点的next指向cur的next
node = Node(item)
node.next = cur.next
# 3 cur的next指向新节点
cur.next = node
# 4 新节点的后继节点向前指向新节点(双向,向前)
node.next.prev = node
# 5 新节点向前指向cur(双向,向前)
node.prev = cur
# 删除节点
def remove(self, item):
# 思路:让待删节点的pre(前节点)next指向待删节点的next
cur = self.head
# 1 找到待删节点并记录前一个节点
while cur is not None:
# 待删节点不存在也就不用删了,若存在
if cur.item == item:
# 2 若cur有前驱节点则:cur的前驱节点指向cur的后继节点,越过待删节点
if cur.prev is not None:
cur.prev.next = cur.next
# 否则(待删节点是第0个节点),head指向待删节点的next
else:
self.head = cur.next
# 3 若cur有后继节点,则cur的后继节点向前指向cur的前驱节点(越过待删节点)
if cur.next is not None:
cur.next.prev = cur.prev
return
cur = cur.next
# 查找某个节点是否存在
def search(self, item):
cur = self.head
while cur is not None:
if cur.item == item:
return True
cur = cur.next
# 没有找到
return False
# 测试代码
if __name__ == '__main__':
dl = DoubleLinkList()
dl.add(1)
dl.add(2)
dl.add(3)
dl.travel()
# 结果3-2-1-
dl.append("abc")
dl.append("def")
dl.append("ghi")
dl.travel()
# 结果3-2-1-abc-def-ghi-
dl.insert(-1, "xx")
dl.insert(99, "yy")
dl.insert(3, "zz")
dl.travel()
# 结果xx-3-2-zz-1-abc-def-ghi-yy-
dl.remove("xx")
dl.remove("yy")
dl.remove(1)
dl.remove(90)
dl.travel()
# 结果3-2-zz-abc-def-ghi-
print(dl.search(3))
# 结果True
print(dl.search("zz"))
# 结果True
print(dl.search(380))
# 结果False
复杂度
头部添加O(1),尾部添加O(n),指定位置添加O(n),
删除节点:
若cur有前驱节点则:cur的前驱节点指向cur的后继节点 O(n),否则:head指向cur的后继节点 O(1)