python双向循环链表实例详解

Python双向循环链表实例详解

本文介绍如何通过Python实现双向循环链表,让读者更好地理解链表的概念和应用。全文包含以下内容:

  1. 什么是双向循环链表?
  2. 如何实现双向循环链表?
  3. 双向循环链表的应用场景
  4. Python双向循环链表的示例

什么是双向循环链表?

双向循环链表是一种常见的数据结构,它由一系列节点组成,每个节点包含两个指针,分别指向前驱节点和后继节点。头节点的前驱节点指向尾节点,尾节点的后继节点指向头节点,形成了一个循环结构。

相比于单向链表,双向循环链表可以快速地访问前驱节点,因此更加方便实现双向遍历和双向查找等操作。同时,在删除节点时也更加方便。

如何实现双向循环链表?

实现双向循环链表,需要定义节点类和链表类,具体代码如下:

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

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

    def add_first(self, value):
        node = Node(value)

        if self.size == 0:
            self.head = self.tail = node
        else:
            node.next = self.head
            self.head.prev = node
            self.head = node

        self.size += 1

    def add_last(self, value):
        node = Node(value)

        if self.size == 0:
            self.head = self.tail = node
        else:
            node.prev = self.tail
            self.tail.next = node
            self.tail = node

        self.size += 1

    def remove_first(self):
        if self.size == 0:
            raise Exception("Linked list is empty")
        elif self.size == 1:
            node = self.head
            self.head = self.tail = None
        else:
            node = self.head
            self.head = node.next
            self.head.prev = None

        self.size -= 1
        return node.data

    def remove_last(self):
        if self.size == 0:
            raise Exception("Linked list is empty")
        elif self.size == 1:
            node = self.head
            self.head = self.tail = None
        else:
            node = self.tail
            self.tail = node.prev
            self.tail.next = None

        self.size -= 1
        return node.data

    def __iter__(self):
        current = self.head
        while current:
            yield current.data
            current = current.next

上面代码中,我们定义了一个Node类来表示链表的节点。每个节点包含三个属性:data表示存储的数据,prev表示前驱节点,next表示后继节点。

我们还定义了一个DoublyLinkedList类来管理整个链表。其中,headtail分别表示头结点和尾节点,size表示链表长度。

add_first方法和add_last方法分别在链表的头部和尾部添加节点。在添加节点时,需要判断链表是否为空,如果为空,则头结点和尾节点都指向新加入的节点;如果不为空,则需要更改头结点或者尾节点的前驱和后继指针。

remove_first方法和remove_last方法分别在链表的头部和尾部删除节点。在删除节点时,同样需要判断链表是否为空,如果为空则抛出异常;如果链表只有一个节点,则需要将头结点和尾节点都置为None;如果链表有多个节点,则需要找到要删除的节点,修改前驱和后继指针。

最后,我们实现了__iter__方法,以便支持对链表的迭代。

双向循环链表的应用场景

双向循环链表在实际应用中非常广泛,例如浏览器的“前进”和“后退”功能、游戏中的物品管理等等。

下面我们以实例的形式来说明如何使用双向循环链表,以此加深对该数据结构和算法的理解。

Python双向循环链表的示例

下面是一个简单的示例,我们使用双向循环链表来实现一个数码游戏。

在数码游戏中,玩家需要将九个数字拼成一个3x3的矩阵。玩家可以通过交换相邻的数字来完成拼图。这个过程中,我们需要实时记录拼图的状态,这时候就可以用到双向循环链表了。

class Puzzle:
    def __init__(self, numbers):
        self.board = DoublyLinkedList()
        self.moves = []
        for number in numbers:
            self.board.add_last(number)

    def move_left(self):
        index = 1
        current = self.board.head.next
        while current:
            if current.data == 0:
                break
            index += 1
            current = current.next

        if index % 3 == 1:
            raise Exception("Cannot move left")

        current.data, current.prev.data = current.prev.data, current.data
        self.moves.append("L")

    def move_right(self):
        index = 1
        current = self.board.head.next
        while current:
            if current.data == 0:
                break
            index += 1
            current = current.next

        if index % 3 == 0:
            raise Exception("Cannot move right")

        current.data, current.next.data = current.next.data, current.data
        self.moves.append("R")

    def move_up(self):
        index = 0
        current = self.board.head
        while current:
            if current.data == 0:
                break
            index += 1
            current = current.next

        if index < 3:
            raise Exception("Cannot move up")

        i = 0
        current = self.board.head
        while i < index - 3:
            current = current.next
            i += 1

        current.data, current.prev.data = current.prev.data, current.data
        self.moves.append("U")

    def move_down(self):
        index = 0
        current = self.board.head
        while current:
            if current.data == 0:
                break
            index += 1
            current = current.next

        if index > 5:
            raise Exception("Cannot move down")

        i = 0
        current = self.board.head
        while i < index + 3:
            current = current.next
            i += 1

        current.data, current.prev.data = current.prev.data, current.data
        self.moves.append("D")

    def print_board(self):
        for i, number in enumerate(self.board):
            print(number, end=" ")
            if i % 3 == 2:
                print()
        print()

上面这个代码中,我们首先定义了一个Puzzle类,这个类包含一个双向循环链表board来存储拼图状态。对于拼图中的每一块,我们都使用一个数字来表示,其中数字0表示空白块。

