Python代码实现双链表

Python代码实现双链表

1. 双链表概述

双链表(doubly linked list)是一种常见的链式数据结构,每个节点有两个指针,一个指向前一个节点,一个指向后一个节点。双链表相比于单链表,虽然存储空间更大,但是它可以更方便地获取前一个节点,所以它具有非常重要的应用价值,例如在LRU缓存算法中就用到了双链表。

2. 双链表的实现

双链表的实现可以考虑使用类的形式,每个节点作为类的一个实例,节点类中包括该元素的值(value)以及两个指针,分别指向前一个节点(prev)和后一个节点(next)。具体实现流程可以分为以下几步:

2.1 定义双链表节点类

我们可以使用Python的面向对象编程思想,定义一个双链表节点类,其中包含value、prev(前一个节点)、next(后一个节点)三个属性。代码如下所示:

class Node: 
    def __init__(self, value=None, prev=None, next=None): 
        self.value = value 
        self.prev = prev 
        self.next = next 

2.2 定义双链表类

双链表类需要包含头节点和尾节点两个属性,以及若干个双链表节点。首先定义构造方法,用于初始化头节点和尾节点:

class MyLinkedList: 
    def __init__(self): 
        self.head = Node() 
        self.tail = Node() 
        self.head.next = self.tail 
        self.tail.prev = self.head 

然后,定义其他的基本方法,包括获取链表长度、在链表指定位置插入节点、删除指定节点、获取指定位置节点等。

2.3 在链表指定位置插入节点

在双链表中,插入节点比较方便,我们只需要将插入节点的prev指向前面的节点,将插入节点的next指向后面的节点,再将前面的节点的next指向插入节点,后面的节点的prev指向插入节点即可。代码如下所示:

def addAtIndex(self, index: int, value) -> None:
    if index > self.get_length() or index < 0:
        return
    node = Node(value)
    curr = self.head
    for i in range(index): # 遍历index前的节点
        curr = curr.next
    node.prev = curr
    node.next = curr.next 
    curr.next.prev = node 
    curr.next = node 

2.4 删除指定节点

在双链表中删除节点也比较简单,我们只需要将待删除节点的前一个节点的next指向待删除节点的后一个节点,待删除节点的后一个节点的prev指向待删除节点的前一个节点即可。代码如下:

def deleteAtIndex(self, index: int) -> None:
    if index >= self.get_length() or index < 0:
        return
    curr = self.head 
    for i in range(index): # 遍历到index节点
        curr = curr.next
    curr.next.prev = curr.prev
    curr.prev.next = curr.next

2.5 获取指定位置节点

根据索引获取链表中的某个节点的方法同样非常简单,我们只需要遍历到目标节点位置即可。代码如下:

def get(self, index: int) -> int:
    if index >= self.get_length() or index < 0:
        return -1
    curr = self.head 
    for i in range(index+1):
        curr = curr.next
    return curr.value

3. 示例说明

下面给出两个使用示例,以便读者更好理解双链表的实现。

3.1 示例一

以下是一个在双链表中插入、删除、获取指定节点等操作的示例:

# 初始化双链表
linked_list = MyLinkedList()

# 在链表尾部添加节点
linked_list.addAtTail(1)
linked_list.addAtTail(2)
linked_list.addAtTail(3)
# 此时链表为 [1, 2, 3]

# 在链表指定位置插入节点
linked_list.addAtIndex(1, 4)
# 此时链表为 [1, 4, 2, 3]

# 删除链表指定位置节点
linked_list.deleteAtIndex(2)
# 此时链表为 [1, 4, 3]

# 获取链表指定位置节点
linked_list.get(1) # 返回4

3.2 示例二

以下是一个在LeetCode题目中使用双链表解决问题的示例。LeetCode第707题要求实现一个MyLinkedList类,支持添加(尾部)、添加(指定位置)、删除、获取等操作。代码如下:

class MyLinkedList:
    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.head = Node(0)
        self.tail = Node(0)
        self.head.next = self.tail
        self.tail.prev = self.head
        self.size = 0

    def get(self, index: int) -> int:
        """
        Get the value of the index-th node in the linked list. If the index is invalid, return -1.
        """
        if index < 0 or index >= self.size:
            return -1
        curr = self.head
        for i in range(index + 1):
            curr = curr.next
        return curr.value

    def addAtHead(self, val: int) -> None:
        """
        Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
        """
        node = Node(val, self.head, self.head.next)
        self.head.next.prev = node
        self.head.next = node
        self.size += 1

    def addAtTail(self, val: int) -> None:
        """
        Append a node of value val to the last element of the linked list.
        """
        node = Node(val, self.tail.prev, self.tail)
        self.tail.prev.next = node
        self.tail.prev = node
        self.size += 1

    def addAtIndex(self, index: int, val: int) -> None:
        """
        Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.
        """
        if index > self.size:
            return
        if index < 0:
            index = 0
        curr = self.head
        for i in range(index + 1):
            curr = curr.next
        node = Node(val, curr.prev, curr)
        curr.prev.next = node
        curr.prev = node
        self.size += 1

    def deleteAtIndex(self, index: int) -> None:
        """
        Delete the index-th node in the linked list, if the index is valid.
        """
        if index < 0 or index >= self.size:
            return
        curr = self.head
        for i in range(index + 1):
            curr = curr.next
        curr.prev.next = curr.next
        curr.next.prev = curr.prev
        self.size -= 1

