题⽬描述

输⼊⼀棵⼆叉搜索树,将该⼆叉搜索树转换成⼀个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向

思路及解答

递归中序遍历(推荐)

根据二叉搜索树的特点:左结点的值<根结点的值<右结点的值,我们不难发现,使用二叉树的中序遍历出来的数据的数序,就是排序的顺序。因此,首先,确定了二叉搜索树的遍历方法。

我们看下图,我们可以把树分成三个部分:值为10的结点、根结点为6的左子树、根结点为14的右子树。根据排序双向链表的定义,值为10的结点将和它的左子树的最大一个结点链接起来,同时它还将和右子树最小的结点链接起来。

按照中序遍历的顺序,当我们遍历到根结点时,它的左子树已经转换成一个排序好的双向链表了,并且处在链表中最后一个的结点是当前值最大的结点。

具体思路如下,可以利用BST中序遍历的有序性,在遍历过程中调整指针:

  1. 中序遍历​:按照左子树→根节点→右子树的顺序遍历
  2. 指针调整​:维护一个pre指针记录前驱节点,将当前节点与前驱节点双向连接
  3. 头节点处理​:第一个被访问的节点(最左节点)作为链表头节点
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
} public class Solution {
private TreeNode pre = null; // 记录前驱节点
private TreeNode head = null; // 链表头节点 public TreeNode convert(TreeNode root) {
if (root == null) return null; // 中序遍历左子树
convert(root.left); // 处理当前节点
if (pre == null) {
head = root; // 第一个节点作为头节点
} else {
pre.right = root; // 前驱节点的next指向当前节点
root.left = pre; // 当前节点的prev指向前驱节点
}
pre = root; // 更新前驱节点为当前节点 // 中序遍历右子树
convert(root.right); return head;
}
}
  • 时间复杂度​:O(n),每个节点被访问一次
  • 空间复杂度​:O(n),递归调用栈的空间(最坏情况下树退化为链表)

迭代中序遍历(栈辅助)

使用栈模拟递归过程,避免递归带来的栈溢出风险:

  1. 栈辅助遍历​:利用栈实现中序遍历的非递归版本
  2. 指针调整​:同样维护pre指针记录前驱节点
  3. 头节点标记​:使用布尔变量标记第一个节点作为链表头
public class Solution {
public TreeNode convert(TreeNode root) {
if (root == null) return null; Stack<TreeNode> stack = new Stack<>();
TreeNode pre = null;
TreeNode head = null;
boolean isFirst = true; // 标记第一个节点 while (root != null || !stack.isEmpty()) {
// 走到最左节点
while (root != null) {
stack.push(root);
root = root.left;
} root = stack.pop(); if (isFirst) {
head = root; // 第一个节点作为头节点
pre = head;
isFirst = false;
} else {
pre.right = root; // 连接前驱和当前节点
root.left = pre;
pre = root;
} root = root.right; // 处理右子树
} return head;
}
}
  • 时间复杂度​:O(n)
  • 空间复杂度​:O(n),栈的空间消耗

Morris遍历

利用Morris遍历实现O(1)空间复杂度的中序遍历:

  1. 线索化​:利用叶子节点的空指针指向中序前驱或后继
  2. 指针调整​:在遍历过程中实时调整指针关系
  3. 无栈递归​:不需要额外栈空间或递归调用
public class Solution {
public TreeNode convert(TreeNode root) {
TreeNode pre = null;
TreeNode head = null;
TreeNode current = root; while (current != null) {
if (current.left == null) {
// 处理当前节点
if (pre == null) {
head = current;
} else {
pre.right = current;
current.left = pre;
}
pre = current; current = current.right;
} else {
// 找到当前节点的中序前驱
TreeNode predecessor = current.left;
while (predecessor.right != null && predecessor.right != current) {
predecessor = predecessor.right;
} if (predecessor.right == null) {
predecessor.right = current; // 建立线索
current = current.left;
} else {
// 处理当前节点
predecessor.right = null;
if (pre == null) {
head = current;
} else {
pre.right = current;
current.left = pre;
}
pre = current; current = current.right;
}
}
} return head;
}
}
  • 时间复杂度​:O(n)
  • 空间复杂度​:O(1),只使用固定数量的指针变量

