此题为July在CSDN发布的微软编程面试100题中的第一题,觉得蛮有趣的,今天也拿过来玩玩,July的代码用的是C++实现,可能因为有指针的原因吧,感觉看起来相对比较容易理解整个的实现过程,而我,试着用C#完成这样的功能。

完整的题目如下:

把二元查找树转变成排序的双向链表,要求不能创建任何新的结点,只调整指针的指向。

10

/   \

6    14

/ \    / \
4 8  12 16

转换成双链表  4=6=8=10=12=14=16

动手编码之前,先回顾下二叉查找树的特点:任意节点的左子树都要小于当前节点,右子树都要大于当前节点。查询某个值,需要的时间复杂度为O(lgN)

现在要求将其由树状结构改造成线性结构的双向链表,重点在于,获得当前节点左子树范围内最右节点(也是左子树最大值节点),以及右子树范围内最左节点(也是右子树最小值节点),然后,调整这两个节点当前节点左右顺序。即调整8、10之间和12、10之间的关系。

算法思路:

  1. 树根节点,分左右子树。先将当前节点左子树范围内最右节点leftR找出来,再将右子树范围内最左节点rightL找出来(这两步放在一开始,因为此时左右子树内的关系还没改变,先取出来,时间消耗O(lgN)。只是查找到节点,空间上只用到一个索引,不会产生新的内存分配)。
  2. 若左子树为叶子节点,则直接设置其右向索引指向其父节点,左向递归结束;否则,将此节点作为根节点,递归调用第一步。
  3. 若右子树为叶子节点,则直接设置其左向索引指向其父节点,右向递归结束,否则,将此节点作为根节点,递归调用第一步。
  4. 设置根节点的左向节点为leftR,leftR的右向节点为根节点(其左向节点,在b和c两步的递归过程中已经赋值),设置根节点的右向节点为rightL,rightL的左向节点为根节点(其右向节点,在b和c两步的递归过程中已经赋值)

C#源码部分:

首先定义根节点和左右子树节点:

        private int value;
private MyLinkedNode left;
private MyLinkedNode right; public MyLinkedNode(int value)
{
this.value = value;
} public MyLinkedNode Left
{
get { return this.left; }
set { this.left = value; }
} public MyLinkedNode Right
{
get { return this.right; }
set { this.right = value; }
}

以下代码为逻辑递归代码:

        private static void ProcessTreeToLinked(MyLinkedNode node)
{
if (null==node)
{
return;
} //获取左子树的最右节点
MyLinkedNode leftR = getMostRightNode(node.Left); //获取右子树的最左节点
MyLinkedNode rightL = getMostLeftNode(node.Right); //左子树非空,递归处理左子树
if (null == node.Left)
{
ProcessLeftNode(node.Left, node);
} //若右子树非空,递归处理右子树
if (null == node.Right)
{
ProcessRightNode(node.right, node);
} //若左子树最右节点非空,调整与根节点相邻
if (null != leftR)
{
leftR.Right = node;
node.Left = leftR;
} //若右子树的最左节点非空,调整与根节点相邻
if (null != rightL)
{
rightL.Left = node;
node.Right = rightL;
}
} private static void ProcessRightNode(MyLinkedNode right, MyLinkedNode node)
{
//若右子树为叶子节点,直接将其左向索引指向父节点,并返回
if (isLeafNode(right))
{
right.Left = node;
return;
} ProcessTreeToLinked(right);
} private static void ProcessLeftNode(MyLinkedNode left, MyLinkedNode node)
{
//若左子树为叶子节点,直接将其右向索引指向父节点,并返回
if (isLeafNode(left))
{
left.Right = node;
return;
} //本节点当作根节点,递归调用
ProcessTreeToLinked(left);
} private static bool isLeafNode(MyLinkedNode node)
{
return (null == node.Left) && (null == node.Right);
} private static MyLinkedNode getMostLeftNode(MyLinkedNode right)
{
if (null == right)
{
return null;
} if (null == right.Left)
{
return right;
} return getMostLeftNode(right.Left);
} private static MyLinkedNode getMostRightNode(MyLinkedNode left)
{
if (null==left)
{
return null;
} if (null==left.Right)
{
return left;
} return getMostRightNode(left.Right);
}

  

编写这段代码其实不难,难的是如何理清楚解题思路。权当为接下来的面试做准备了,上次面试被问到要实现String.Replace()方法,却不能调用API,不得不说,作为一名测试人员,这样的编码难度对我来说还是比较大的,但并非不可克服,只是,需要继续努力提升自己~轻轻地,对自己说一声,加油~

