什么是双向链表,一篇搞懂双向链表

双向链表

还不清楚单向链表的同学可以去看我另一篇文章,实践总结:一篇搞懂链表——单链表和双指针技巧

首先,我们先看下双向链表(下文用双链表表述)的图示,见下图:
双向链表
与单链表不同的是,双链表有两个方向,对应单链表节点中的一个引用字段next,双链表每个节点中都含有两个引用字段,我们用prev和next表示。

也就是在双链表中的每个节点,包含一个数值val,还包括两个引用字段,一个是prev 指向前一个节点,next 指向后一个节点。

添加操作 - 双链表

如果我们想在现有的结点 prev 之后插入一个新的结点 cur,我们可以将此过程分为两个步骤:

  1. 链接 cur 与 prev 和 next,其中 next 是 prev 原始的下一个节点;
    在这里插入图片描述
  2. prev 和 next再次指向cur
    在这里插入图片描述
    这两步在代码上的实现,可以简化为:
new_node.next = curr.next
new_node.prev = curr
curr.next.prev = new_node
curr.next = new_node

删除操作 - 双链表

如果我们想从双链表中删除一个现有的结点 cur,我们可以简单地将它的前一个结点 prev 与下一个结点 next 链接起来。
举个例子:
在这里插入图片描述

设计一个双链表

要求:
实现一个向链表。

实现 MyLinkedList 类:

  1. MyLinkedList() 初始化 MyLinkedList 对象。
  2. int get(int index) 获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1 。
  3. void addAtHead(int val) 将一个值为 val的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。
  4. void addAtTail(int val) 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
  5. void addAtIndex(int index, int val) 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。如果 index 比长度更大,该节点将 不会插入 到链表中。
  6. void deleteAtIndex(int index) 如果下标有效,则删除链表中下标为 index 的节点。

代码实现:

class ListNode:
    def __init__(self, val=0):
        self.val = val
        # 标记向后的变量
        self.next = None
        # 标记向前的变量
        self.prev = None


class MyLinkedList:
    def __init__(self):
        # 初始化头节点
        self.head = None
        # 初始化尾节点
        self.tail = None
        self.size = 0

    # 获取链表中下标为 index 的节点的值
    def get(self, index: int) -> int:
        # 在index有效的范围内,遍历得到curr即可
        if 0 <= index < self.size:
            curr = self.head
            for _ in range(index):
                curr = curr.next
            return curr.val
        else:
            return -1

    #将一个值为 val 的节点插入到链表中第一个元素之前
    def addAtHead(self, val: int) -> None:
        self.addAtIndex(0, val)

    # 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
    def addAtTail(self, val: int) -> None:
        self.addAtIndex(self.size, val)

    # 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。
    def addAtIndex(self, index: int, val: int) -> None:
        if index < 0 or index > self.size:
            return None
        new_node = ListNode(val)
        # 插入头节点
        if index == 0:
            new_node.next = self.head
            if self.head:
                self.head.prev = new_node
            else:
                self.tail=new_node
            self.head = new_node
            self.size += 1
            return
        if index == self.size:
            new_node.prev = self.tail
            if self.tail:
                self.tail.next = new_node
            else:
                self.head=new_node
            self.tail = new_node
            self.size += 1
            return
        if 0 < index < self.size:
            curr = self.head
            # 从头节点遍历链表到index的前一位
            for _ in range(index - 1):
                curr = curr.next
            new_node.next = curr.next
            new_node.prev = curr
            curr.next.prev = new_node
            curr.next = new_node
            self.size += 1
            return
        return

    # 删除链表中下标为 index 的节点。
    def deleteAtIndex(self, index: int) -> None:
        # 如果删除的是头节点
        if index == 0:
            # 当链表长度等于1时
            if self.size == 1:
            	# 删除之后链表就为空了
                self.head = None
                self.tail = None
                self.size -= 1
            else:
                self.head = self.head.next
                self.head.prev = None
                self.size -= 1
             # 删除尾节点
        elif index == self.size - 1:
            self.tail = self.tail.prev
            self.tail.next = None
            self.size -= 1
        elif 0 < index < self.size - 1:
            curr = self.head
            # 遍历到当前节点
            for _ in range(index):
                curr = curr.next
            # 当前节点的前一个节点指向当前节点下一个节点
            curr.prev.next = curr.next
            # 当前节点后一个节点的前一个节点,是当前节点的前一个节点
            curr.next.prev = curr.prev
            self.size-=1
        return None

第二种实现:

class ListNode:
    def __init__(self, val=0):
       self.val=val
       # 标记向前的变量
       self.prev = None
       # 标记向后的变量
       self.next = None


class MyLinkedList:
    def __init__(self):
        # 初始化头节点
        self.head = None
        # 初始化尾节点
        self.tail = None
        # 初始化链表长度
        self.size = 0

    # 获取链表中下标为 index 的节点的值
    def get(self, index: int) -> int:
        curr=self.head
        if 0<=index<self.size:
            for _ in range(index):
                curr=curr.next
            return curr.val
        else:
            return -1

    #将一个值为 val 的节点插入到链表中第一个元素之前
    def addAtHead(self, val: int) -> None:
        self.addAtIndex(0, val)

    # 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
    def addAtTail(self, val: int) -> None:
        self.addAtIndex(self.size, val)

    # 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。
    def addAtIndex(self, index: int, val: int) -> None:
        new_node =ListNode(val)
        curr=self.head
        if index==0:
            new_node.next=curr
            if curr:
                curr.prev=new_node
            else:
                self.tail=new_node
            self.head = new_node
            self.size+=1
            return
        if 0<index<=self.size:
            for _ in range(index-1):
                curr=curr.next
            if curr.next:
                curr.next.prev=new_node
            else:
                self.tail=new_node
            new_node.next=curr.next
            curr.next=new_node
            new_node.prev=curr

            self.size+=1
            return


    # 删除链表中下标为 index 的节点。
    def deleteAtIndex(self, index: int) -> None:
        curr=self.head
        if index==0:
            if self.size==1:
                self.head=None
                self.tail=None
            elif self.size>1:
                self.head=curr.next
                curr.next.prev=None
            self.size-=1
            return 
        if 0<index<self.size:
            for _ in range(index-1):
                curr=curr.next
            if curr.next.next:
                curr.next.next.prev=curr
            else:
                self.tail=curr
            curr.next=curr.next.next
            self.size-=1
            return
        return
  • 29
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值