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

二叉搜索树与双向链表

目录

基本要求

节点结构

核心算法:中序遍历 + 指针修改

算法思想

递归实现

非递归实现

复杂度分析

时间复杂度:

空间复杂度:


基本要求

这是一个经典的算法问题:将二叉搜索树(BST)转换成一个排序的双向循环链表(或双向链表)。

通常题目要求是:

  1. 双向链表中的节点顺序与二叉搜索树的中序遍历顺序一致(即升序)。
  2. 需要将节点的左右指针分别作为双向链表的前驱(prev)和后继(next)指针。
  3. 有时要求链表是循环的(头尾相连),有时只要求是双向链表。
  4. 原地转换:不能创建新节点,只能调整原有指针

节点结构

class Node { public: int val; Node* left; Node* right; Node(int _val) : val(_val), left(nullptr), right(nullptr) {} };

核心算法:中序遍历 + 指针修改

算法思想

利用BST(二叉搜索树)的中序遍历特性:

  1. 中序遍历BST会按升序访问所有节点
  2. 在遍历过程中,记录前一个访问的节点(prev)
  3. 将当前节点与prev节点双向连接
  4. 遍历完成后,连接头尾节点形成循环

递归实现

class Solution { private: Node* prev = nullptr; // 记录前驱节点 Node* head = nullptr; // 记录链表头节点 // 中序遍历递归函数 void inorderTraversal(Node* curr) { if (!curr) return; // 1. 递归遍历左子树 inorderTraversal(curr->left); // 2. 处理当前节点 if (!prev) { // 第一个节点(最小值),设为头节点 head = curr; } else { // 连接前驱和当前节点 prev->right = curr; curr->left = prev; } // 更新prev为当前节点 prev = curr; // 3. 递归遍历右子树 inorderTraversal(curr->right); } public: Node* treeToDoublyList(Node* root) { if (!root) return nullptr; // 中序遍历并调整指针 inorderTraversal(root); //如果需要转换BST为双向循环链表(不需要删除下面两行代码即可) // 连接头尾形成循环链表 head->left = prev; // 头的前驱指向尾 prev->right = head; // 尾的后继指向头 return head; } };

非递归实现

不使用递归,通过显式栈来模拟中序遍历的过程,在遍历过程中调整指针指向。

class Solution { public: Node* treeToDoublyList(Node* root) { if (!root) return nullptr; Node* prev = nullptr; Node* head = nullptr; stack<Node*> st; Node* curr = root; // 中序遍历(迭代版) while (curr || !st.empty()) { // 左子树入栈 while (curr) { st.push(curr); curr = curr->left; } // 弹出当前节点 curr = st.top(); st.pop(); // 连接节点 if (!prev) { head = curr; // 第一个节点 } else { prev->right = curr; curr->left = prev; } prev = curr; curr = curr->right; // 处理右子树 } //如果需要转换BST为双向循环链表(不需要删除下面两行代码即可) // 形成循环 head->left = prev; prev->right = head; return head; } };

复杂度分析

时间复杂度:

O(n):每个节点被访问一次,n为节点总数

空间复杂度:

O(h),h为树的高度

  • 最坏情况(链状树):O(n)
  • 最好情况(平衡树):O(log n)
http://www.gsyq.cn/news/113542.html

相关文章:

  • GitHub级文档美化终极方案:github-markdown-css完整指南
  • 图像测量技术详解(含 Halcon 示例)
  • Vosk Android语音识别:5个常见模型部署问题及解决方案
  • [鸿蒙2025领航者闯关]人情往来应用开源项目实战
  • 5个关键步骤快速掌握Unitree GO2 ROS2 SDK:从环境搭建到实战应用
  • 基于VUE的企业员工管理系统 [VUE]-计算机毕业设计源码+LW文档
  • 基于VUE的汽车出租管理系统 [VUE]-计算机毕业设计源码+LW文档
  • Koodo Reader如何实现智能封面管理?电子书封面优化全攻略
  • 在Docker环境中安装RabbitMQ延迟消息插件实战记录
  • 具身智能:零基础入门睿尔曼机械臂(五)—— 手眼标定核心原理与数学求解
  • d2s-editor:暗黑破坏神2存档编辑的终极解决方案
  • C++元编程完全指南
  • Compressor.js革命性图像压缩:让你的Web应用飞起来
  • 学习笔记——线程
  • NVIDIA显卡设置终极指南:轻松掌握图形性能优化技巧
  • AI自动生成PPT工具对比分析,效率差距明显
  • EmotiVoice语音合成质量打分标准(MOS)参考
  • 暗黑破坏神2存档编辑器终极解决方案:告别刷怪困扰,开启自定义游戏新纪元
  • 文档生成PPT工具大集合,PDF与Word都能直接用
  • 免费开源屏幕录制神器:vokoscreenNG 2024终极指南
  • 灵活配置+高精度:4/6/8/12路模拟量采集模块,工业场景首选
  • Mem Reduct终极指南:简单三步解决电脑内存不足问题
  • JavaScript解密神器:JStillery让你的代码分析变得如此简单
  • 实战指南:Kafka-UI隔离网络环境部署全流程
  • 导轨水平安装中安装面不平的解决方法
  • 手机端3秒AI绘图:denoising-diffusion轻量化实战指南
  • Obsidian Style Settings 插件终极使用指南:快速个性化你的笔记界面
  • Switch大气层主题终极指南:完美定制你的个性化界面
  • Vosk Android中文语音识别模型部署:解决“Failed to unpack the model“错误的完整指南
  • 5分钟解锁OpenPLC Editor:新手也能快速上手的工业自动化编程神器