面试类二叉树题目汇总

来源:互联网 发布:淘宝一件代发是真的吗 编辑:程序博客网 时间:2024/06/05 17:16

目录:

1 求二叉树节点个数

2.1 求二叉树的深度

2.2 判断二叉树是否是平衡树

3  二叉树转化为双向链表

4 二叉树的镜像

5 输入一行整数,判断是不是二叉搜索树的后序遍历?假设输入的任意两个数字均不相同。

6  二叉树中和为某一值的路径。

7  数中两个结点的公共祖先之求从根节点分别到某个节点的路径。

8 输入两棵二叉树A和B, 判断B是不是A的子结构。

9.1递归前中后遍历二叉树

9.2 非递归前中后遍历二叉树

9.3 二叉树DFS BFS

10 求二叉树第K层节点个数

11 求二叉树叶结点个数

12 求二叉树中节点的最大距离

13判断一棵树是否是完全二叉树

14 重建二叉树(剑指offr T6)




struct BinaryTreeNode

{
    int m_nValue;
    BinaryTreeNode *m_pLeft;
    BinaryTreeNode *m_pRight;
};



1 求二叉树节点个数

int GetNodeNum(BinaryTreeNode *pRoot)
{
    if (pRoot == NULL)
        return 0;
    else
        return (GetNodeNum(pRoot->m_pLeft) + GetNodeNum(pRoot->m_pRight) + 1);

}


2.1 求二叉树的深度

int TreeDepth(BinaryTreeNode *pRoot)
{
    if (pRoot == NULL)
        return 0;
    int nLeft = TreeDepth(pRoot->m_pLeft);
    int nRight = TreeDepth(pRoot->m_pRight);
    return  (nLeft > nRight) ? (nLeft + 1) : (nRight+1);

}

2.2 判断二叉树是否是平衡树

方法1

bool IsBalanced(BinaryTreeNode *pRoot)
{
    if (pRoot == NULL)
        return true;
    int Left = TreeDepth(pRoot->m_pLeft);
    int Right = TreeDepth(pRoot->m_pRight);
    int diff = Left - Right;
    if (diff < -1 || diff > 1)
        return false;
    return IsBalanced(pRoot->m_pLeft) && IsBalanced(pRoot->m_pRight);
}

方法2


bool IsBalanced1(BinaryTreeNode *pRoot, int &len)
{
    if (pRoot == NULL)
    {
        len = 0;
        return true;
    }
    int left, right;
    if (IsBalanced1(pRoot->m_pLeft, left) && IsBalanced1(pRoot->m_pRight, right))
    {
        int diff = left - right;
        if (diff >= -1 && diff <= 1)
        {
            len = (left > right) ? (left + 1) : (right + 1);
            return true;
        }    
    }
    return false;
}

3  二叉树转化为双向链表

方法1

void ConvertNode(BinaryTreeNode* pNode, BinaryTreeNode** pLastNodeInList);

BinaryTreeNode* Convert(BinaryTreeNode* pRootOfTree)
{
    BinaryTreeNode *pLastNodeInList = NULL;
    ConvertNode(pRootOfTree, &pLastNodeInList);

    // pLastNodeInList指向双向链表的尾结点,
    // 我们需要返回头结点
    BinaryTreeNode *pHeadOfList = pLastNodeInList;
    while(pHeadOfList != NULL && pHeadOfList->m_pLeft != NULL)
        pHeadOfList = pHeadOfList->m_pLeft;

    return pHeadOfList;
}

void ConvertNode(BinaryTreeNode* pNode, BinaryTreeNode** pLastNodeInList)
{
    if(pNode == NULL)
        return;

    BinaryTreeNode *pCurrent = pNode;

    if (pCurrent->m_pLeft != NULL)
        ConvertNode(pCurrent->m_pLeft, pLastNodeInList);

    pCurrent->m_pLeft = *pLastNodeInList;
    if(*pLastNodeInList != NULL)
        (*pLastNodeInList)->m_pRight = pCurrent;

    *pLastNodeInList = pCurrent;

    if (pCurrent->m_pRight != NULL)
        ConvertNode(pCurrent->m_pRight, pLastNodeInList);
}