剑指offer-26、二叉搜索树与双向链表的更多相关文章

  1. 剑指Offer 26. 二叉搜索树与双向链表 (二叉搜索树)

    题目描述 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. 题目地址 https://www.nowcoder.com/practic ...

  2. [剑指Offer] 26.二叉搜索树与双向链表

    [思路]因为二叉搜索树的中序遍历就是递增排列的,所以只要在中序遍历时将每个结点放入vector中,再分别为每个结点的左右指针赋值即可. /* struct TreeNode { int val; st ...

  3. 剑指 Offer 36. 二叉搜索树与双向链表 + 中序遍历 + 二叉排序树

    剑指 Offer 36. 二叉搜索树与双向链表 Offer_36 题目描述 题解分析 本题考查的是二叉树的中序遍历以及二叉排序树的特征(二叉排序树的中序遍历序列是升序序列) 利用排序二叉树中序遍历的性 ...

  4. 剑指 Offer 36. 二叉搜索树与双向链表

    剑指 Offer 36. 二叉搜索树与双向链表 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表.要求不能创建任何新的节点,只能调整树中节点指针的指向. 为了让您更好地理解问题,以下面的 ...

  5. 【剑指Offer】二叉搜索树与双向链表 解题报告(Python)

    [剑指Offer]二叉搜索树与双向链表 解题报告(Python) 标签(空格分隔): 剑指Offer 题目地址:https://www.nowcoder.com/ta/coding-interview ...

  6. 【剑指offer】二叉搜索树转双向链表,C++实现

    原创博文,转载请注明出处! # 题目 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. 二叉树节点的定义 struct TreeNod ...

  7. 【Java】 剑指offer(36) 二叉搜索树与双向链表

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不 ...

  8. Go语言实现:【剑指offer】二叉搜索树与双向链表

    该题目来源于牛客网<剑指offer>专题. 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. Go语言实现: type T ...

  9. 剑指offer 27二叉搜索树与双向链表

    class Solution { public: void ConvertNode(TreeNode* pRootOfTree,TreeNode** pre) { if(pRootOfTree) { ...

  10. 【剑指offer】二叉搜索树转双向链表

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/26623795 题目描写叙述: 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表. ...

随机推荐

  1. H20 大模型推理系统环境配置踩坑

    基础环境 CPU:INTEL(R) XEON(R) PLATINUM 8558P 48 Cores 96 Threads × 2 GPU:NVIDIA H20-3e NVL 141G × 8,NVLI ...

  2. 使用远程IO控制器ZLAN6808-3代替PLC实现电池工业生产线自动化

    动力电池是一种能量储存装置,随着智能制造在传统制造领域的进一步渗透,作为国家战略性新兴产业,明确提出动力电池产业的智能制造发展规划,动力电池的生产已逐步从半自动化.自动化向智能化.数字化转型. 在动力 ...

  3. Darkreader插件导致B站评论区“更多评论”不显示

    解决方案: 在高级设置中把B站css中的".button:before"那里删掉即可

  4. win11系统把扫描仪快捷方式到桌面的问题

    说到扫描仪已经成为了很多雨林木风官网用户在日常工作生活中不可或缺的一个工具.扫描仪都能帮助我们快速.高效地将纸质文档转化为数字格式.然而,有一位Windows 11系统用户,却发现在桌面上没有扫描仪的 ...

  5. win10专业版点击右键无法弹出菜单的问题

    一位雨林木风系统的小伙伴遇到在win10专业版电脑里面点击鼠标右键没有弹出菜单,想点击刷新都没办法了,应该怎么解决呢?接下来,雨林木风小编就来分享具体的处理方法,一起来看看吧. 如果 Windows ...

  6. unity 单位 像素 分辨率 正交摄像机size 之间的关系

    这个5表示摄像机的视距 代表摄像机拍摄的一般高度 如果16:9的分辨率,100像素为1 unity单位的情况 填充摄像机所需图片大小尺寸为:高度:5*2*100 = 1000    宽度:1000*1 ...

  7. Angular12和WebApi多语言使用

    1.安装ngx-translate 运行下面命令安装@ngx-translate/core和@ngx-translate/http-loader: npm install @ngx-translate ...

  8. 读《我加载了恋爱游戏》(by掠过的乌鸦)

    读书经过 事情发生于寒假请假在家的一个下午,闲来无事刷b站,看到up主凌凌上将带老爸看小说女主的视频(因为<我真没想重生啊>点进去的),出现清野凛.然后由于推送机制加上之前也被推过,我就看 ...

  9. Jenkins集成部署SpringBoot

    Jenkins集成部署SpringBoot 1. 前言 随着业务的增长,需求也开始增多,每个需求的大小,开发周期,发布时间都不一致.基于微服务的系统架构,功能的叠加,对应的服务的数量也在增加,大小功能 ...

  10. NAS和SAN存储基本知识

    1 NAS存储是一台网络局域存储服务器,相当于是一台存储服务器,就和web服务器,邮件服务器一样的道理,因为接在了网络上面去了,所以有大量访问NAS的时候,也是很容易造成网络停顿:作为存储,主要目的是 ...