在LeetCode上测试该代码,发现通过所有测试用例,说明了Python的双链表实现充分具备实际使用的能力。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python代码实现双链表 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • Windows优化大师怎么关闭右键快捷入口?Windows优化大师关闭右键快捷入口教程

    关于“Windows优化大师怎么关闭右键快捷入口? Windows优化大师关闭右键快捷入口教程”的完整攻略,包括以下几个步骤: 第一步:打开“Windows优化大师”软件 首先,在电脑上打开“Windows优化大师”软件。如果你没有安装该软件,可以前往官方网站下载并安装。 第二步:找到“右键菜单管理”并打开 在“Windows优化大师”软件的“常规优化”选项…

    other 2023年6月27日
    00
  • ocam怎么添加鼠标右键单击效果 ocam添加鼠标右键单击效果教程

    添加鼠标右键单击效果其实是给OCam添加录制区域选框功能。具体的实现过程需要进行以下几个步骤: 步骤一:下载并安装AutoHotkey AutoHotkey是一款Windows自动化脚本语言,可用于编写各种脚本来自动化各种操作。我们可以借助它来实现鼠标右键的单击效果。 下载AutoHotkey安装程序并完成安装。 步骤二:创建脚本文件 在桌面上新建一个空白文…

    other 2023年6月27日
    00
  • NBA2K16提示0xc000007b错误的解决方法

    NBA2K16提示0xc000007b错误的解决方法 问题描述 在运行NBA2K16时,可能会出现0xc000007b错误提示,这是系统中缺少重要组件或配置不当导致的典型错误。该错误提示信息通常如下:The application was unable to start correctly (0xc000007b) 解决方法 下面介绍一些修复错误的方法,你可…

    other 2023年6月27日
    00
  • Android 实现当下最流行的吸顶效果

    为了实现 Android 中的吸顶效果,我们可以采用以下步骤: 1.创建列表布局并添加一个头部布局在创建列表布局时,需要添加一个头部布局并设置与列表布局同样的宽度和高度,同时需要设置头部布局的位置,默认为隐藏。 示例1: <RelativeLayout android:layout_width="match_parent" andr…

    other 2023年6月27日
    00
  • java通过AOP实现全局日志打印详解

    Java通过AOP实现全局日志打印详解 1. 简介 AOP(面向切面编程)是一种编程范式,可以通过在运行时动态地将代码片段(称为“切面”)插入到程序的特定位置,从而实现一些横切关注点的统一处理。全局日志打印是一个常见的横切关注点,可以通过AOP来实现。 2. 准备工作 在使用AOP实现全局日志打印之前,需要先引入相关的依赖库。这里以使用Spring框架为例,…

    other 2023年6月28日
    00
  • 浅谈JavaScript的函数及作用域

    浅谈JavaScript的函数及作用域 函数的定义和使用 JavaScript中的函数是一段可重复使用的代码块,用于执行特定的任务。函数可以接受参数,并且可以返回一个值。 函数的定义使用关键字function,后面跟着函数名和一对圆括号,圆括号中可以包含参数列表。函数体由一对花括号包围,其中包含了函数要执行的代码。 下面是一个简单的示例,展示了如何定义和使用…

    other 2023年8月19日
    00
  • Java基础入门语法–String类

    Java基础入门语法–String类攻略 1. String类简介 在Java中,字符串是以String类的形式存在的。String类可以作为一个不可变的字符序列,即一旦创建了一个String对象,它的值就不能被改变了。String类提供了很多操作字符串的方法,例如检索、替换、拼接字符串等。 2. String类的创建 可以通过以下两种方式来创建Strin…

    other 2023年6月20日
    00
  • 浅谈SpringBoot如何封装统一响应体

    第一步:创建一个统一响应体类 要封装统一响应体,我们需要先创建一个响应体类,用于封装统一的返回内容。使用Java Bean形式的类会比较方便,因为我们可以通过类的对象访问响应内容的各个部分,如状态码,返回信息,响应数据等。 下面是一个示例响应体类: public class ResponseBody { private int code; // 状态码 pr…

    other 2023年6月25日
    00
合作推广
合作推广
分享本页
返回顶部