python实现双向链表原理

Python实现双向链表原理

双向链表是一种非常经典的数据结构,它的每一个节点都有两个指针,一个指向前驱节点,一个指向后继节点。相对于单向链表,双向链表能够快速地在任意位置插入或删除元素,因此被广泛地应用于实际场景中。

Python语言提供了很多数据结构类型,包括列表、字典、集合等等。但是在某些情况下,双向链表也能够更好地满足我们的需求。本篇文章将详细介绍Python实现双向链表的原理及代码实现。

双向链表的结构

首先,我们需要定义一个双向链表的节点类。它需要包含三个属性:valueprevnext。其中,value表示节点存储的值,prev表示前驱节点,next表示后继节点。代码如下所示:

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

然后,我们需要定义一个双向链表类。它需要包含两个属性:headtail。其中,head表示双向链表的头节点,tail表示双向链表的尾节点。代码如下所示:

class DoublyLinkedList:
    def __init__(self):
        self.head = None
        self.tail = None

在双向链表中,每一个节点都有一个前驱节点和一个后继节点。因此,我们需要实现向双向链表中添加节点的方法 add_node,它需要按照正确的顺序往链表中插入节点。我们可以定义三种情况:

  1. 链表为空,直接将节点插入到头部即可;
  2. 链表非空,节点需要插入到头部;
  3. 链表非空,节点需要插入到中间或者尾部。

代码如下所示:

class DoublyLinkedList:
    def __init__(self):
        self.head = None
        self.tail = None

    # 向链表中添加节点
    def add_node(self, value):
        # 创建新节点
        new_node = Node(value)

        # 链表为空,直接将节点插入到头部
        if self.head is None:
            self.head = new_node
            self.tail = new_node

        # 链表非空,节点需要插入到头部
        else:
            new_node.next = self.head
            self.head.prev = new_node
            self.head = new_node

在双向链表中,每一个节点都有一个前驱节点和一个后继节点。因此,我们需要实现从双向链表中删除节点的方法 remove_node,它需要按照正确的顺序将节点从链表中删除。我们可以定义三种情况:

  1. 链表为空,无需进行任何操作;
  2. 链表仅有一个元素,直接将头部和尾部节点清空即可;
  3. 链表非空,需要删除中间或者尾部的节点。

代码如下所示:

class DoublyLinkedList:
    def __init__(self):
        self.head = None
        self.tail = None

    # 向链表中添加节点
    def add_node(self, value):
        # 创建新节点
        new_node = Node(value)

        # 链表为空,直接将节点插入到头部
        if self.head is None:
            self.head = new_node
            self.tail = new_node

        # 链表非空,节点需要插入到头部
        else:
            new_node.next = self.head
            self.head.prev = new_node
            self.head = new_node

    # 从链表中删除节点
    def remove_node(self, value):
        # 链表为空,无需进行任何操作
        if self.head is None:
            return

        # 链表仅有一个元素,直接将头部和尾部节点清空即可
        elif self.head == self.tail and self.head.value == value:
            self.head = None
            self.tail = None

        # 链表非空,需要删除中间或者尾部的节点
        else:
            curr_node = self.head
            while curr_node:
                # 找到匹配的节点,删除它
                if curr_node.value == value:
                    # 中间节点
                    if curr_node.prev and curr_node.next:
                        curr_node.prev.next = curr_node.next
                        curr_node.next.prev = curr_node.prev

                    # 尾部节点
                    elif curr_node == self.tail:
                        self.tail = curr_node.prev
                        curr_node.prev.next = None

                    # 头部节点
                    else:
                        self.head = curr_node.next
                        curr_node.next.prev = None

                    del curr_node
                    break

                curr_node = curr_node.next

示例说明

示例 1:添加节点

以下是通过双向链表添加 1、2、3 三个节点后的链表结构:

doubly_linked_list = DoublyLinkedList()
doubly_linked_list.add_node(3)
doubly_linked_list.add_node(2)
doubly_linked_list.add_node(1)

print(doubly_linked_list.head.value)  # 1
print(doubly_linked_list.head.next.value)  # 2
print(doubly_linked_list.head.next.next.value)  # 3

print(doubly_linked_list.tail.value)  # 3
print(doubly_linked_list.tail.prev.value)  # 2
print(doubly_linked_list.tail.prev.prev.value)  # 1

示例 2:删除节点

以下是通过双向链表删除 2 节点后的链表结构:

