聲明:題目來自: 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);
}
}