二叉树笔试题

题目:输入两棵二叉树A和B,判断树B是不是A的子结构
递归判断:如果当前结点值相等,就判断左子树和右子树是否是子结构

bool IsChildTree(Node * father, Node * son)
{
    if(father == NULL && son == NULL)
        return true;

    if(father == NULL && son != NULL)
        return false;

    if(father != NULL && son == NULL)
        return true;

    if(father->data == son->data )
    {
         return IsChildTree(father->left, son->left) && IsChildTree(father->right, son->right);
    }

    if(IsChildTree(father->left, son))
        return true;

    if(IsChildTree(father->right, son))
        return true;

    return false;
}

 

题目:求二叉树中相距最远的两个节点之间的距离
求两节点的最远距离,实际就是求二叉树的直径。本问题可以转化为求“二叉树每个节点的左右子树高度和的最大值”。

int TreeHeight(Node* root, int& max_distance)
{
    if(root == NULL)
    {
        max_distance = 0;
        return 0;
    }

    int left_height,right_height;

    if(root->left)
        left_height = TreeHeight(root->left,max_distance)+1;
    else
        left_height = 0;

    if(root->right)
        right_height = TreeHeight(root->right,max_distance)+1;
    else
        right_height = 0;

    int distance = left_height + right_height;
    if (max_distance < distance) max_distance = distance;

    return (left_height > right_height ? left_height : right_height);
}

int TreeDiameter(Node* root)
{
    int max_distance = 0;
    if(root) TreeHeight(root, max_distance);
    return max_distance;
}

 

题目:求二叉树中节点的最大距离:如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,定义“距离”为两节点之间边的个数。

//结点的定义
typedef struct Node
{
     Node * left;
     Node * right;
     int maxLeft;
     int maxRight;
     char chValue;
}Node,*pNode;

//最大距离
int maxLen = 0;

//寻找二叉树中节点的最大距离
void findMaxLength(Node* root)
{
     if(root == NULL) return;

     //如果左子树为空,则该节点左边最长距离为0 
     if(root->left == NULL)     root->maxLeft = 0;

     //如果右子树为空,则该节点右边最长距离为0 
     if(root->right == NULL)    root->maxRight = 0;

     //如果左子树不为空,递归寻找左边最长距离 
     if(root->left != NULL)     findMaxLength(root->left);

     //如果右子树不为空,递归寻找右边最长距离 
     if(root->right != NULL)    findMaxLength(root->right);

     //计算左子树最长节点距离 
     if(root->left != NULL) 
     {
         int tempMax = 0;
         if(root->left->maxLeft > root->left->maxRight)
           tempMax = root->left->maxLeft;
         else tempMax = root->left->maxRight;
         root->maxLeft = tempMax+1;
     }

     //计算右子树最长节点距离 
     if(root->right != NULL) 
     {
         int tempMax = 0;
         if(root->right->maxLeft > root->right->maxRight)
           tempMax = root->right->maxLeft;
         else tempMax = root->right->maxRight;
         root->maxRight = tempMax+1;
     }

     //更新最长距离 
     if(root->maxLeft+root->maxRight > maxLen)
       maxLen = root->maxLeft+root->maxRight;
}


题目:重建二叉树:通过先序遍历和中序遍历的序列重建二叉树

//通过先序遍历和中序遍历的序列重建二叉树
void ReBuild(char* pPreOrder,char* pInOrder,int nTreeLen,Node** pRoot)
{
     //检查边界条件 
     if(pPreOrder == NULL || pInOrder == NULL)
        return ;

     //获得前序遍历的第一个节点 
     Node* temp = new Node;
     temp->data = *pPreOrder;
     temp->left = NULL;
     temp->right = NULL;

     //如果节点为空,把当前节点复制到根节点 
     if(*pRoot == NULL) *pRoot = temp;

     //如果当前树长为1,那么已经是最后一个节点 
     if(nTreeLen == 1) return;

     //寻找子树长度 
     char* pOrgInOrder = pInOrder;
     char* pLeftEnd = pInOrder;
     int nTempLen = 0;

     //找到左子树的结尾 
     while(*pPreOrder != *pLeftEnd)
     {
       if(pPreOrder == NULL || pLeftEnd == NULL)
          return;
       //记录临时长度,以免溢出 
       nTempLen++;
       if(nTempLen > nTreeLen) break;
       pLeftEnd++;
     }

     //寻找左子树长度 
     int nLeftLen = (int)(pLeftEnd-pOrgInOrder);

     //寻找右子树长度 
     int nRightLen = nTreeLen-nLeftLen-1;

     //重建左子树 
     if(nLeftLen > 0)
       ReBuild(pPreOrder+1,pInOrder,nLeftLen,&((*pRoot)->left));

     //重建右子树 
     if(nRightLen > 0)
       ReBuild(pPreOrder+nLeftLen+1,pInOrder+nLeftLen+1,nRightLen,&((*pRoot)->right));
}

 

