当前位置: 首页 > news >正文

【3】数据结构的双向链表章

目录标题

    • 双向链表的定义
      • 双向链表的初始化
      • 双向链表的创建
      • 插入操作
      • 删除操作
    • 双向链表总代码与调试

双向链表的定义

  • 结点结构组成:数据域(data)、指针域(pre)、指针域(next)。其中,

    • data存储结点的值
    • pre直接前驱结点的地址
    • next直接后继结点的地址
  • 定义:在单链表中的每一个结点中再增加一个指向其前驱的指针域,该中方式形式的链表成为双向链表。

  • 结点示意图
    在这里插入图片描述

  • 双向链表逻辑结构示意图
    在这里插入图片描述

  • 代码定义双向链表结点

class Node:
    """
    定义双向链表结点类型
    """
    def __init__(self, data):
        # 存储结点中的数据域
        self.data = data
        # 指向后继结点的指针域next
        self.next = None
        # 指向前驱结点的指针域pre
        self.pre = None

双向链表的初始化

  • 初始化双向链表
class DLinkedList:
    """
    双向链表的定义
    """
    def __init__(self):
        """
        双向链表的初始化
        """
        self.head = Node(None)
  • 判断双向链表是否为空
    def isEmpty(self):
        """
        判断双向链表是否为空表
        :return: true or false
        """
        # 如果头结点的next域为none,则返回True,否则返回false
        return self.head.next is None
  • 求双向链表的长度
    def getLength(self):
        """
        获取双向链表的长度
        :return: 当前双向链表中元素的个数
        """
        # length用于计算双向链表的长度
        length = 0
        # 声明cur指针,用于遍历表
        cur = self.head.next
        while cur != None:
            length += 1
            cur = cur.next
        return length
  • 展示双向链表
    def display(self):
        """
        遍历双向链表,进行扫描展示
        :return:
        """
        if self.isEmpty():
            print("当前双向链表为空")
            return
        print("双向链表的元素为:", end="")
        # 循环遍历
        cur = self.head.next
        while cur != None:
            print(cur.data, end="")
            cur =cur.next
        print()

双向链表的创建

    def append(self, data):
        """
        建立双向链表
        :param data: 待插入的元素
        :return:
        """
        # 查找尾结点
        rear = self.head
        while rear.next != None:
            rear = rear.next
        # 创建新结点
        newNode = Node(data)
        # 将尾结点的next指针指向新结点
        rear.next = newNode
        # 将新结点的pre指针指向尾结点
        newNode.pre = rear

插入操作

  • 核心思想

    • 在双向链表第index个结点之前插入一个新的结点,通过四个操作调整指针的指向;
    • 1.设置指针,指向第index个结点,将新结点的前驱指针指向指针cur所指向的结点的前驱结点
    • 2.将指针cur所指向的结点的前驱结点的后继指针指向新结点
    • 3.将新结点的后继指针指向cur所指向的结点
    • 4.将指针cur所指向的结点的前驱指针指向新结点
  • 插入示意图
    在这里插入图片描述

  • 代码定义插入法

    def insert(self, index, data):
        """
        双向链表中任意位置插入元素
        :param index: 待插入的元素位置
        :param data: 待插入元素的值
        :return:
        """
        i = 1
        # 声明指针cur,用于遍历双向链表
        cur = self.head
        # 遍历
        while cur != None and i !=index + 1:
            cur = cur.next
            i += 1
        # index非法情况
        if cur == None or i > self.getLength():
            raise IndexError('index 非法')
        # 创建新结点
        newNode = Node(data)
        # 将新结点的前驱指针指向指针cur所指向的结点的前驱结构
        newNode.pre = cur.pre
        # 将指针cur所指向的结点的前驱结点的后继指针指向新结点
        cur.pre.next = newNode
        # 将新结点的后继指针指向cur所指向的结点
        newNode.next = cur
        # 将指针cur所指向的结点的前驱指针指向新结点
        cur.pre = newNode

删除操作

  • 核心思想
    • 设置局域指针cur,遍历表,直到该指针指向要删除结点;
    • 将指针cur所指向结点的前驱结点的next指针指向指针cur所指向结点的后继结点
    • 将指针cur所指向结点的后继结点的pre指针指向指针cur指向结点的前驱结点
  • 删除示意图
    在这里插入图片描述
  • 代码定义删除法
    def delete(self, index):
        """
        在双向链表中任意位置删除元素
        :param index: 待删除元素的位置
        :return: 被删除的元素
        """
        # 若双向链表为空,抛出异常
        if self.isEmpty():
            raise IndexError('当前为空表!')
        # 找到需要删除结点的前一个结点
        i = 1
        cur = self.head
        while cur != None and i != index + 1:
            cur = cur.next
            i += 1
        # 若index非法
        if cur == None or i > self.getLength():
            raise IndexError('index 非法')
        # 获取被删除元素
        data = cur.data
        # 将指针cur所指向结点的前驱结点的next指针指向指针cur所指向结点的后继结点
        cur.pre.next = cur.next
        # 将指针cur所指向结点的后继结点的pre指针指向指针cur指向结点的前驱结点
        cur.next.pre = cur.pre
        return data

双向链表总代码与调试

  • 双向链表:单链表的一个缺点是无法快速访问前驱结点,当查找某一元素,需要再次从头开始遍历查找,便有了双向链表。
  • 相对于单链表,双向链表复杂一些,它多了一个前驱指针,插入与删除操作相对更复杂与易出错。
# 5.双向链表的实现
class Node:
    """
    定义双向链表结点类型
    """
    def __init__(self, data):
        # 存储结点中的数据域
        self.data = data
        # 指向后继结点的指针域next
        self.next = None
        # 指向前驱结点的指针域pre
        self.pre = None

