1 前言
关于链表的系列,目前已经整理完成了:
现在还剩下双向链表的问题,双向链表的结构如下:
那如何实现它呢?
2 Python实现
2.1 先定义节点
class Node(object):
'''结点'''
def __init__(self, elem):
self.elem = elem
self.next = None
self.prev = None # 新增加的
2.2 定义双链表
class DoubleLinkList(object):
def __init__(self, node=None): # 设置一个默认参数
self.__head = node # 双下划线表示私有属性 不让别人看到 仅自己用
def is_empty(self):
'''is_empty() 链表是否为空'''
return self.__head == None
def length(self):
'''length() 链表长度
双链表和单链表在求长度的时候没有差别
'''
# 另外下面对于空链表的特殊情况符合,返回0
# 先定义辅助的cur cur游标,用来移动遍历节点
cur = self.__head
# count用来计数
count = 0
while cur != None: # 区别于cur.next
count += 1
cur = cur.next
return count
pass
def travel(self):
'''travel() 遍历整个链表
双链表和单链表遍历效果一致!
'''
cur = self.__head # 进入了第一个结点
while cur != None:
# 保证每一个结点的元素都打印出来即可
print(cur.elem, end = ' ') # 打印元素值
cur = cur.next
print(' ')
def add(self, item):
'''链表头部添加元素,头插法
时间复杂度:O(1)
需要改变!区别于单链表!
'''
node = Node(item)
if self.is_empty():
# 如果是空链表,将_head指向node
self._head = node
else:
# 将node的next指向_head的头节点
node.next = self.__head
# 将_head的头节点的prev指向node
self.__head.prev = node
# 将_head 指向node
self.__head = node
def append(self, item):
'''链表尾部添加元素,尾插法
时间复杂度:O(n) 循环找到尾部
'''
# 先定义一个节点 然后循环到最后一个
node = Node(item)
if self.is_empty():
# 如果为空 直接头结点指向该插入的元素
self.__head = node
else:
# 非空引入一个游标cur
cur = self.__head
while cur.next != None: # 区别于上面,因为要在最后一个节点指向新的!
# 这里无法直接兼容空链表 因为空链表没有.next
cur = cur.next
# 前面一致 只需加入新加入的指向上一个cur
cur.next = node
node.prev = cur # 新加入的
def insert(self, pos, item):
'''指定位置添加元素
参数pos:表示下标,从0开始索引
区别于之前的cur 用pre 其实意思一致
时间复杂度:O(n) 尾部插入 循环 也是n
'''
if pos <= 0:
# 认为是头插法
self.add(item)
elif pos > (self.length()-1):
# 认为是尾插法
self.append(item)
else:
cur = self.__head
count = 0
while count < pos:
count += 1
cur = cur.next
# 当循环退出后,pre指向pos位置
node = Node(item)
node.next = cur
node.prev = cur.prev
cur.prev.next = node
cur.prev = node
def remove(self, item):
'''删除节点
下面是单链表思路:
引入两个游标 比较好理解
先cur指向首节点,pre指向None
然后让pre指向cur cur再移动
双向链表:
只要一个指针即可!
'''
# 初始化
cur = self.__head
while cur != None:
if cur.elem == item:
# 先判断此节点是否是头节点
if cur == self.__head:
self.__head = cur.next
if cur.next:
# 判断练链表是否只有一个结点
cur.next.prev = None # 如果为一个 直接指向None 就没有prev了
else:
pass
else:
cur.prev.next = cur.next
if cur.next:
# 尾部判断 因为cur.next如果为空 则没有prev
cur.next.prev = cur.prev
break
else:
# 开始移动 两个游标之间差1个位置
cur = cur.next
# 空链表不执行任何操作!可以没问题
# 如果删除首节点 需要变化的是头结点指向下一个!
# 如果只有一个节点,咋办呢?没问题 指向None
# 上面是头部情况,尾部情况捏?没有问题,直接指向None
def search(self, item):
'''查找节点是否存在
时间复杂度:O(n) 循环!
和单链表一致!
'''
cur = self.__head # 用来遍历链表
while cur != None:
if cur.elem == item:
return True
else:
cur = cur.next
return False
# 能解决空链表的问题 如果为空 直接return false
2.3 实例
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) # 头插法ok
ll.travel()
ll.append(3)
ll.append(4)
ll.append(5)
ll.append(6)
ll.insert(-1,9) # 9 8 ....
ll.travel()
ll.insert(3,100) # 9 8 1 100
ll.travel()
ll.insert(10, 200)
ll.travel()
print(ll.search(100))
print(ll.search(200))
print(ll.search(100000))
ll.remove(100)
ll.travel()
ll.remove(200)
ll.travel()
True
0
False
1
8 1 2
9 8 1 2 3 4 5 6
9 8 1 100 2 3 4 5 6
9 8 1 100 2 3 4 5 6 200
True
True
False
9 8 1 2 3 4 5 6 200
9 8 1 2 3 4 5 6