双向链表
一种更加复杂的链表,特征是每个节点有两个链接:一个指向前一个节点,一个指向后一个节点,处理时只需要管前一个节点的后(next),后一个结节点的前(prev)即可。
特殊情况,当节点为第一个节点时prev指向空值(None),当节点为最后一个节点时next指向空值(None)
1.头部插入更改的代码以及原理:
node.next = self.__head
self.__head = node
node.next.prev = node
2.指定位置插入
指定位置插入有两种方法:
3.删除
这里非常体现操作前一个节点的next,后一个节点的prev。
4.尾部插入(略)
测试代码
class Node(object):
"""节点"""
def __init__(self, item):
self.elem = item
self.next = None
self.prev = None # 多定义一个前驱
class DoubleLinkList(object):
"""双链表"""
def __init__(self, node=None): # 3: 如果用户不输入头节点值 当成默认参数 None 直接创建空列表 None 其实又回到了下面一行
# self.__head = None 1:一上来设置为空 意思是不指向任何节点 | 私有加 __ 意义:只有这个函数内部使用
self.__head = node # 2:在上一行的基础上人性化,用户如果先构造节点,就将头指向这个头节点 node
def is_empty(self):
"""链表是否为空"""
return self.__head is None # class在变量和None进行比较时,应该使用 is。
# 可以把比较的值直接作为返回值 如果相等即为真就是1 即返回1
# 只要头节点指的是空那么就是空链表
def length(self):
"""链表长度"""
cur = self.__head # 让它等于指向表头指向的第一个节点,cur 用于移动遍历元素
# count 记录数量
count = 0
while cur is not None: # count 从0开始的好处就是能够记录空表的长度,一个代码实现空表与一般表的长度计算
count += 1
cur = cur.next # cur指向了 下一个节点
return count
def travel(self):
"""遍历整个链表"""
cur = self.__head
while cur is not None:
print(cur.elem, end=" ") # 打印每一个元素 空格隔开
cur = cur.next
print("") # 换行
def add(self, item):
"""链表头部添加元素,头插法"""
node = Node(item) # 把item这个数据封装成链表所需要的节点形式
node.next = self.__head
self.__head = node # 当一开始是空的时候 头和节点都指向None 所以跑一遍上述两行还是满足的
node.next.prev = node # node 节点的n指向的p指向node本身
def append(self, item):
"""链表尾部添加元素,尾插法"""
node = Node(item)
if self.is_empty(): # 如果链表是空的 头直接指向插入的节点
self.__head = node
else:
cur = self.__head
while cur.next is not None:
cur = cur.next
cur.next = node
node.prev = cur
def insert(self, pos, item):
"""指定位置添加元素
:param item: 元素
:param pos从0开始
"""
if pos <= 0: # 如果输入位置是<=0的默认是在头部插入
ll.add(item)
elif pos > self.length() - 1:
self.append(item)
else:
cur = self.__head
count = 0
while count < pos: # 不需要两个游标只需要一个了
count += 1
cur = cur.next
# 当循环退出后 cur指向pos位置
node = Node(item)
node.next = cur # 这四句话是完成指定位置插入的操作过程
node.prev = cur.prev
cur.prev.next = node
cur.prev = node
def remove(self, item):
"""删除节点,找到和你想删除的数一样的数"""
cur = self.__head
while cur is not None:
if cur.elem == item:
# 先判断此节点是否是头节点 如果是头节点
if cur == self.__head:
self.__head = cur.next
if cur.next: # 判断链表是否只有一个元素
cur.next.prev = None
else:
cur.prev.next = cur.next
if cur.next:
cur.next.prev = cur.prev
break
else: # 移动
cur = cur.next
def search(self, item):
"""链表查找节点是否存在,并返回True或者False"""
cur = self.__head
while cur is not None:
if cur.elem == item:
return True
else:
cur = cur.next
return False
# 测试代码
if __name__ == "__main__":
ll = DoubleLinkList()
print(ll.is_empty())
print(ll.length())
ll.append(1)
print(ll.is_empty())
print(ll.length())
ll.append(2)
ll.add(8)
ll.append(3)
ll.append(4)
ll.append(5)
ll.append(6)
ll.insert(-1, 9)
ll.travel()
ll.insert(2, 100)
ll.travel()
ll.insert(10, 200)
ll.travel()
ll.remove(200)
ll.travel()
ll.insert(20, 200)
ll.travel()
ll.insert(21, 200)
ll.travel()
ll.remove(200)
ll.travel()