class DLinkedList:
    """
    双向链表的定义
    """
    def __init__(self):
        """
        双向链表的初始化
        """
        self.head = Node(None)
    def isEmpty(self):
        """
        判断双向链表是否为空表
        :return: true or false
        """
        # 如果头结点的next域为none,则返回True,否则返回false
        return self.head.next is None
    def getLength(self):
        """
        获取双向链表的长度
        :return: 当前双向链表中元素的个数
        """
        # length用于计算双向链表的长度
        length = 0
        # 声明cur指针,用于遍历表
        cur = self.head.next
        while cur != None:
            length += 1
            cur = cur.next
        return length
    def display(self):
        """
        遍历双向链表,进行扫描展示
        :return:
        """
        if self.isEmpty():
            print("当前双向链表为空")
            return
        print("双向链表的元素为:", end="")
        # 循环遍历
        cur = self.head.next
        while cur != None:
            print(cur.data, end="")
            cur =cur.next
        print()
    # 建立双向链表
    def append(self, data):
        """
        建立双向链表
        :param data: 待插入的元素
        :return:
        """
        # 查找尾结点
        rear = self.head
        while rear.next != None:
            rear = rear.next
        # 创建新结点
        newNode = Node(data)
        # 将尾结点的next指针指向新结点
        rear.next = newNode
        # 将新结点的pre指针指向尾结点
        newNode.pre = rear
    def insert(self, index, data):
        """
        双向链表中任意位置插入元素
        :param index: 待插入的元素位置
        :param data: 待插入元素的值
        :return:
        """
        i = 1
        # 声明指针cur,用于遍历双向链表
        cur = self.head
        # 遍历
        while cur != None and i !=index + 1:
            cur = cur.next
            i += 1
        # index非法情况
        if cur == None or i > self.getLength():
            raise IndexError('index 非法')
        # 创建新结点
        newNode = Node(data)
        # 将新结点的前驱指针指向指针cur所指向的结点的前驱结构
        newNode.pre = cur.pre
        # 将指针cur所指向的结点的前驱结点的后继指针指向新结点
        cur.pre.next = newNode
        # 将新结点的后继指针指向cur所指向的结点
        newNode.next = cur
        # 将指针cur所指向的结点的前驱指针指向新结点
        cur.pre = newNode

    def delete(self, index):
        """
        在双向链表中任意位置删除元素
        :param index: 待删除元素的位置
        :return: 被删除的元素
        """
        # 若双向链表为空,抛出异常
        if self.isEmpty():
            raise IndexError('当前为空表!')
        # 找到需要删除结点的前一个结点
        i = 1
        cur = self.head
        while cur != None and i != index + 1:
            cur = cur.next
            i += 1
        # 若index非法
        if cur == None or i > self.getLength():
            raise IndexError('index 非法')
        # 获取被删除元素
        data = cur.data
        # 将指针cur所指向结点的前驱结点的next指针指向指针cur所指向结点的后继结点
        cur.pre.next = cur.next
        # 将指针cur所指向结点的后继结点的pre指针指向指针cur指向结点的前驱结点
        cur.next.pre = cur.pre
        return data


if __name__ == '__main__':
    # print('PyCharm')
    
    # 1.双向链表初始化
    list = DLinkedList()
    list.display()
    # 2.创建双向链表
    for i in range(10):
        list.append(chr(ord('A') + i))
    print('尾插入操作,', end="")
    list.display()
    # 3.获取双向链表的长度
    length = list.getLength()
    print('双向链表的长度为:', length)
    # 4.在双向链表中任意位置插入元素
    list.insert(2, 'Y')
    list.display()
    # 4.在双向链表中任意位置删除元素
    data = list.delete(2)
    print("被删除元素为:", data)
    list.display()
http://www.dtcms.com/a/112174.html

相关文章:

  • 每日一题洛谷P8649 [蓝桥杯 2017 省 B] k 倍区间c++
  • 【嵌入式-stm32电位器控制以及旋转编码器控制LED亮暗】
  • DHCP协议和win server2022无脑配置DHCP
  • 残差神经网络(ResNet)概念解析与用法实例:简洁的图像处理任务
  • 树莓派5使用问题
  • Mysql 使用时的一些规范值
  • Kibana 连接 Elasticsearch(8.11.3)教程
  • Vue组件化开发深度解析:Element UI与Ant Design Vue对比实践
  • WEB安全--提权思路
  • LeetCode 1817 查找用户活跃分钟数
  • Linux下调试器gdb_cgdb使用
  • 中小企业数字化赋能专项行动:Websoft9 开源聚合平台的明确行动计划
  • 蓝桥杯真题———交换瓶子
  • 【嵌入式】——Linux系统调用编程
  • Appium 自动化测试从入门到精通
  • 我与数学建模之波折
  • One API:LLM API 管理 分发系统,github 24.2K Star!
  • 算法设计与分析5(动态规划)
  • Go+Gin实现多文件上传
  • Linux: 系统内核中的信号
  • 【NLP 53、投机采样加速推理】
  • 【CMake】《CMake构建实战:项目开发卷》笔记-Chapter8-生成器表达式
  • LIO-SAM跑自己的数据集
  • 局域网:电脑或移动设备作为主机实现局域网访问
  • MyBatis操作数据库(1)
  • linux安装redis
  • PyTorch使用(7)-张量常见运算函数
  • AIGC实战——CycleGAN详解与实现
  • NVIDIA AgentIQ 详细介绍
  • 从Keep-Alive到页面关闭:解决Vue和React生命周期函数不触发的实战技巧