单链表只有一个方向的链接,即使增加了尾结点的引用,也只能支持O(1)时间的表头、表尾插入和O(1)时间的表头删除。
如果希望两端插入和删除都变得高效,需要增加另一方向的链接,这就得到了双向链接表,简称双链表。
这样做也会付出代价,每个结点都需要增加一个链接域,增加的空间开销与结点数成正比,是O(n)。但是,如果每个表结点里的数据规模比较大,新增加的开销可能就显得不太重要了。
从双链表的任一结点出发,可以直接找到其前后的相邻结点,都是O(1)操作。而对于单链表而言,只能方便地找到下一结点,如果要找前一结点,则必须从表头开始再向后依次遍历。
class Node:
def __init__(self, elem, prev=None, pnext=None):
self.elem = elem
self.prev = prev
self.pnext = pnext
def __repr__(self): #这个函数将内容‘友好’地显示出来,否则会显示对象的内存地址
return str(self.elem)
class DLList:
def __init__(self):
self.head = None
self.rear = None
def is_empty(self):
"""
判断该链表是否为空
:return: boolean
"""
return self.head == None
def prepend(self, elem): #前端插入
"""
前端插入时,需要改变两处引用赋值
如果为空表:改变其头结点域和尾结点域
如果不是空表:改变其下一结点的前驱结点域和尾结点域
"""
p = Node(elem,None, self.head)
if self.is_empty():
self.rear = p
else:
p.pnext.prev = p
self.head = p
def append(self,elem): #尾端插入
"""
尾端插入时,也需要改变两处引用赋值
如果为空表:改变其头结点域和尾结点域
如果不是空表:改变其前一结点的后继结点域和尾结点域
"""
p = Node(elem, self.rear, None)
if self.is_empty():
self.head = p
else:
p.prev.pnext = p
self.rear = p
def pop_start(self): #前端弹出
"""
前端弹出时,需要改变两处引用赋值
如果为空表:仅改变其头结点
如果不是空表:需要将头结点指向下一结点和并其前驱结点域置为空
"""
if self.is_empty():
print("The list is None.")
return
val = self.head.elem
self.head = self.head.pnext
if not self.is_empty(): #head为空时不做任何事
self.head.prev = None
return val
def pop_last(self): #前端弹出
"""
前端弹出时,需要改变两处引用赋值
如果为空表:仅改变其头结点
如果不是空表:需要将头结点指向下一结点和并其前驱结点域置为空
"""
if self.is_empty():
print("The list is None.")
return
val = self.rear.elem
self.rear = self.rear.prev
if self.rear is None: #向前挪一位后的尾结点为空,说明之前只有一个元素
self.head = None #设置head保证is_empty能正常工作
else:
self.rear.pnext = None
return val
def printall(self):
if self.is_empty():
print("The list is None.")
return
p = self.head
print("Head-->", p.elem, end=' ')
while p.pnext:
p = p.pnext
print("-->",p.elem, end=' ')
print("--> None. Linked node finished")
if __name__ == '__main__':
node1 = Node(elem='node1')
node2 = Node(elem='node2')
DLlist = DLList()
DLlist.append(node1)
DLlist.append(node2)
DLlist.printall()
print(DLlist.pop_start())
DLlist.printall()
print(DLlist.pop_last())
DLlist.printall()