本文参考自《剑指offer》一书,代码采用Java语言。

更多:《剑指Offer》Java实现合集  

题目 

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

思路

  二叉搜索树、排序链表,想到使用中序遍历。

  要实现双向链表,必须知道当前结点的前一个结点。根据中序遍历可以知道,当遍历到根结点的时候,左子树已经转化成了一个排序的链表了,根结点的前一结点就是该链表的最后一个结点(这个结点必须记录下来,将遍历函数的返回值设置为该结点即可),链接根结点和前一个结点,此时链表最后一个结点就是根结点了。再处理右子树,遍历右子树,将右子树的最小结点与根结点链接起来即可。左右子树的转化采用递归即可。

  大概思想再理一下:首先想一下中序遍历的大概代码结构(先处理左子树,再处理根结点,之后处理右子树),假设左子树处理完了,就要处理根结点,而根结点必须知道左子树的最大结点,所以要用函数返回值记录下来;之后处理右子树,右子树的最小结点(也用中序遍历得到)要和根结点链接。

  注意搞清楚修改后的中序遍历函数的意义(见代码注释)

测试算例 

  1.功能测试(一个结点;左右斜树;完全二叉树;普通二叉树)

  2.特殊测试(根结点为null)

Java代码

//题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求
//不能创建任何新的结点,只能调整树中结点指针的指向。public class ConvertBinarySearchTree {public class TreeNode {int val = 0;TreeNode left = null;TreeNode right = null;public TreeNode(int val) {this.val = val;}}public TreeNode convert(TreeNode head) {if(head==null)return head;TreeNode lastNodeInList=null;lastNodeInList=convertHelper(head,lastNodeInList);TreeNode firstNodeInList=lastNodeInList;while(firstNodeInList.left!=null) {firstNodeInList=firstNodeInList.left;}  return firstNodeInList;}//将以node为根结点的树转化为排序链表,链表头部与lastNode链接,并返回最后一个结点private TreeNode convertHelper(TreeNode node,TreeNode lastNode) {//处理左子树,获得最大结点if(node.left!=null)lastNode=convertHelper(node.left, lastNode);//链接最大结点和根结点node.left=lastNode;if(lastNode!=null)lastNode.right=node;//处理右子树lastNode=node;if(node.right!=null)lastNode=convertHelper(node.right, lastNode);return lastNode;}
}

  

上面的代码是参考《剑指OFFER》写的,下面的代码是复习时重新写过的,思路比较简洁一点。非递归方法的核心是中序遍历的非递归实现。

public class Solution {/** 递归版本* 1.已知函数返回的是转换好的双向链表头结点* 2.左子树处理完后与根结点连接* 3.右子树处理,也与根结点连接* 4.最后返回头结点*/public TreeNode Convert(TreeNode root) {if (root == null)return root;// 处理左子树,获得左子树链表的头结点TreeNode left = Convert(root.left);TreeNode p = left;if (left != null) {// 找到左子树链表的末尾结点while (p.right != null)p = p.right;// 连接结点p.right = root;root.left = p;}// 处理右子树,获得右子树链表的头结点TreeNode right = Convert(root.right);// 连接结点if (right != null) {root.right = right;right.left = root;}return left == null ? root : left;}/* 非递归版本* 1.利用非递归中序遍历来连接结点*/public TreeNode Convert1(TreeNode root) {TreeNode head = null;TreeNode pre = null;LinkedList<TreeNode> stack = new LinkedList<>();while (root != null || !stack.isEmpty()) {// 把root当作指针使用while (root != null) {stack.push(root);root = root.left;}TreeNode node = stack.pop();if (head == null) {head = node;pre = node;} else {node.left = pre;pre.right = node;pre = node; // 别漏写了}root = node.right;}return head;}
}

  

收获

  题目较复杂时,不要慌。这道题和中序遍历有关,把树分为三部分:根结点、左子树和右子树,思考在中序遍历中根结点应该如何处理,这是关键——要将左子树的最大结点、根结点、右子树的最小结点链接起来。左右子树的处理是相同的,因此采用递归。

更多:《剑指Offer》Java实现合集  

  

转载于:https://www.cnblogs.com/yongh/p/9860700.html

【Java】 剑指offer(36) 二叉搜索树与双向链表相关推荐