二元查找树转变成排序的双向链表之C#算法实现的更多相关文章

  1. MS - 1 - 把二元查找树转变成排序的双向链表

    ## 1. 把二元查找树转变成排序的双向链表 ## ### 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表. ### 要求不能创建任何新的结点,只调整指针的指向. 10       ...

  2. 【Data structure & Algorithm】把二元查找树转变成排序的双向链表

    把二元查找树转变成排序的双向链表 题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表,要求不能创建任何新节点,只调整指针指向. 比如将二元查找树 10 /       \ 6       ...

  3. 1.把二元查找树转变成排序的双向链表[BST2DoubleLinkedList]

    [题目]:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表.要求不能创建任何新的结点,只调整指针的指向. 比如将二元查找树 . 10 / \ 6 14 / \ / \ 4 8 12 16 转 ...

  4. IT公司100题-15-求二元查找树的镜像

    问题描述: 输入一颗二元查找树,将该树转换为它的镜像树,即对每一个节点,互换左右子树.   例如输入:   6/    \4     12/ \   /   \2  5 8   16 输出:   6/ ...

  5. IT公司100题-9-判断整数序列是不是二元查找树的后序遍历结果

    问题描述: 输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果. 如果是返回true,否则返回false. 例如输入4, 8, 6, 12, 16, 14, 10,由于这一整数序列是如下树 ...

  6. 6.二元查找树的后序遍历结果[PostOrderOfBST]

    [题目] 输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果.如果是返回true,否则返回false. 例如输入5.7.6.9.11.10.8,由于这一整数序列是如下树的后序遍历结果: 8 ...

  7. 11.求二元查找树的镜像[MirrorOfBST]

    [题目] 输入一颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的结点都大于右子树的结点.用递归和循环两种方法完成树的镜像转换. 例如输入: 8    /  \  6      1 ...

  8. 数据结构:JAVA_二叉数查找树基本实现(上)

    数据结构:二叉数查找树基本实现(JAVA语言版) 1.写在前面 二叉查找树是一种能将链表插入的灵活性与有序数组查找的高效性结合在一起的一种数据结构. ..... 2.代码分解 2.1 对节点的结构定义 ...

  9. 【查找结构5】多路查找树/B~树/B+树

    在前面专题中讲的BST.AVL.RBT都是典型的二叉查找树结构,其查找的时间复杂度与树高相关.那么降低树高自然对查找效率是有所帮助的.另外还有一个比较实际的问题:就是大量数据存储中,实现查询这样一个实 ...

随机推荐

  1. 使用LotusScript操作Lotus Notes RTF域

    Lotus Notes RTF域的功能也非常强大,除了支持普通的文本以外,还支持图片.表格.嵌入对象.Http 链接.Notes 链接.附件等等众多的类型.本文将介绍如何使用这些类来灵活操作富文本域. ...

  2. gradle介绍

    Gradle是什么? https://gradle.org/whygradle-build-automation/ 自动化编译的工具,可编程,适合各种语言,管理各种依赖,高效,提供分析报告. 我个人觉 ...

  3. POJ-1475-Pushing Boxes(BFS)

    Description Imagine you are standing inside a two-dimensional maze composed of square cells which ma ...

  4. JAVA本地远程连接linux程序监控状态

    环境:  1.本地window 2.程序部署在centos   一,启动访问权限安全守护程序 新建文件:jstatd.all.policy ,注意路径 grant codebase "$JA ...

  5. CSS-JQUERY笔记

    Ready $(document).ready(function(){ }) Input_div_span Input-长度限制 <input maxLength="2"&g ...

  6. iOS8中使用CoreLocation定位[转]

    本文转自:http://blog.devzeng.com/blog/ios8-corelocation-framework.html iOS8以前使用CoreLocation定位 1.首先定义一个全局 ...

  7. [Z] 关于c++ typename的另一种用法

    在看c++ primer的时候见到了一下这种用法: typedef typename std::vector<int>::size_type size_type; 觉得这里面的typena ...

  8. JavaScript - javascript 中的 "||" 与 "&&" 的理解与灵活运

    你肯定见到过这样的代码:a = a||"xxx". 它其实就等价于下面三种形式的代码: a = a || "xxx"; 与: if (!a) { a = &qu ...

  9. tengine + mysql + nginx + php

    tengine + mysql + nginx + php 1.配置防火墙vim /etc/sysconfig/iptables # 允许80端口通过防火墙-A INPUT -m state --st ...

  10. ps裁剪圆角

    1.打开要编辑的图片 2.选择圆角矩形工具,并调整半径(半径越大,角越圆),本例半径为20像素 3.使用上述工具画出选区 4.按下ctrl+enter,可以看到选区边缘描上了虚线 5.菜单栏-图像-剪 ...