此题为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. jackson 注脚学习参考

    (1)初级我们从几个简单的使用场景开始:重命名属性,忽略属性,以及修改属性所使用的类型.注意:下面的例子仅仅显示了成员属性(field properties),注解同样也可以用在成员方法(getter ...

  2. Web app 的性能瓶颈与性能调优方法

    1. web app 性能测试工具使用 2. mysql 性能分析与调优方法

  3. Mac 下安装mitmproxy

    环境:  Mac OS X 10.9.4 1. 安装 直接用pip 安装 pip install mitmproxy 发现在安装依赖包 lxml 的时候报错 In : /private/tmp/pip ...

  4. C#判断一个string是否为数字

    案一:Try...Catch(执行效率不高) private bool IsNumberic(string oText) { try { int var1=Convert.ToInt32 (oText ...

  5. 日常工作中的点滴总结from 2014-03

    一 关于 写方案: 写某个产品的方案基本应包括以下几点: 1产品目前现状(国内外)  2产品意义.作用 3产品架构 4产品优势 5产品功能讲解 二 关于 处理下属工作方向不正确的事务 首先 先肯定 下 ...

  6. sudo 使用不了, the permissions on the /etc/sudoers file are changed to something other than 0440

    sudo 使用不了,报错: the permissions on the /etc/sudoers file are changed to something other than 0440 how ...

  7. android 开发 - 使用okhttp框架封装的开发框架

    概述 在android开发中经常要访问网络,目前最流行的网络访问框架就是Okhttp了,然而我们在具体使用时,往往仍然需要二次封装.我使用Builder设计模式进行了封装形成oknet开源库. 介绍 ...

  8. BugFixed

  9. POJ 3320 Jessica's Reading Problem

    Jessica's Reading Problem Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6001   Accept ...

  10. Ubuntu下的杀毒

      Ubuntu 11.04 杀毒软件ESET NOD32   Linux防病毒,并不代表没有病毒,只是数量过少.因技术精英发现漏洞后即时打补丁,病毒很少. 有兴趣的同学可以尝试下Ubuntu 11. ...