声明:题目来自: http://blog.csdn.net/v_JULY_v/archive/2010/11/17/6015165.aspx JULY整理了100道微软等公司的面试题目,我想先不看答案:http://blog.csdn.net/v_JULY_v/archive/2011/01/10/6126406.aspx 自己先做一遍。
题目:
1. 把二元查找树转变成排序的双向链表
题目:
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不能创建任何新的结点,只调整指针的指向。
10
/ /
6 14
/ / / /
4 8 12 16
转换成双向链表
4=6=8=10=12=14=16。
首先我们定义的二元查找树 节点的数据结构如下:
struct BSTreeNode
{
int m_nValue; // value of node
BSTreeNode *m_pLeft; // left child of node
BSTreeNode *m_pRight; // right child of node
};
思路:
看一下输出的双向链表,他的顺序和二元查找树的先序遍历的顺序是一致的,所以一开始我的思路就是用先序遍历来解这个问题。既然是递归,那么问题肯定能转换成,要把 节点parent之下(包括节点parent)所代表的二叉树转变成双向链表,我们认为parent的left child 和 right child都已经是转换好的 双向链表了,所以伪代码是:
preOrderTransform(Parent A)
{
preOrderTransform(Left Child of Parent A);
preOrderTransform(Right Child of Parent A);
把 1)左儿子中最大节点, 2)当前Parent节点 ,3)还有 右儿子的最小节点 链接起来
}
直观的思路就是 让preOderTransform(leftChild) 返回左儿子中最大的节点;让preOrderTransform(rightChild)返回右儿子中最小的节点。但是 问题是: 当parent A所管理的数转换好以后,它可以作为祖父节点B 的左字数,也有可能作为祖父节点B 的右字数,如果作为B的左子树,B需要知道A的最大节点,但是处理A的 preOrderTransform(Parent A) 目前并不知道它麾下最大的节点是谁,除非1) 它向右遍历 (因为这时候A麾下已经是双向链表,我们可以通过 node=node->m_right 一直找到最右边的,也就是最大的节点);或者2) 我们想办法让A 记住自己的最小和最大节点。
我下面的代码采用了“记住”的方法:
代码:
class BSTreeNode{
int m_nValue;
BSTreeNode m_left;
BSTreeNode m_right;
BSTreeNode(int value){
m_nValue = value;
}
}
public class BinaryTree2DoubleLink {
static class Result{
BSTreeNode head;
BSTreeNode tail;
public Result(BSTreeNode head, BSTreeNode tail){
this.head = head;
this.tail = tail;
}
}
BSTreeNode buildTree(){
BSTreeNode root = new BSTreeNode(10);
root.m_left = new BSTreeNode(6);
root.m_right = new BSTreeNode(14);
BSTreeNode node = root.m_left;
node.m_left = new BSTreeNode(4);
node.m_right = new BSTreeNode(8);
node = root.m_right;
node.m_left = new BSTreeNode(12);
node.m_right = new BSTreeNode(16);
return root;
}
//
Result preOrder(BSTreeNode node){
Result result = new Result(node, node);
if(node == null ){
return result;
}
//let's make left child a double linked list
//leftResult remember the head and tail of the new double linked list
Result leftResult = preOrder(node.m_left);
//let's make right child a double linked list
Result rightResult = preOrder(node.m_right);
//link current node with the tail node of left child linked list
if(leftResult.tail != null){ //注意边界条件
leftResult.tail.m_right = node;
}
node.m_left = leftResult.tail;
//link current node with the head node of right child linked list
if(rightResult.head != null){
rightResult.head.m_left = node;
}
node.m_right = rightResult.head;
//modify the result after merge current node with both it's left child and right child
if(leftResult.head != null){ //注意边界条件
result.head = leftResult.head;
}
if(rightResult.tail != null){
result.tail = rightResult.tail;
}
return result;
}
Result transform(BSTreeNode root){
BSTreeNode head = null;
Result result = preOrder(root);
//the order of double linked list is actually the order of pre-order traverse
return result;
}
void print(Result result){
//print from head
BSTreeNode node = result.head;
while(node != null){
System.out.format("%2d ", node.m_nValue);
node = node.m_right;
}
System.out.println();
node = result.tail;
while(node != null){
System.out.format("%2d ", node.m_nValue);
node = node.m_left;
}
System.out.println();
}
public static void main(String[] args){
BinaryTree2DoubleLink app = new BinaryTree2DoubleLink();
BSTreeNode root = app.buildTree();
Result result = app.transform(root);
app.print(result);
}
}