题目:寻找最近公共祖先LCA(Lowest Common Ancestor)

Node* getLCA(Node* root,Node* x,Node* y)
{
    if(root == NULL) return NULL;
    if(x == root || y == root) return root;
    Node* pleft = getLCA(root->left,x,y);
    Node* pright = getLCA(root->right,x,y);
    if(pleft == NULL) return pright;
    else if(pright == NULL)return pleft;
    else return root;
}

分别得到根节点root到结点x的路径和到结点y的路径,再比较路径中第一个相同的结点,即是LCA

//得到根节点pHead到pNode的路径
bool GetNodePath(Node* pHead, Node* pNode, std::list<Node*>& path)
{
    if(pHead == pNode)
        return true;

    path.push_back(pHead);

    bool found = false;

    if(pHead->left != NULL)
        found = GetNodePath(pHead->left, pNode, path);

    if(!found && pHead->right)
        found = GetNodePath(pHead->right, pNode, path);

    if(!found)
        path.pop_back();

    return found;
}

题目:寻找二叉搜索树(BST)的最低公共祖先(LCA)
利用BST的性质:从根结点开始搜索,当第一次遇到当前结点的值介于两个给定的结点值之间时,这个当前结点就是要找的LCA

Node* FindLCA(Node* root,int x, int y)
{
    Node * t = root;
    while(1)
    {
        if(t->data > x && t->data > y)
            t = t->left;
        else if(t->data < x && t->data < y)
            t = t->right;
        else return t;
    }
}

 

题目:输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。如果是返回true,否则返回false。
例如输入5、7、6、9、11、10、8,由于这一整数序列是如下树的后序遍历结果,因此返回true。
         8
       /    \
      6     10
     / \       /  \
    5  7  9    11
如果输入7、4、6、5,没有哪棵树的后序遍历的结果是这个序列,因此返回false。
分析:这是一道trilogy的笔试题,主要考查对二元查找树的理解。
在后续遍历得到的序列中,最后一个元素为树的根结点。从头开始扫描这个序列,比根结点小的元素都应该位于序列的左半部分;从第一个大于根节点开始到根结点前面的一个元素为止,所有元素都应该大于根结点,因为这部分元素对应的是树的右子树。根据这样的划分,把序列划分为左右两部分,我们递归地确认序列的左、右两部分是不是都是二元查找树。
参考代码:

///
// Verify whether a squence of integers are the post order traversal
// of a binary search tree (BST)
// Input: squence - the squence of integers
//        length  - the length of squence
// Return: return ture if the squence is traversal result of a BST,
//         otherwise, return false
///
bool verifySquenceOfBST(int squence[], int length)
{
      if(squence == NULL || length <= 0)
            return false;

      // root of a BST is at the end of post order traversal squence
      int root = squence[length - 1];

      // the nodes in left sub-tree are less than the root
      int i = 0;
      for(; i < length - 1; ++ i)
      {
            if(squence[i] > root)
                  break;
      }

      // the nodes in the right sub-tree are greater than the root
      int j = i;
      for(; j < length - 1; ++ j)
      {
            if(squence[j] < root)
                  return false;
      }

      // verify whether the left sub-tree is a BST
      bool left = true;
      if(i > 0)
            left = verifySquenceOfBST(squence, i);

      // verify whether the right sub-tree is a BST
      bool right = true;
      if(i < length - 1)
            right = verifySquenceOfBST(squence + i, length - i - 1);

      return (left && right);
}

 

题目:怎样编写一个程序,把一个有序整数数组放到二叉搜索树中?
分析:本题考察二叉搜索树的建树方法,简单的递归结构。关于树的算法设计一定要联想到递归,因为树本身就是递归的定义。

参考代码:

Node* array_to_tree(int array[],int start,int end)
{
    if (start > end) return NULL;
    int m = start+(end-start)/2;
    Node* root = new Node(array[m]);
    root->left = array_to_tree(array,start,m-1);
    root->right = array_to_tree(array,m+1,end);
    return root;
}

Node* array2Tree(int array[],int n)
{
    return array_to_tree(array,0,n-1);
}

 

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