方法2


BinaryTreeNode *Tmp = NULL;
BinaryTreeNode *Calc2(BinaryTreeNode *pNode)
{
  if (pNode == NULL)
       return NULL;
  BinaryTreeNode *pCurr = pNode;
  if (pCurr->m_pLeft != NULL)
   {
       Tmp = Calc2(pCurr->m_pLeft);
   }

  pCurr->m_pLeft = Tmp;
  if (Tmp != NULL)
      Tmp->m_pRight = pCurr;
  Tmp = pCurr;
  if (pCurr->m_pRight != NULL)
  {
       Tmp = Calc2(pCurr->m_pRight);
  }
  return Tmp;
}

BinaryTreeNode * Convert(BinaryTreeNode *pRoot)
{
    BinaryTreeNode *Tmp1 = Calc2(pRoot);
    
    while (Tmp1 != NULL&&Tmp1->m_pLeft != NULL)
    {
        Tmp1 = Tmp1->m_pLeft;
    }
    return Tmp1;
}

方法3

BinaryTreeNode * Calc1(BinaryTreeNode *pNode,BinaryTreeNode *pLast)
{
    if (pNode == NULL)
        return NULL;
    BinaryTreeNode *pCurr = pNode;
    if (pCurr->m_pLeft != NULL)
    {
        pLast=Calc1(pCurr->m_pLeft, pLast);
    }
    pCurr->m_pLeft = pLast;
    if (pLast != NULL)
    {
        (pLast)->m_pRight = pCurr;
    }
    pLast = pCurr;
    if (pCurr->m_pRight != NULL)
    {
        pLast=Calc1(pCurr->m_pRight, pLast);
    }
    return pLast;
}

BinaryTreeNode * Convert(BinaryTreeNode *pRoot)
{
    BinaryTreeNode *Tmp1 = Calc1(pRoot,NULL);
    
    while (Tmp1 != NULL&&Tmp1->m_pLeft != NULL)
    {
        Tmp1 = Tmp1->m_pLeft;
    }
    return Tmp1;
}


4 二叉树的镜像

方法1 循环实现,循环实现肯定要用stack喽

void MirrorIteratively(BinaryTreeNode* pRoot)
{
    if(pRoot == NULL)
        return;

    std::stack<BinaryTreeNode*> stackTreeNode;
    stackTreeNode.push(pRoot);

    while(stackTreeNode.size() > 0)
    {
        BinaryTreeNode *pNode = stackTreeNode.top();
        stackTreeNode.pop();

        BinaryTreeNode *pTemp = pNode->m_pLeft;
        pNode->m_pLeft = pNode->m_pRight;
        pNode->m_pRight = pTemp;

        if(pNode->m_pLeft)
            stackTreeNode.push(pNode->m_pLeft);

        if(pNode->m_pRight)
            stackTreeNode.push(pNode->m_pRight);
    }
}

方法2 递归实现!

void MirrorRecursively(BinaryTreeNode *pNode)
{
    if((pNode == NULL) || (pNode->m_pLeft == NULL && pNode->m_pRight))
        return;

    BinaryTreeNode *pTemp = pNode->m_pLeft;
    pNode->m_pLeft = pNode->m_pRight;
    pNode->m_pRight = pTemp;
    
    if(pNode->m_pLeft)
        MirrorRecursively(pNode->m_pLeft);  

    if(pNode->m_pRight)
        MirrorRecursively(pNode->m_pRight);
}


5 输入一行整数,判断是不是二叉搜索树的后序遍历?假设输入的任意两个数字均不相同。


