微软面试100题系列-第1题

来源:互联网 发布:微博桌面2015网络异常 编辑:程序博客网 时间:2024/05/16 19:25
注:微软面试100题系列中的题都是v_JULY_v(http://blog.csdn.net/v_JULY_v)收集的面试题,具体PDF下载地址为:http://download.csdn.net/detail/v_july_v/4583815

                写文的目的是锻炼自己,欢迎各位大牛提出建议,批评指正~

第一题:把二分查找树转变成排序的双向链表

输入一棵二分查找树,将该二分查找树转换成一个排序的双向链表。要求不能创建任何新的结点,只调整指针的指向。如:
                                                 

                                                        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
};

 

我的解题思路如下:

      本题中不能建立新的结点,只能改变指针的指向。先观察根结点,根据二叉查找树的特点,可以发现根结点的左指针应该指向左子树双向链表的尾部,而根结点的右指针

应该指向右子树双向链表的头部。因此该问题可以递归为求解左、右孩子的双向链表。求解完左、右孩子的双向链表后,再接上根结点,即可完成对双向链表的求解。

     根据上述思路,先来看一下代码结构,之后会有例子讲解。

      编写如下的递归函数:

      void ConvertRecursive(BSTNode* &subHead, BSTNode* &subTail, BSTNode* subRoot)

      然后在函数中求解左、右孩子的双向链表:

      BSTNode *leftTail = NULL, *rightHead = NULL;

      ConvertRecursive(subHead,leftTail,subRoot->pLeft);  //求解左子的链表

      ConvertRecursive(rightHead,subTail,subRoot->pRight);  //求解右子的链表

      。。。。。。 //将左子链表、根、右子链表连接起来

      这个递归初看可能有点不清晰,我们可以先看一下求解左子链表的语句:

      ConvertRecursive(subHead,leftTail,subRoot->pLeft);   

       这个subHead可看成是当前链表的头,在递归结束后,最上一层的subHead将是整个双向链表的头。而leftTail是我们想要的左孩子双向链表的尾部。

       ConvertRecursive(rightHead,subTail,subRoot->pRight); 

       rightHead是我们想要的右孩子双向链表的头部,而subTail可看成是当前链表的尾,在递归结束后,最上一层的subTail将是整个双向链表的尾。

       现在看一下左子链表、根与右子链表连接的操作:如果左子没有双向链表,那么根结点就成为当前链表的头;如果有,根结点就连接上左子链表的尾部。

       同理,如果右子没有链表,那么根结点就成为当前链表的尾;如果有,则根结点与右子链表的头部相连接。

//连接左子链表与根
  if (leftTail == NULL)  //左子没有双向链表
  {
       subHead = subRoot;
  }
  else
  {
      leftTail->pRight = subRoot;
      subRoot->pLeft = leftTail;
  }

  //连接右子链表与根
  if (rightHead == NULL) //右子没有双向链表
  {
      subTail = subRoot;
  }
  else
  {
      subRoot->pRight = rightHead;
      rightHead->pLeft = subRoot;
  }

         以子树        6                   为例,

                          /        \

                       4           8

         递归到4时,因为4是叶子结点,其左、右子树链表为空,则有subHead -> 4, subTail -> 4。同理8也是这种情况。

         返回到6的调用,因为6调用4的递归中,形参subTail实际上是实参leftTail的引用,因此6的左子链表leftTail->4不为空,按照之前的思路,我们可以将结点6与左子链表连

接起来,就有了链表4=6;同理,在6调用8的递归中,形参subHead实际上是实参rightHead的引用,因此6的右子链表rightHead->8也不为空,将6与右子链表连接起来,我们

有了双向链表4=6=8,而此时当前链表的subHead->4,subTail->8。

由此,可以看出整个递归过程中,leftTail和rightHead起到了连接整个链表中间结点的作用,而subHead和subTail则保存了目前递归层次中的最小和最大值。

         完整的代码如下,因为自己有一个BST树结点的模板类,所以直接拿来用了,BSTNode<int>和题目中的BSTreeNode的结构是一样的。

//written by zero#include "BST.h"#include <iostream>using namespace std;void ConvertRecursive(BSTNode<int>* &subHead, BSTNode<int>* &subTail, BSTNode<int>* subRoot){ BSTNode<int> *leftTail = NULL, *rightHead = NULL; if (subRoot == NULL) { subHead = NULL; subTail = NULL; return; } ConvertRecursive(subHead,leftTail,subRoot->pLeft);  //求解左子的链表 ConvertRecursive(rightHead,subTail,subRoot->pRight);  //求解右子的链表 //将左子链表,根,右子链表接在一起 //连接左子链表与根 if (leftTail == NULL)  //左子没有双向链表 { subHead = subRoot; } else { leftTail->pRight = subRoot; subRoot->pLeft = leftTail; } //连接右子链表与根 if (rightHead == NULL) //右子没有双向链表 { subTail = subRoot; } else { subRoot->pRight = rightHead; rightHead->pLeft = subRoot; }}int main(){//建立二叉查找树BSTree<int> tree;tree.Insert(10);tree.Insert(6);tree.Insert(14);tree.Insert(4);tree.Insert(8);tree.Insert(12);tree.Insert(16);/*tree.TravelRecursive(&BSTree<int>::PosOderRecursive,&BSTree<int>::process);cout << endl;tree.TravelRecursive(&BSTree<int>::PosOderNonRecursive,&BSTree<int>::process);cout << endl;*///转换成双向链表BSTNode<int> *head = NULL, *tail = NULL, *pNode;ConvertRecursive(head,tail,tree.root);//验证正向遍历双向链表cout << "正向遍历链表:";pNode = head;while(pNode){cout << pNode->value << " ";pNode = pNode->pRight;}cout << endl;//验证逆向遍历双向链表cout << "逆向遍历链表:";pNode = tail;while(pNode){cout << pNode->value << " ";pNode = pNode->pLeft;}cout << endl;}


运行结果如下:

原创粉丝点击