学习笔记-双链表(Python实现)

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


猜你喜欢

转载自blog.csdn.net/qq_34840129/article/details/80601053
今日推荐