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

每日一题-二叉搜索树与双向链表

将二叉搜索树转化为排序双向链表

问题描述

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表,要求空间复杂度为 O(1),时间复杂度为 O(n),并且不能创建新的结点,只能调整树中结点的指针指向。
在这里插入图片描述

数据范围
  • 二叉树的节点数: 0 ≤ n ≤ 1000 0 \leq n \leq 1000 0n1000
  • 每个节点的值: 0 ≤ v a l ≤ 1000 0 \leq val \leq 1000 0val1000
解决方案
  1. 要求:不能创建新的结点,只能调整树中结点指针的指向。转换完成后,树中节点的左指针需要指向前驱,右指针需要指向后继。
  2. 返回:返回链表中的第一个节点的指针。
  3. 结构:链表的节点就是原树的节点,每个节点的左指针指向前驱,右指针指向后继。
示例
  • 输入:{10, 6, 14, 4, 8, 12, 16}

  • 输出:从左到右是:4, 6, 8, 10, 12, 14, 16;从右到左是:16, 14, 12, 10, 8, 6, 4

  • 输入:{5, 4, #, 3, #, 2, #, 1}

  • 输出:从左到右是:1, 2, 3, 4, 5;从右到左是:5, 4, 3, 2, 1

代码实现
/*** 定义二叉树节点结构* 树节点包含一个整数值 `val`,指向左子节点 `left` 和右子节点 `right` 的指针*//*** 中序遍历函数,将二叉搜索树转化为双向链表* @param node 当前节点* @param prev 指向前一个节点的指针,用于连接当前节点* @param head 指向链表头节点的指针*/
void inOrderTraversal(struct TreeNode* node, struct TreeNode** prev,struct TreeNode** head) {// 递归终止条件:节点为空时返回if (node == NULL) {return;}// 先遍历左子树inOrderTraversal(node->left, prev, head);// 处理当前节点if (*prev) {  // 如果前一个节点存在(*prev)->right = node;  // 前驱节点的右指针指向当前节点node->left = *prev;     // 当前节点的左指针指向前驱节点} else {  // 如果是链表的第一个节点*head = node;  // 第一个节点就是链表的头节点}// 更新prev为当前节点*prev = node;  // 前一个节点更新为当前节点// 再遍历右子树inOrderTraversal(node->right, prev, head);
}/*** 将二叉搜索树转换为双向链表* @param pRootOfTree 二叉树的根节点* @return 双向链表的头节点*/
struct TreeNode* Convert(struct TreeNode* pRootOfTree ) {// 如果根节点为空,直接返回NULLif (!pRootOfTree) return NULL;// prev指针用于记录中序遍历中的前一个节点struct TreeNode* prev = NULL;// head指针用于记录链表的头节点struct TreeNode* head = NULL;// 调用中序遍历函数,完成树转链表inOrderTraversal(pRootOfTree, &prev, &head);// 返回链表的头节点return head;
}
关键概念
  1. 中序遍历:二叉搜索树的中序遍历是递增的。因此,通过中序遍历的顺序将二叉树节点连接成双向链表,即可确保双向链表是有序的。

  2. 指针传递:在递归过程中,prevhead 使用指针的指针传递(即 struct TreeNode**)。这可以确保在递归过程中修改这些指针的值时,外部调用者也能看到这些修改。

为什么 struct TreeNode** prevstruct TreeNode** head

我一直在思考为什么TreeNode** prev, struct TreeNode** head,而不是TreeNode* prev, struct TreeNode* head,后来才意识到在函数 inOrderTraversal 中,prev 和 head 是作为值传递给递归函数的。由于 C 语言中函数传递的是值,而不是引用,所以在递归过程中修改 prev 和 head 的值不会影响到外部的 prev 和 head。
为了解决这个问题,我们需要使用 struct TreeNode** 来传递指针的指针。可以把 struct TreeNode当作一个数据类型int,然后再 struct TreeNode**类比int指针。完美。
在递归过程中,prevhead 是作为指针传递的。如果直接使用 struct TreeNode*,那么修改的是它们的副本,无法影响到外部的实际值。通过传递 struct TreeNode**,递归函数可以修改指针本身,从而影响到实际的 prevhead 指针。

相关文章:

每日一题-二叉搜索树与双向链表

将二叉搜索树转化为排序双向链表 问题描述 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表,要求空间复杂度为 O(1),时间复杂度为 O(n),并且不能创建新的结点,只能调整树中结点的指针指向。 数据范围 …...

【多视图学习】Self-Weighted Contrastive Fusion for Deep Multi-View Clustering

Self-Weighted Contrastive Fusion for Deep Multi-View Clustering 用于深度多视图聚类的自加权对比融合 TMM 2024 代码链接 论文链接 0.摘要 多视图聚类可以从多个视图中探索共识信息,在过去二十年中越来越受到关注。然而,现有的工作面临两个主要挑…...

ASK-HAR:多尺度特征提取的深度学习模型

一、探索多尺度特征提取方法 在近年来,随着智能家居智能系统和传感技术的快速发展,人类活动识别(HAR)技术已经成为一个备受瞩目的研究领域。HAR技术的核心在于通过各种跟踪设备和测量手段,如传感器和摄像头&#xff0…...

C语言:数据的存储

本文重点: 1. 数据类型详细介绍 2. 整形在内存中的存储:原码、反码、补码 3. 大小端字节序介绍及判断 4. 浮点型在内存中的存储解析 数据类型结构的介绍: 类型的基本归类: 整型家族 浮点家族 构造类型: 指针类型&…...

深入理解动态规划(dp)--(提前要对dfs有了解)

前言:对于动态规划:该算法思维是在dfs基础上演化发展来的,所以我不想讲的是看到一个题怎样直接用动态规划来解决,而是说先用dfs搜索,一步步优化,这个过程叫做动态规划。(该文章教你怎样一步步的…...

单片机基础模块学习——数码管(二)

一、数码管模块代码 这部分包括将数码管想要显示的字符转换成对应段码的函数,另外还包括数码管显示函数 值得注意的是对于小数点和不显示部分的处理方式 由于小数点没有单独占一位,所以这里用到了两个变量i,j用于跳过小数点导致的占据其他字符显示在数…...

【大数据】机器学习----------强化学习机器学习阶段尾声

一、强化学习的基本概念 注: 圈图与折线图引用知乎博主斜杠青年 1. 任务与奖赏 任务:强化学习的目标是让智能体(agent)在一个环境(environment)中采取一系列行动(actions)以完成一个…...

flink写parquet解决timestamp时间格式字段问题

背景 Apache Parquet 是一种开源的列式数据文件格式,旨在实现高效的数据存储和检索。它提供高性能压缩和编码方案(encoding schemes)来批量处理复杂数据,并且受到许多编程语言和分析工具的支持。 在我们通过flink写入parquet文件的时候,会遇到timestamp时间格式写入的问题。…...

redis实现lamp架构缓存

redis服务器环境下mysql实现lamp架构缓存 ip角色环境192.168.242.49缓存服务器Redis2.2.7192.168.242.50mysql服务器mysql192.168.242.51web端php ***默认已安装好redis,mysql 三台服务器时间同步(非常重要) # 下载ntpdate yum -y install…...

正则表达式中常见的贪婪词

1. * 含义:匹配前面的元素零次或者多次。示例:对于正则表达式 a*,在字符串 "aaaa" 中,它会匹配整个 "aaaa",因为它会尽可能多地匹配 a 字符。代码示例(Python)&#xff1a…...

CF 339A.Helpful Maths(Java实现)

题目分析 输入一串式子,输出从小到大排列的式子 思路分析 如上所说核心思路,但是我要使用笨方法,输入一串式子用split分割开,但是此时需要用到转义字符,即函数内参数不能直接使用“”,而是“\\”。分割开后…...

SQL 指南

SQL 指南 引言 SQL(Structured Query Language,结构化查询语言)是一种用于管理关系数据库系统的标准计算机语言。自1970年代问世以来,SQL已经成为了数据库管理和数据操作的事实标准。本文旨在为初学者和有经验的数据库用户提供一个全面的SQL指南,涵盖SQL的基础知识、高级…...

DDD架构实战第七讲总结:分层模型和代码组织

云架构师系列课程之DDD架构实战第七讲总结:分层模型和代码组织 一、引言 在前几讲中,我们介绍了领域驱动设计(DDD)的基本构造块和生命周期模型中的聚合。本讲将重点讨论如何将这些构造块和代码组织起来,探讨分层架构和六边形模型,以及如何组织代码结构。 二、工厂和资…...

Python “字典” 实战案例:5个项目开发实例

Python “字典” 实战案例:5个项目开发实例 内容摘要 本文包括 5 个使用 Python 字典的综合应用实例。具体是: 电影推荐系统配置文件解析器选票统计与排序电话黄页管理系统缓存系统(LRU 缓存) 以上每一个实例均有完整的程序代…...

(一)QT的简介与环境配置WIN11

目录 一、QT的概述 二、QT的下载 三、简单编程 常用快捷键 一、QT的概述 简介 Qt(发音:[kjuːt],类似“cute”)是一个跨平台的开发库,主要用于开发图形用户界面(GUI)应用程序,…...

在 Windows 系统上,将 Ubuntu 从 C 盘 迁移到 D 盘

在 Windows 系统上,如果你使用的是 WSL(Windows Subsystem for Linux)并安装了 Ubuntu,你可以将 Ubuntu 从 C 盘 迁移到 D 盘。迁移过程涉及导出当前的 Ubuntu 发行版,然后将其导入到 D 盘的目标目录。以下是详细的步骤…...

vue2的$el.querySelector在vue3中怎么写

这个也属于直接操作 dom 了,不建议在项目中这样操作,不过我是在vue2升级vue3的时候遇到的,是以前同事写的代码,也没办法 先来看一下对比 在vue2中获取实例是直接通过 this.$refs.xxx 获取绑定属性 refxxx 的实例,并且…...

GPSd定时检测保活TCP GPS源

为了在 TCP GPS 源丢失连接时自动重新连接,可以编写一个监控脚本,定期检查 gpspipe 输出中的 TCP 源数据是否存在。如果检测到丢失,则使用 gpsdctl 或直接命令重新添加 TCP 源。 1、工具 检查并安装必要工具,本例需要使用 gpspi…...

IDEA中Maven使用的踩坑与最佳实践

文章目录 IDEA中Maven使用的踩坑与最佳实践一、环境配置类问题1. Maven环境配置2. IDEA中Maven配置建议 二、常见问题与解决方案1. 依赖下载失败2. 依赖冲突解决3. 编译问题修复 三、效率提升技巧1. IDEA Maven Helper插件使用2. 常用Maven命令配置3. 多模块项目配置4. 资源文件…...

使用 Python 调用 OpenAI 的接口初识

使用 Python 调用 OpenAI 的接口非常简单,以下将结合实际代码示例和使用场景进行详细讲解,步骤如下: 文章目录 1. 安装 OpenAI 官方库2. 准备 API Key3. 基本使用示例:调用 ChatGPT**代码示例:****运行结果&#xff1a…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage)&#xff1a…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

Cesium1.95中高性能加载1500个点

一、基本方式&#xff1a; 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的&#xff0c;根据Excel列的需求预估的工时直接打骨折&#xff0c;不要问我为什么&#xff0c;主要…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

(转)什么是DockerCompose?它有什么作用?

一、什么是DockerCompose? DockerCompose可以基于Compose文件帮我们快速的部署分布式应用&#xff0c;而无需手动一个个创建和运行容器。 Compose文件是一个文本文件&#xff0c;通过指令定义集群中的每个容器如何运行。 DockerCompose就是把DockerFile转换成指令去运行。 …...

深度学习水论文:mamba+图像增强

&#x1f9c0;当前视觉领域对高效长序列建模需求激增&#xff0c;对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模&#xff0c;以及动态计算优势&#xff0c;在图像质量提升和细节恢复方面有难以替代的作用。 &#x1f9c0;因此短时间内&#xff0c;就有不…...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...