bool VerifySquenceOfBST(int sequence[], int length)
{
    if(sequence == NULL || length <= 0)
        return false;

    int root = sequence[length - 1];

    // 在二叉搜索树中左子树的结点小于根结点
    int i = 0;
    for(; i < length - 1; ++ i)
    {
        if(sequence[i] > root)
            break;
    }

    // 在二叉搜索树中右子树的结点大于根结点
    int j = i;
    for(; j < length - 1; ++ j)
    {
        if(sequence[j] < root)
            return false;
    }

    // 判断左子树是不是二叉搜索树
    bool left = true;
    if(i > 0)
        left = VerifySquenceOfBST(sequence, i);

    // 判断右子树是不是二叉搜索树
    bool right = true;
    if(i < length - 1)
        right = VerifySquenceOfBST(sequence + i, length - i - 1);

    return (left && right);
}


6  二叉树中和为某一值的路径。

输入一棵二叉树和一个整数,打印出二叉树中和为此输入值的所有路径。从根节点到叶结点形成一条完整路径。

void FindPath(BinaryTreeNode* pRoot, int expectedSum, std::vector<int>& path, int& currentSum);

void FindPath(BinaryTreeNode* pRoot, int expectedSum)
{
    if(pRoot == NULL)
        return;

    std::vector<int> path;
    int currentSum = 0;
    FindPath(pRoot, expectedSum, path, currentSum);
}

void FindPath
(
    BinaryTreeNode*   pRoot,        
    int               expectedSum,  
    std::vector<int>& path,         
    int&              currentSum
)
{
    currentSum += pRoot->m_nValue;
    path.push_back(pRoot->m_nValue);

    // 如果是叶结点,并且路径上结点的和等于输入的值
    // 打印出这条路径
    bool isLeaf = pRoot->m_pLeft == NULL && pRoot->m_pRight == NULL;
    if(currentSum == expectedSum && isLeaf)
    {
        printf("A path is found: ");
        std::vector<int>::iterator iter = path.begin();
        for(; iter != path.end(); ++ iter)
            printf("%d\t", *iter);
        
        printf("\n");
    }

    // 如果不是叶结点,则遍历它的子结点
    if(pRoot->m_pLeft != NULL)
        FindPath(pRoot->m_pLeft, expectedSum, path, currentSum);
    if(pRoot->m_pRight != NULL)
        FindPath(pRoot->m_pRight, expectedSum, path, currentSum);

    // 在返回到父结点之前,在路径上删除当前结点,
    // 并在currentSum中减去当前结点的值
    currentSum -= pRoot->m_nValue;
    path.pop_back();
}


7  数中两个结点的公共祖先之求从根节点分别到某个节点的路径。

bool GetNodePath(TreeNode* pRoot, TreeNode* pNode, list<TreeNode*>& path)
{
    if(pRoot == pNode)
        return true;
 
    path.push_back(pRoot);
 
    bool found = false;

    vector<TreeNode*>::iterator i = pRoot->m_vChildren.begin();
    while(!found && i < pRoot->m_vChildren.end())
    {
        found = GetNodePath(*i, pNode, path);
        ++i;
    }
 
    if(!found)
        path.pop_back();
 
    return found;
}


8 输入两棵二叉树A和B, 判断B是不是A的子结构。

方法1

bool HasSubtreeCore(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2);
bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2);