分析:本题是微软的面试题。很多与树相关的题目都是用递归的思路来解决,本题也不例外。下面我们用两种不同的递归思路来分析。

  思路一:当我们到达某一结点准备调整以该结点为根结点的子树时,先调整其左子树将左子树转换成一个排好序的左子链表,再调整其右子树转换右子链表。最后链接左子链表的最右结点(左子树的最大结点)、当前结点和右子链表的最左结点(右子树的最小结点)。从树的根结点开始递归调整所有结点。

  思路二:我们可以中序遍历整棵树。按照这个方式遍历树,比较小的结点先访问。如果我们每访问一个结点,假设之前访问过的结点已经调整成一个排序双向链表,我们再把调整当前结点的指针将其链接到链表的末尾。当所有结点都访问过之后,整棵树也就转换成一个排序双向链表了。

参考代码:

//定义二元查找树结点的数据结构如下:
    struct BSTreeNode // a node in the binary search tree
    {
        int        m_nValue; // value of node
        BSTreeNode *m_pLeft; // left child of node
        BSTreeNode *m_pRight; // right child of node
    };

//思路一对应的代码:
///
// Covert a sub binary-search-tree into a sorted double-linked list
// Input: pNode - the head of the sub tree
//        asRight - whether pNode is the right child of its parent
// Output: if asRight is true, return the least node in the sub-tree
//         else return the greatest node in the sub-tree
///
BSTreeNode* ConvertNode(BSTreeNode* pNode, bool asRight)
{
      if(!pNode)
            return NULL;

      BSTreeNode *pLeft = NULL;
      BSTreeNode *pRight = NULL;

      // Convert the left sub-tree
      if(pNode->m_pLeft)
            pLeft = ConvertNode(pNode->m_pLeft, false);

      // Connect the greatest node in the left sub-tree to the current node
      if(pLeft)
      {
            pLeft->m_pRight = pNode;
            pNode->m_pLeft = pLeft;
      }

      // Convert the right sub-tree
      if(pNode->m_pRight)
            pRight = ConvertNode(pNode->m_pRight, true);

      // Connect the least node in the right sub-tree to the current node
      if(pRight)
      {
            pNode->m_pRight = pRight;
            pRight->m_pLeft = pNode;
      }

      BSTreeNode *pTemp = pNode;

      // If the current node is the right child of its parent, 
      // return the least node in the tree whose root is the current node
      if(asRight)
      {
            while(pTemp->m_pLeft)
                  pTemp = pTemp->m_pLeft;
      }
      // If the current node is the left child of its parent, 
      // return the greatest node in the tree whose root is the current node
      else
      {
            while(pTemp->m_pRight)
                  pTemp = pTemp->m_pRight;
      }
 
      return pTemp;
}

///
// Covert a binary search tree into a sorted double-linked list
// Input: the head of tree
// Output: the head of sorted double-linked list
///
BSTreeNode* Convert(BSTreeNode* pHeadOfTree)
{
      // As we want to return the head of the sorted double-linked list,
      // we set the second parameter to be true
      return ConvertNode(pHeadOfTree, true);
}

//思路二对应的代码:
///
// Covert a sub binary-search-tree into a sorted double-linked list
// Input: pNode - the head of the sub tree
//       pLastNodeInList - the tail of the double-linked list
///
void ConvertNode(BSTreeNode* pNode, BSTreeNode*& pLastNodeInList)
{
      if(pNode == NULL)
            return;

      BSTreeNode *pCurrent = pNode;

      // Convert the left sub-tree
      if (pCurrent->m_pLeft != NULL)
            ConvertNode(pCurrent->m_pLeft, pLastNodeInList);

      // Put the current node into the double-linked list
      pCurrent->m_pLeft = pLastNodeInList; 
      if(pLastNodeInList != NULL)
            pLastNodeInList->m_pRight = pCurrent;

      pLastNodeInList = pCurrent;

      // Convert the right sub-tree
      if (pCurrent->m_pRight != NULL)
            ConvertNode(pCurrent->m_pRight, pLastNodeInList);
}

///
// Covert a binary search tree into a sorted double-linked list
// Input: pHeadOfTree - the head of tree
// Output: the head of sorted double-linked list
///
BSTreeNode* Convert_Solution1(BSTreeNode* pHeadOfTree)
{
      BSTreeNode *pLastNodeInList = NULL;
      ConvertNode(pHeadOfTree, pLastNodeInList);

      // Get the head of the double-linked list
      BSTreeNode *pHeadOfList = pLastNodeInList;
      while(pHeadOfList && pHeadOfList->m_pLeft)
            pHeadOfList = pHeadOfList->m_pLeft;

      return pHeadOfList;
}
  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值