我们可以通过move_leftmove_rightmove_upmove_down方法来移动拼图的空白块,这里涉及到了判断拼图中每个块的位置关系,如果空白块可以移动,则交换空白块和它所在的块。我们用moves数组记录下每一步的移动方向。最后,我们还提供了print_board方法,用于打印当前拼图的状态。

现在我们可以通过以下代码来测试这个类的功能:

puzzle = Puzzle([2, 8, 3, 1, 6, 4, 7, 0, 5])

puzzle.move_right()
puzzle.print_board()
puzzle.move_right()
puzzle.print_board()
puzzle.move_down()
puzzle.print_board()
puzzle.move_down()
puzzle.print_board()
puzzle.move_left()
puzzle.print_board()
puzzle.move_up()
puzzle.print_board()
puzzle.move_left()
puzzle.print_board()
puzzle.move_up()
puzzle.print_board()

print(puzzle.moves)

以上就是Python实现双向循环链表的示例。本文中,我们首先介绍了什么是双向循环链表,然后讲解了如何使用Python来实现双向循环链表,最后,我们通过一个实际的数码游戏来展示双向循环链表的应用。

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

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

相关文章

  • nodeserver零基础——开发环境文件自动重载

    nodeserver零基础——开发环境文件自动重载 在软件开发中,不断地修改代码,并且反复测试是一个必不可少的过程。然而,对于初学者来说,这一过程会变得很繁琐。每一次修改代码后,需要手动重启服务器,才能看到修改后的效果,这对于时间的浪费是不必要的。因此,为了方便初学者,现在我们来介绍一种零基础操作的方法,将我们的开发环境改进为支持自动重载的环境。 什么是文件…

    其他 2023年3月28日
    00
  • 使用maven命令行下载依赖库

    使用Maven命令行下载依赖库 Maven是一个常用的Java构建工具,可以帮助我们管理项目依赖,并可以自动下载所需的依赖库。通过使用Maven,我们可以节省大量配置和管理时间,提高项目的构建效率。本篇文章将介绍如何通过Maven命令行下载依赖库。 1. 确认Maven已安装 首先我们需要确认Maven是否已经安装。可以在命令行中输入以下命令来检查: mvn…

    其他 2023年3月29日
    00
  • Fragment配合RadioGroup实现点击切换布局

    在Android开发中,我们经常需要实现点击切换布局的功能。其中,Fragment和RadioGroup是两个常用的组件。本文将介绍如何使用Fragment和RadioGroup实现点击切换布局的完整攻略,包括创建Fragment、使用RadioGroup监听点击事件、切换Fragment等内容,并提供两个示例说明。 1. 创建Fragment 在使用Fra…

    other 2023年5月5日
    00
  • win11右键菜单用不习惯怎么办 win11右键菜单显示样式恢复至win10教程

    以下是详细的攻略,包含步骤和示例说明。 标题:win11右键菜单用不习惯怎么办 首先,需要下载并安装WinAero Tweaker,这是一款免费的Windows系统优化工具,可以用来修改系统设置和调整各种功能。点击以下链接进入官网下载页面:https://winaero.com/download.php?view.2145 安装完毕后,打开WinAero T…

    other 2023年6月27日
    00
  • 基于PHP实现通过照片获取ip地址

    基于PHP实现通过照片获取IP地址的攻略 1. 简介 在本攻略中,我们将使用PHP编程语言来实现通过照片获取IP地址的功能。具体来说,我们将利用照片中的元数据信息,提取出其中的位置信息,从而获取到照片拍摄时的IP地址。 2. 步骤 2.1 安装必要的库和工具 首先,我们需要安装以下两个库和工具:- Exif扩展:用于读取照片的元数据信息。- GeoIP库:用…

    other 2023年7月31日
    00
  • BigDecimal类

    BigDecimal类 在Java中,使用float或double类型来表示小数时,由于浮点数本质上是二进制的,因此在进行精确计算时可能会存在精度丢失的问题,这对于需要精确计算的场景来说是不能接受的。 为了解决这一问题,Java中提供了BigDecimal类,即可以精确表示数字的高精度类。本篇文章将分为以下几个部分介绍BigDecimal类的使用。 1. B…

    其他 2023年3月28日
    00
  • Python警察与小偷的实现之一客户端与服务端通信实例

    首先介绍一下”Python警察与小偷”这个项目的背景和概念。 “Python警察与小偷”是一种基于Python编程语言实现的网络安全技术,它通过客户端与服务端的通信方式,让警察在远程主机上对小偷进行操作和控制,从而达到保护计算机安全的目的。 下面我们来介绍一下客户端与服务端通信的实现过程。 选择通信协议 在客户端与服务端之间进行通信时,我们需要选择一种通信协…

    other 2023年6月27日
    00
  • elasticsearch中国

    当然,我很乐意为您提供有关“elasticsearch中国”的完整攻略。以下是详细的步骤和两个示例: 1. 什么是elasticsearch中国? elasticsearch中国是elasticsearch在中国的官方网站,提供了elasticsearch的中文文档、社区、培训、咨询等服务。elasticsearch是一个开源的分布式搜索引擎,可以用于全文搜…

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