二叉树面试题

1.求二叉树节点个数
可以使用递归解决。将问题分解为求根节点+左子树的节点数+右节点的节点数。
这里写图片描述
实现 :

public:
    size_t _Size() {   //封装调用
        return Size(_root);
    }
private:
    size_t Size(Node *root){   //二叉树中节点个数
        if (root == NULL)
            return 0;
        return 1 + Size(root->leftChild) + Size(root->rightChild);
    }

2.求页节点个数
页节点:左右子树都为空的节点被称为页节点,使用递归遍历,当碰到一个左右子树为空的节点时,返回 1,累加起来。
这里写图片描述
实现:

public:
    size_t _LeafSize() {   //封装
        return LeafSize(_root);
    }
private:
    size_t LeafSize(Node *root) {    //页节点数
        if (root == NULL)
            return 0;
        if (root->leftChild == NULL && root->rightChild == NULL)  //如果左右都为空
            return 1;
        return LeafSize(root->leftChild)+LeafSize(root->rightChild);

    }

3.求第K层节点个数
在求第 K 层节点个数时,可能会出现所求的第 K 层大于实际二叉树的层数。
实现

public:
    size_t _LevelSize(size_t k)  //封装
    {
        return LevelSize(_root, k, 1);
    }
private:
    size_t LevelSize(Node *root, size_t k, size_t n)//求第K层节点数
    {
        if (root == NULL) {    //节点为空 返回0
            return 0;
        }
        if (n < k - 1) {
            return LevelSize(root->leftChild, k, n + 1) + LevelSize(root->rightChild, k, n + 1);
        }
        if (n == k - 1) {
            return (root->leftChild != NULL) + (root->rightChild != NULL);
        }
        return 0;
    }

4.求二叉树深度/高度
在求二叉树深度的时候,可以将问题分解为求根节点的左子树和右子树的深度的最大值 + 1。所以需要对左子树和右子树的深度进行判断,返回较大的。
这里写图片描述
实现

public:
    size_t Depth() {   //封装
        return _Depth(_root);
    }
private:
    size_t _Depth(Node *root) {   //求深度
        if (root == NULL) {
            return 0;
        }
        if (_Depth(root->leftChild) > _Depth(root->rightChild))
            return 1+_Depth(root->leftChild);
        else
            return 1+_Depth(root->rightChild);
    }

5.查找节点
可以使用递归对整个二叉树进行遍历,如果碰到则返回该节点位置。
实现:

public:
    Node *Find(const T& x) {   //查找并返回节点
        return _Find(_root, x);
    }
private:
    Node* _Find(Node *root , const T&x) {
        if (root == NULL)
            return NULL;
        if (root->_data == x)
            return root;
        Node * ret = _Find(root->leftChild, x);
        if (ret != NULL)
            return ret;
        return _Find(root->rightChild, x);

    }

6.将二叉树镜像
将二叉树镜像也就是将二叉树进行翻转。
可以使用队列,从上向下将每个元素的左右子树进行交换。
也可以使用递归,从下向上就行翻转。
循环思想
这里写图片描述
实现

public:
    void MirrorTree()  //非递归求镜像
    {
        _MirrorTree(_root);
    }

private:
    void _MirrorTree(Node *root) //封装调用
    {
        queue<Node*> q;  //利用队列
        Node *cur = root;
        q.push(cur);
        while (!q.empty())
        {
            Node* top = q.front();
            if (top->leftChild)
                q.push(top->leftChild);
            if (top->rightChild)
                q.push(top->rightChild);
            swap(top->leftChild, top->rightChild);
            q.pop();
        }
    }

递归思想
这里写图片描述
实现

public:
    void MirrorTreeR()  //递归二叉树镜像
    {
        _MirrorTree(_root);
    }
private:
    void _MirrorTreeR(Node *root)   //封装调用
    {
        if (root == NULL)
            return;
        _MirrorTree(root->leftChild);  //左树
        _MirrorTree(root->rightChild);  //右树
        swap(root->leftChild, root->rightChild);
    }

7.判断一颗二叉树是不是完全二叉树

完全二叉树:前N个节点与该树的满二叉树相同。
可以使用队列对二叉树进行遍历。
如果二叉树存在左右子树,则对左右子树进行压栈。
此时会出现4中情况
(1) 左右子树都存在
此时应该将根节点的左右子树入队,并将根结点的出队。
(2) 左子树存在,右子树不存在
此时应该将左节点入队并退出循环进行判断,队列中剩余元素是否存在子节点,如果存在则不是完全二叉树。
(3) 右子树存在,左子树不存在
此时,此颗二叉树肯定不是完全二叉树。
(4) 左右子树都不存在
此时应该直接退出循环,对队列中剩余的所有子树进行判断。
实现

bool IsComplateTree()
{
    queue<Node *> q;
    if (_root)
        q.push(_root);
    while (!q.empty())
    {
        Node *front = q.front();
        q.pop();
        if (front->leftChild&&front->rightChild) //如果左右子树都不为空则压入
        {
            q.push(front->leftChild);
            q.push(front->rightChild);
        }
        else if (front->leftChild) {  //左不为空,右为空
            q.push(front->leftChild);
            break;   //放入左树后进行判断
        }
        else if (front->rightChild) //左空右不空,肯定不是完全二叉树
            return false;
        else //左右都为空
            break; //对队列中剩下的元素进行判断
    }       
    while (!q.empty())
    {
        Node *front = q.front();

        if (front->leftChild == NULL&&front->rightChild == NULL)
            q.pop();
        else
            return false;
    }
    return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值