数据结构与算法 | 链表-4:双向链表的实现

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  

参考

猜你喜欢

转载自blog.csdn.net/qq_27782503/article/details/94480641