bool HasSubtree(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
{
    bool result = false;

    if(pRoot1 != NULL && pRoot2 != NULL)
    {
        if(pRoot1->m_nValue == pRoot2->m_nValue)
            result = DoesTree1HaveTree2(pRoot1, pRoot2);
        if(!result)
            result = HasSubtree(pRoot1->m_pLeft, pRoot2);
        if(!result)
            result = HasSubtree(pRoot1->m_pRight, pRoot2);
    }

    return result;
}

bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
{
    if(pRoot2 == NULL)
        return true;

    if(pRoot1 == NULL)
        return false;

    if(pRoot1->m_nValue != pRoot2->m_nValue)
        return false;

    return DoesTree1HaveTree2(pRoot1->m_pLeft, pRoot2->m_pLeft) &&DoesTree1HaveTree2(pRoot1->m_pRight, pRoot2->m_pRight);
}


方法2

bool DoesTree1HasTree2(BinaryTreeNode *pRoot1, BinaryTreeNode *pRoot2);
bool HasSubtree(BinaryTreeNode *pRoot1, BinaryTreeNode *pRoot2)
{
    if (pRoot1 == NULL || pRoot2 == NULL)
    {
        return false;
    }
    else if (pRoot1 != NULL&&pRoot2 != NULL)
    {
        if (pRoot1->m_nValue == pRoot2->m_nValue)
        {
            if (DoesTree1HasTree2(pRoot1, pRoot2))
                return true;
            else
                return HasSubtree(pRoot1->m_pLeft, pRoot2) || HasSubtree(pRoot1->m_pRight, pRoot2);
        }            
        else if (pRoot1->m_nValue != pRoot2->m_nValue)
        {
            return HasSubtree(pRoot1->m_pLeft, pRoot2) || HasSubtree(pRoot1->m_pRight, pRoot2);
        }
    }
}


bool DoesTree1HasTree2(BinaryTreeNode *pRoot1, BinaryTreeNode *pRoot2)
{
    if (pRoot2 == NULL)
        return true;
    else if (pRoot1 == NULL)
        return false;
    else if (pRoot1 != NULL&&pRoot2 != NULL)
    {
        if (pRoot1->m_nValue == pRoot2->m_nValue)
            return DoesTree1HasTree2(pRoot1->m_pRight, pRoot2->m_pRight) && DoesTree1HasTree2(pRoot1->m_pLeft, pRoot2->m_pLeft);
        else
            return false;
    }
}


9.1递归前中后遍历二叉树

9.2 非递归前中后遍历二叉树

9.3 二叉树DFS BFS

10 求二叉树第K层节点个数

int GetNumOfK(BinaryTreeNode *pRoot, int k, int level)
{
    if (pRoot == NULL)
        return 0;
    static int num = 0;
    if (level == k)
    {
        num++;
        return num;
    }
    GetNumOfK(pRoot->m_pLeft, k, level + 1);
    GetNumOfK(pRoot->m_pRight, k, level + 1);
    return num;
}

11 求二叉树叶结点个数

方法1

int num = 0;

void FindLeafNum1(BinaryTreeNode *pRoot, int &num)
{
    if (pRoot == NULL)
        num=0;
    if (pRoot->m_pLeft != NULL)
        FindLeafNum1(pRoot->m_pLeft, num);
    if (pRoot->m_pRight != NULL)
        FindLeafNum1(pRoot->m_pRight, num);
    if (pRoot->m_pLeft == NULL&&pRoot->m_pRight == NULL)
    {
        num++;
    }
}

方法2
int FindLeafNum(BinaryTreeNode *pRoot)
{
    if (pRoot == NULL)
        return 0;
    if (pRoot->m_pLeft == NULL&&pRoot->m_pRight == NULL)
        return 1;
    return FindLeafNum(pRoot->m_pRight) + FindLeafNum(pRoot->m_pLeft);
}


方法3  也可以用全局变量

int FindLeafNum2(BinaryTreeNode *pRoot)
{
    static int num = 0;
    if (pRoot == NULL)
        num = 0;
    if (pRoot->m_pLeft == NULL&&pRoot->m_pRight == NULL)
    {
        num++;
    }
    if (pRoot->m_pLeft != NULL)
        FindLeafNum2(pRoot->m_pLeft);
    if (pRoot->m_pRight != NULL)
        FindLeafNum2(pRoot->m_pRight);
    return num;

}


12 求二叉树中节点的最大距离

分析: 

  1、如果具有最远距离的两个结点之间的路径经过根结点,则最远距离就是这个根节点左边的深度加上根节点的右边的深度。
  2、如果具有最远距离的两个结点之间的路径不经过根节点,则最远距离的结点就在根节点的某一棵子树上的两个叶子结点。
  使用distance记录这个最远的距离。后序遍历二叉树中每一个结点,对于每一个结点先算出左边和右边的深度和然后与distance里面的数据进行比较,如果结果大于distance则更新distance的值。这种方法的时间复杂度是O(N)。

int GetFarDistance(BinaryTreeNode *pRoot, int &distance)//函数返回的是当前节点左边最大距离和右边最大距离较大的一个,包括本节点;而distance代表的是以此节点为头结点树的两子节点最大距离;
{
    if (!pRoot)
        return 0;
    int left = GetFarDistance(pRoot->m_pLeft, distance);
    int right = GetFarDistance(pRoot->m_pRight, distance);
    if ((left + right) > distance)
        distance = (left + right);
    return left > right ? left + 1 : right + 1;
}

int GetFarDistance(BinaryTreeNode *pRoot)
{
    if (!pRoot)
        return 0;
    int distance = 0;
    GetFarDistance(pRoot, distance);
    return distance;
}


13判断一棵树是否是完全二叉树

分析:
  什么是完全二叉树呢???
  如果一颗二叉树的只有最后两层结点的度能小于2,其余结点的度都等于2。且最后一层的结点从最左边依次排列。
  如果一颗二叉树中的每一个结点都与编号从1到n的满二叉树中的结点一一对应,则称这棵二叉树为完全二叉树。
  我们可以根据完全二叉树的定义,按照层序遍历一颗树,当遇到空结点时如果这棵树已经遍历完毕,则这棵树就是完全二叉树,如果遇到空结点的后面还有元素则这棵树就不是完全二叉树。
bool IsCompleteTree(BinaryTreeNode *pRoot)
{
    if (pRoot == NULL)
        return false;
    queue<BinaryTreeNode *> q;
    q.push(pRoot);
    int flag = 0;//flag代表之前的遍历中是否出现过缺少子节点的情况!
    while (!q.empty())
    {
        BinaryTreeNode *curr = q.front();
        q.pop();
        if (curr->m_pLeft)
        {
            if (flag)
                return false;
            else
                q.push(curr->m_pLeft);
        }
        else
        {
            if (flag==0)
              flag = 1;
        }
        if (curr->m_pRight)
        {
            if (flag)
                return false;
            else
                q.push(curr->m_pRight);
        }
        else
        {
            if (flag == 0)
                flag = 1;
        }
    }
    return true;
}

14 重建二叉树(剑指offr T6)

根据前序和中序重建二叉树,假设没有重复数字。

BinaryTreeNode* ConstructCore(int* startPreorder, int* endPreorder, int* startInorder, int* endInorder);

BinaryTreeNode* Construct(int* preorder, int* inorder, int length)
{
    if(preorder == NULL || inorder == NULL || length <= 0)
        return NULL;

    return ConstructCore(preorder, preorder + length - 1,
        inorder, inorder + length - 1);
}

BinaryTreeNode* ConstructCore
(
    int* startPreorder, int* endPreorder,
    int* startInorder, int* endInorder
)
{
    // 前序遍历序列的第一个数字是根结点的值
    int rootValue = startPreorder[0];
    BinaryTreeNode* root = new BinaryTreeNode();
    root->m_nValue = rootValue;
    root->m_pLeft = root->m_pRight = NULL;

    if(startPreorder == endPreorder)
    {
        if(startInorder == endInorder && *startPreorder == *startInorder)
            return root;
        else
            throw std::exception("Invalid input.");
    }

    // 在中序遍历中找到根结点的值
    int* rootInorder = startInorder;
    while(rootInorder <= endInorder && *rootInorder != rootValue)
        ++ rootInorder;

    if(rootInorder == endInorder && *rootInorder != rootValue)
        throw std::exception("Invalid input.");

    int leftLength = rootInorder - startInorder;
    int* leftPreorderEnd = startPreorder + leftLength;
    if(leftLength > 0)
    {
        // 构建左子树
        root->m_pLeft = ConstructCore(startPreorder + 1, leftPreorderEnd,
            startInorder, rootInorder - 1);
    }
    if(leftLength < endPreorder - startPreorder)
    {
        // 构建右子树
        root->m_pRight = ConstructCore(leftPreorderEnd + 1, endPreorder,
            rootInorder + 1, endInorder);
    }

    return root;
}