单链表只有一个方向的链接,即使增加了尾结点的引用,也只能支持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()