  1. 【LeetCode】剑指 Offer 36. 二叉搜索树与双向链表

    [LeetCode]剑指 Offer 36. 二叉搜索树与双向链表 文章目录 [LeetCode]剑指 Offer 36. 二叉搜索树与双向链表 package offer;//定义节点 class ...

  2. 【LeetCode笔记】剑指 Offer 36. 二叉搜索树与双向链表(Java、二叉树、链表、原地算法)

    文章目录 题目描述 思路 && 代码 1. 非原地算法 2. 原地算法 二刷 题目描述 谈到二叉搜索树,那就得考虑考虑中序遍历啦- 这道题对中序遍历的理解提升很有好处! 思路 & ...

  3. [剑指offer] 36. 二叉搜索树与双向链表

    题目 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表.要求不能创建任何新的节点,只能调整树中节点指针的指向. 需要返回双向链表最左侧的节点. 思路 1 排序链表:利用二叉搜索树的中序遍 ...

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

    1.概述 地址:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof/ /* // De ...

  5. 2021-08-19剑指 Offer 36. 二叉搜索树与双向链表

    我的思路: 前序遍历保证链表的有序性,并且在这个遍历的同时调整指针的指向 class Solution {public:Node* treeToDoublyList(Node* root) {if(r ...

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

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

  7. 剑指offer之二叉搜索树和双向链表

    1 问题 比如我们搜索二叉树如下,我们需要变成双向链表 2 分析 我们知道这个变成双向链接的时候是按照树的中序遍历打印的,我们只需要在中序遍历打印的时候操作该节点,我们可以用临时变量保存这个节点,同时 ...

  8. 剑指offer之二叉搜索树的后序遍历序列

    剑指offer之二叉搜索树的后序遍历序列 欢迎关注作者博客 简书传送门 题目 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则输出Yes,否则输出No.假设输入的数组的任意两个 ...

  9. 【LeetCode】剑指 Offer 33. 二叉搜索树的后序遍历序列

    [LeetCode]剑指 Offer 33. 二叉搜索树的后序遍历序列 文章目录 [LeetCode]剑指 Offer 33. 二叉搜索树的后序遍历序列 package offer;public cl ...

最新文章

  1. ESXI | ESXI6.7如何在网页端添加用户并且赋予不同的权限
  2. kali高速更新源以及主题修改方法
  3. 【Spark 深入学习 04】再说Spark底层运行机制
  4. python学习笔记(七)函数
  5. c语言贪吃蛇运行代码,刚学C语言,想写一个贪吃蛇的代码
  6. 高能!这些段子已刷爆大学老师朋友圈
  7. js实现手机端、pc端相应的跳转
  8. Qt实践|HTTP知识点-使用百度AI语音识别服务
  9. C++ 一个简单的log类的实现
  10. eclipse最新版本photon下载和安装
  11. 【CODE】Longest Substring Without Repeating Characters
  12. 移动应用,让人激动的这些年
  13. cncert网络安全周报35期 境内被植入后门的政府网站112个 环比上涨24.4%
  14. qt 控件设置相对位置_qt设置控件相对位置
  15. MongoDB not authorized for query - code 13 错误解决办法
  16. 为App签名(为apk签名)
  17. Winform从入门到精通(38)——StatusStrip(史上最全)
  18. 北京大学计算机博士金钊,她是北大工科博士生,颜值胜过学霸武亦姝,深受理科男生的喜爱...
  19. LaTex案例——制作三线表
  20. LightGBM: A Highly Efficient Gradient Boosting Decision Tree

热门文章

  1. Linux 查看软件位置的命令
  2. STM32F103xC、STM32F103xD和STM32F103xE增强型模块框图 与 时钟树
  3. STM32中STD、HAL、LL库比较
  4. 谷歌宣布确立“量子霸权” IBM质疑:真的吗?
  5. 使用 TensorFlow 的公司
  6. 深度学习系列之CNN核心内容
  7. 为什么「道理都懂,然而执行力差」的现象如此普遍?
  8. token、cookie是什么
  9. java 获取包名类名_获取指定包名下的所有类的类名(全名)
  10. mysql 开户机构_mysql开户、权限设置、建库流程及常用操作