doubly_linked_list = DoublyLinkedList()
doubly_linked_list.add_node(3)
doubly_linked_list.add_node(2)
doubly_linked_list.add_node(1)

doubly_linked_list.remove_node(2)

print(doubly_linked_list.head.value)  # 1
print(doubly_linked_list.head.next.value)  # 3
print(doubly_linked_list.tail.value)  # 3
print(doubly_linked_list.tail.prev.value)  # 1

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

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

相关文章

  • python入门for循环嵌套理解学习

    Python入门:for循环嵌套理解学习攻略 1. 什么是for循环嵌套? 在Python中,for循环嵌套是指在一个for循环内部再嵌套另一个for循环。通过嵌套多个for循环,可以实现对多维数据结构(如列表的列表)的遍历和操作。 2. for循环嵌套的语法 for循环嵌套的语法如下所示: for 变量1 in 序列1: for 变量2 in 序列2: #…

    other 2023年7月27日
    00
  • 完美的loading的实现方法

    以下是我对于完美的loading实现方法的完整攻略: 1、使用CSS实现loading 使用CSS实现loading是最简单的方法之一,可以使用CSS3的animation属性实现loading的动画效果,可以通过一些技巧实现loading的居中,在这里我给出一个实现loading的示例代码: <div class="loading&quot…

    other 2023年6月25日
    00
  • Java类加载的过程详解

    Java类加载的过程是指在Java应用程序运行时,JVM将类的.class文件加载到内存中,并对类进行解析,链接和初始化的过程。下面我们就来详细讲解一下Java类加载的过程。 Java类加载的过程 Java类加载的主要过程分为三个阶段:加载、链接和初始化。 加载 类加载是指在JVM内存中创建一个Class对象,用来表示加载的类。类加载的过程大致可以分为以下几…

    other 2023年6月25日
    00
  • java实现图的邻接表存储结构的两种方式及实例应用详解

    下面就给您详细讲解“java实现图的邻接表存储结构的两种方式及实例应用详解”的完整攻略。 一、什么是图的邻接表存储结构? 图是一种重要的数据结构,主要由顶点和边组成。邻接表存储结构是一种常见的存储图的方式,它采用链表来表示图中的每个顶点及其相邻的顶点。其中,每个顶点对应一个单链表,存储该顶点与其他顶点相邻的边。 邻接表存储结构通常使用数组加链表的方式实现。数…

    other 2023年6月28日
    00
  • c与c++之间的相互调用及函数区别示例详解

    相关基础知识 在介绍 C 和 C++ 之间相互调用的过程之前,需要梳理一下 C 和 C++ 函数的区别。 C 函数和 C++ 函数的定义和调用有以下区别: 函数重载 C++ 支持函数重载,即同名函数的参数个数和类型不同,可以被认为是不同的函数。例如: // C++ 中使用函数重载 int sum(int a, int b) { return a + b; }…

    other 2023年6月26日
    00
  • 使用PHP批量生成随机用户名

    下面是使用PHP批量生成随机用户名的完整攻略。 步骤一:生成随机的用户名 我们可以通过PHP内置函数来生成随机的用户名,比如使用uniqid()函数,该函数可以返回一个前缀为当前时间的唯一ID字符串。我们可以将这个ID字符串截取前6位作为我们的随机用户名,代码如下: $username = substr(uniqid(), 0, 6); 步骤二:存储用户名 …

    other 2023年6月27日
    00
  • 使用快捷键F2快速更改文件名

    下面是详细的“使用快捷键F2快速更改文件名”的攻略: 1. 开始更改文件名 在文件资源管理器中选择要更改的文件,然后按下F2键,光标将会进入文件名编辑模式。 2. 编辑文件名 在编辑模式下,可以对文件名进行任何修改。包括添加/删除字符和更改拼写错误。您还可以使用鼠标将光标移动到您想要编辑的位置,并按下Ctrl + Shift + End组合键选择文件名中的所…

    other 2023年6月26日
    00
  • Java源码解析之GenericDeclaration详解

    Java源码解析之GenericDeclaration详解攻略 什么是GenericDeclaration GenericDeclaration是Java泛型机制中的一个接口,表示定义泛型类型、方法或类型变量的通用声明。因此,GenericDeclaration可以是类、方法或类型变量。泛型机制需要这些通用声明来支持泛型类型或方法的调用。 GenericDe…

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