【剑指Offer学习】【面试题27:二叉搜索树与双向链表】
题目:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建不论什么新的结点。仅仅能调整树中结点指针的指向。
比方输入图4.12 中左边的二叉搜索树,则输出转换之后的排序现向链表。
结点定义:
public static class BinaryTreeNode {
int value;
BinaryTreeNode left;
BinaryTreeNode right;
}
解题思路:
在二叉树中,每个结点都有两个指向子结点的指针。在双向链表中。每个结点也有两个指针,它们分别指向前一个结点和后一个结点。因为这两种结点的结构类似,同一时候二叉搜索树也是一种排序的数据结构,因此在理论上有可能实现二叉搜索树和排序的双向链表的转换。
在搜索二叉树中。左子结点的值总是小于父结点的值。右子结点的值总是大于父结点的值。
因此我们在转换成排序双向链表时,原先指向左子结点的指针调整为链表中指向前一个结点的指针,原先指向右子结点的指针调整为链表中指向后一个结点指针。接下来我们考虑该怎样转换。
因为要求转换之后的链表是排好序的。我们能够中序遍历树中的每个结点, 这是因为中序遍历算法的特点是依照从小到大的顺序遍历二叉树的每个结点。当遍历到根结点的时候,我们把树看成三部分:值为10 的结点、根结点值为6 的左子树、根结点值为1 4 的右子树。
依据排序链表的定义。值为10 的结点将和它的左子树的最大一个结点(即值为8 的结点)链接起来。同一时候它还将和右子树最小的结点(即值为12 的结点)链接起来。如图4.13 所看到的。
依照中序遍历的顺序, 当我们遍历转换到根结点(值为10 的结点)时,它的左子树已经转换成一个排序的链表了, 而且处在链表中的最后一个结点是当前值最大的结点。
我们把值为8 的结点和根结点链接起来,此时链表中的最后一个结点就是10 了。
接着我们去地历转换右子树, 并把根结点和右子树中最小的结点链接起来。至于怎么去转换它的左子树和右子树,因为遍历和转换过程是一样的。我们非常自然地想到能够用递归。
代码实现:
public class Test27 {
/**
* 二叉树的树结点
*/
public static class BinaryTreeNode {
int value;
BinaryTreeNode left;
BinaryTreeNode right;
}
/**
* 题目:输入一棵二叉搜索树。将该二叉搜索树转换成一个排序的双向链表。
* 要求不能创建不论什么新的结点,仅仅能调整树中结点指针的指向。
*
* @param root 二叉树的根结点
* @return 双向链表的头结点
*/
public static BinaryTreeNode convert(BinaryTreeNode root) {
// 用于保存处理过程中的双向链表的尾结点
BinaryTreeNode[] lastNode = new BinaryTreeNode[1];
convertNode(root, lastNode);
// 找到双向链表的头结点
BinaryTreeNode head = lastNode[0];
while (head != null && head.left != null) {
head = head.left;
}
return head;
}
/**
* 链表表转换操作
*
* @param node 当前的根结点
* @param lastNode 已经处理好的双向链表的尾结点。使用一个长度为1的数组,类似C++中的二级指针
*/
public static void convertNode(BinaryTreeNode node, BinaryTreeNode[] lastNode) {
// 结点不为空
if (node != null) {
// 假设有左子树就先处理左子树
if (node.left != null) {
convertNode(node.left, lastNode);
}
// 将当前结点的前驱指向已经处理好的双向链表(由当前结点的左子树构成)的尾结点
node.left = lastNode[0];
// 假设左子树转换成的双向链表不为空,设置尾结点的后继
if (lastNode[0] != null) {
lastNode[0].right = node;
}
// 记录当前结点为尾结点
lastNode[0] = node;
// 处理右子树
if (node.right != null) {
convertNode(node.right, lastNode);
}
}
}
public static void main(String[] args) {
test01();
test02();
test03();
test04();
test05();
}
private static void printList(BinaryTreeNode head) {
while (head != null) {
System.out.print(head.value + "->");
head = head.right;
}
System.out.println("null");
}
private static void printTree(BinaryTreeNode root) {
if (root != null) {
printTree(root.left);
System.out.print(root.value + "->");
printTree(root.right);
}
}
// 10
// / \
// 6 14
// /\ /\
// 4 8 12 16
private static void test01() {
BinaryTreeNode node10 = new BinaryTreeNode();
node10.value = 10;
BinaryTreeNode node6 = new BinaryTreeNode();
node6.value = 6;
BinaryTreeNode node14 = new BinaryTreeNode();
node14.value = 14;
BinaryTreeNode node4 = new BinaryTreeNode();
node4.value = 4;
BinaryTreeNode node8 = new BinaryTreeNode();
node8.value = 8;
BinaryTreeNode node12 = new BinaryTreeNode();
node12.value = 12;
BinaryTreeNode node16 = new BinaryTreeNode();
node16.value = 16;
node10.left = node6;
node10.right = node14;
node6.left = node4;
node6.right = node8;
node14.left = node12;
node14.right = node16;
System.out.print("Before convert: ");
printTree(node10);
System.out.println("null");
BinaryTreeNode head = convert(node10);
System.out.print("After convert : ");
printList(head);
System.out.println();
}
// 5
// /
// 4
// /
// 3
// /
// 2
// /
// 1
private static void test02() {
BinaryTreeNode node1 = new BinaryTreeNode();
node1.value = 1;
BinaryTreeNode node2 = new BinaryTreeNode();
node2.value = 2;
BinaryTreeNode node3 = new BinaryTreeNode();
node3.value = 3;
BinaryTreeNode node4 = new BinaryTreeNode();
node4.value = 4;
BinaryTreeNode node5 = new BinaryTreeNode();
node5.value = 5;
node5.left = node4;
node4.left = node3;
node3.left = node2;
node2.left = node1;
System.out.print("Before convert: ");
printTree(node5);
System.out.println("null");
BinaryTreeNode head = convert(node5);
System.out.print("After convert : ");
printList(head);
System.out.println();
}
// 1
// \
// 2
// \
// 3
// \
// 4
// \
// 5
private static void test03() {
BinaryTreeNode node1 = new BinaryTreeNode();
node1.value = 1;
BinaryTreeNode node2 = new BinaryTreeNode();
node2.value = 2;
BinaryTreeNode node3 = new BinaryTreeNode();
node3.value = 3;
BinaryTreeNode node4 = new BinaryTreeNode();
node4.value = 4;
BinaryTreeNode node5 = new BinaryTreeNode();
node5.value = 5;
node1.right = node2;
node2.right = node3;
node3.right = node4;
node4.right = node5;
System.out.print("Before convert: ");
printTree(node1);
System.out.println("null");
BinaryTreeNode head = convert(node1);
System.out.print("After convert : ");
printList(head);
System.out.println();
}
// 仅仅有一个结点
private static void test04() {
BinaryTreeNode node1 = new BinaryTreeNode();
node1.value = 1;
System.out.print("Before convert: ");
printTree(node1);
System.out.println("null");
BinaryTreeNode head = convert(node1);
System.out.print("After convert : ");
printList(head);
System.out.println();
}
// 没有结点
private static void test05() {
System.out.print("Before convert: ");
printTree(null);
System.out.println("null");
BinaryTreeNode head = convert(null);
System.out.print("After convert : ");
printList(head);
System.out.println();
}
}
执行结果:
【剑指Offer学习】【面试题27:二叉搜索树与双向链表】的更多相关文章
- 《剑指offer》面试题27 二叉搜索树与双向链表 Java版
(将BST改成排序的双向链表.) 我的方法一:根据BST的性质,如果我们中序遍历BST,将会得到一个从小到大排序的序列.如果我们将包含这些数字的节点连接起来,就形成了一个链表,形成双向链表也很简单.关 ...
- 《剑指offer》面试题36. 二叉搜索树与双向链表
问题描述 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表.要求不能创建任何新的节点,只能调整树中节点指针的指向. 为了让您更好地理解问题,以下面的二叉搜索树为例: 我们希望将这个二叉搜 ...
- 《剑指offer》面试题24 二叉搜索树的后序遍历序列 Java版
(判断一个元素均不相同的序列是否为一个BST的LRD) 书中方法:首先对于二叉搜索树,左子树中的所有元素小于根节点小于右子树中的所有元素,然后后序遍历序列最后一个元素是根节点,这是我们已知的条件.这道 ...
- 《剑指offer》面试题33. 二叉搜索树的后序遍历序列
问题描述 输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历结果.如果是则返回 true,否则返回 false.假设输入的数组的任意两个数字都互不相同. 参考以下这颗二叉搜索树: 5 / \ ...
- 《剑指offer》面试题54. 二叉搜索树的第k大节点
问题描述 给定一棵二叉搜索树,请找出其中第k大的节点. 示例 1: 输入: root = [3,1,4,null,2], k = 1 3 / \ 1 4 \ 2 输出: 4 示例 2: 输入: ...
- 剑指Offer:面试题27——二叉搜索树与双向链表(java实现)
问题描述: 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. 思路: 将树分为三部分:左子树,根结点,右子树. 1.我们要把根结点与左 ...
- (剑指Offer)面试题27:二叉搜索树与双向链表
题目: 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. 二叉树的定义如下: struct TreeNode{ int val; Tr ...
- 【剑指offer】面试题27:二叉搜索树与双向链表
题目: 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表.要求不能创建任何新的结点,只能调整树中结点指针的指向. 思路: 假设已经处理了一部分(转换了左子树),则得到一个有序的双向链表,现在 ...
- 剑指offer——27. 二叉搜索树与双向链表(Java版)
题目: 剑指offer的题目有挺多都挺典型的,就像这一道.不过书中的代码写的真是ugly,有很多题目LeetCode上都有,可以去LeetCode讨论区看看,经常有一些大神分享,写的代码真是高效.简洁 ...
- 剑指offer 27二叉搜索树与双向链表
class Solution { public: void ConvertNode(TreeNode* pRootOfTree,TreeNode** pre) { if(pRootOfTree) { ...
随机推荐
- nodejs简介
1.Node.js是什么? Node.js不是一种独立的语言,与PHP.java..net即是开发语言也是平台不同,也不是javaScript的框架 jquery,更不是浏览器的库ExtJs,能不与E ...
- spark pipeline 例子
""" Pipeline Example. """ # $example on$ from pyspark.ml import Pipeli ...
- 基于深度学习的病毒检测技术无需沙箱环境,直接将样本文件转换为二维图片,进而应用改造后的卷积神经网络 Inception V4 进行训练和检测
话题 3: 基于深度学习的二进制恶意样本检测 分享主题:全球正在经历一场由科技驱动的数字化转型,传统技术已经不能适应病毒数量飞速增长的发展态势.而基于沙箱的检测方案无法满足 APT 攻击的检测需求,也 ...
- 7.stack
#include <iostream> #include <stack> #include <algorithm> #include <list> #i ...
- 【DNN 系列】 DNN是什么
DNN平台 这个DNN平台是一个开放的.可扩展的.安全的.可扩展的内容管理系统和ASP.NET.世界各地的数十万商户,从地方小企业到全球1000强企业,取决于DNN平台作为他们网站的编辑环境. 这个网 ...
- Linux企业运维人员最常用150个命令汇
近来老男孩发现新手学习Linux记不住命令,不会分类.不会筛选重点,胡子眉毛一把抓当然记不住了. 特别整理Linux运维最常用150个命令和大家分享,大家学习命令不用在盲目了,根据分类,然后逐步学习! ...
- php八大设计模式之单例模式
单例模式的好处: 实例化后只得到一个对象,减少内存的开销. 实现单例模式: 提供一个私有的属性用来存储实例后的对象. 禁止外部实例化对象,提供公共的的方法,返回实例化后的对象. 避免继承此类,然后重写 ...
- DedeCMS筛选简单实现方法不改后台源文件
笔者在前面几篇文章中提到的dedecms筛选的实现方法,对新手来说实现过程较复杂.接下来分享一个最简单的实现在移动端上筛选功能. 最近在筹备移动端企业站,实现功能有:实现一个管理后台管理PC端和移动端 ...
- lhgDialog使用--loading提示(不自动关闭)
使用lhgDialog时,发现有一个$.dialog.tips()方法可以实现loading样式的提示,但是存在默认关闭时间.方法如下图所示, 为了实现不自动关闭的方法,查看了相应的源码后,实现不关闭 ...
- info---Linux下info格式的帮助指令。
info命令是Linux下info格式的帮助指令. 它的几个常用快捷键. ?键:它就会显示info的常用快捷键. N键:显示(相对于本节点的)下一节点的文档内容. P键:显示(相对于本节点的)前一节点 ...