python实现双向链表原理

yizhihongxing

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日

相关文章

  • Spring容器初始化及问题解决方案

    Spring容器是Spring框架中的核心组件,负责管理应用中的bean对象的声明周期及其依赖关系。Spring容器初始化过程中有很多细节需要注意,同时也会出现一些常见的问题,这篇文章将详细介绍Spring容器的初始化流程以及常见问题的解决方案。 Spring容器的初始化流程 Spring容器初始化的过程分为以下几个主要步骤: 加载配置文件:Spring容器…

    other 2023年6月20日
    00
  • C++:构造函数,析构函数详解

    C++:构造函数,析构函数详解 什么是构造函数? 构造函数是在实例化对象时自动调用的一种函数,用于初始化对象的数据成员和其他相关资源。在C++中,构造函数的名称必须与类的名称相同。 C++支持默认构造函数和带参数的构造函数。默认构造函数是没有参数的构造函数,它可以在对象创建时被调用,用于初始化默认值。带参数的构造函数允许像函数一样传递参数列表,用于根据传递的…

    other 2023年6月26日
    00
  • 用QQ截图截取鼠标右键菜单并防止菜单消失的方法

    使用QQ截图工具截取鼠标右键菜单是一项非常有用的技能,但是由于右键菜单通常只在鼠标按下时出现,在使用QQ截图时经常会出现菜单突然消失的问题。在这里,我们提供两种解决此问题的方法。 方法一:使用Windows系统自带的步骤记录器 在开始菜单中搜索并打开“步骤记录器”。 点击“开始记录”按钮,将步骤记录器设为录制模式。 按下鼠标右键,在菜单中选择QQ截图工具。 …

    other 2023年6月27日
    00
  • Linux里LVM磁盘扩容详细步骤

    下面是关于“Linux里LVM磁盘扩容详细步骤”的完整攻略。 准备工作 在进入具体操作之前,需要先进行一些准备工作。 查看LVM分区信息 首先需要确定LVM和分区的信息,使用如下命令来查看: sudo pvs sudo vgs sudo lvdisplay 其中,pvs用于显示物理卷信息,vgs用于显示卷组信息,lvdisplay用于显示逻辑卷信息。 扩容磁…

    other 2023年6月28日
    00
  • 浅谈Android系统的基本体系结构与内存管理优化

    浅谈Android系统的基本体系结构与内存管理优化 1. Android系统的基本体系结构 Android系统是一个基于Linux内核的开源操作系统,它的基本体系结构可以分为四个主要层次:应用层、应用框架层、系统运行库层和Linux内核层。 应用层:应用层是用户直接与Android系统交互的层次,包括各种应用程序,如浏览器、短信、电话等。应用层通过应用框架层…

    other 2023年8月1日
    00
  • tree获取点击节点的父节点

    获取tree中点击节点的父节点,可以使用tree的onSelect事件和getParentNode方法来实现。以下是详细的攻略: 在tree中添加onSelect事件 首先,在tree中添加onSelect事件。可以在tree的属性中添加onSelect属性,并将其设置为一个函数。例如: typescript <Tree onSelect={handl…

    other 2023年5月7日
    00
  • 魔兽世界6.1武僧坦天赋雕文技能属性优先级 wow6.1武僧坦攻略

    魔兽世界6.1武僧坦攻略 本攻略主要讲解魔兽世界6.1版本中武僧坦克职业的天赋、雕文、技能、属性等方面的优先级及操作技巧。具体内容如下: 选择天赋 武僧坦克在选择天赋时,需根据作战需求和个人操作习惯进行选择。下面列举几种常见的天赋选择方案: 坦克输出型天赋选择 冲天炮:可以提升坦克的输出,尤其是在团队副本中,能为团队造成更多的输出贡献,是能力很强的天赋。 猴…

    other 2023年6月27日
    00
  • 高手总结的电脑应用技巧

    标题:高手总结的电脑应用技巧 作为一名电脑爱好者,我们需要学习电脑应用技巧,以更好的使用电脑。本文总结了一些高手常用的电脑应用技巧,并结合实例进行讲解。 1. 终端命令 在终端中使用命令,可以让我们更快的完成一些任务。以下是常用终端命令: mkdir directory_name # 创建一个新目录 cd directory_name # 进入目录 ls #…

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