二叉树——面试题

34 篇文章 1 订阅
21 篇文章 1 订阅

1.求二叉树中最远的两个节点的距离


在这我们首先来分析思路,对于最远的两个节点,在这会有两种情况。

1)如果root为NULL,那么这是一颗空树。空树的最远子节点距离和高度均为零。
2),如果root非空,最大距离要么是左子树中的最大距离,要么是右子树中的最大距离,要么是左子树节点中到根节点的最大距离+右子树节点中到根节点的最大距离,同时记录左子树和右子树节点中到根节点的最大距离。
这里写图片描述

示例代码:

//求得二叉树中最远两个节点之间的距离
    size_t MaxDistance()
    {
        size_t maxdistance = 0;
        _MaxDistance(_root,maxdistance);
        return maxdistance;

    }
        //求二叉树中最远的两个节点的距离
    size_t _MaxDistance(Node *root,size_t &Max)
    {
        if (root == NULL)
        {
            Max = 0;
            return 0;
        }
        if (root->_left == NULL&&root->_right == NULL)
        {
            return 0;
        }
        size_t leftdepth= _MaxDistance(root->_left, Max)+1;
        size_t rightdepth = _MaxDistance(root->_right, Max)+1;
        //用来得到最远距离
        Max = (Max < (leftdepth + rightdepth) ? (leftdepth + rightdepth) : Max) ;
        //顺带返回深度
        return (leftdepth>rightdepth?leftdepth:rightdepth);

    }

2.判断一棵树是否为完全二叉树


判断一棵树是否为完全二叉树,首先要理解完全二叉树的定义,完全二叉树就是 只有最下面的两层结点度能够小于2,并且最下面一层的结点都集中在该层最左边的若干位置的二叉树。

1)所以根据特点,我们可以思考,如果对于完全二叉树,我们进行层序遍历,那么一直就可以走到头,而对于非完全二叉树,我们进行层序遍历,那么我们可能还会遇到空。因为最后一层节点的分布导致。

所以我们就可以利用层序遍历进行判断,先把每层的节点进行入队。然后出队,一直到碰到NULL,这个时候看队中是否还剩下了非空结点,如果存在,那么就不是完全二叉树。如果不存在,那么就是完全二叉树。

2)可以给一个flag,当到左树的时候,利用这个flag,如果左为空,右边还右节点,那么这棵树必定不是完全二叉树。

3)也还可以从上利用队列,放入队列当中,当遇到一个空节点后不再入队,然后向后看是否还有非空节点,有则不是完全二叉树,没有则是完全二叉树。
这里写图片描述

示例代码:

bool IsComplateBinaryTree()
    {
        std::queue<Node * > q;
        Node* cur = _root;
        q.push(cur);
        //首先进行层序,把每一层的节点都入队,这个时候不存在的节点就按照NULL入队
        while ((cur = q.front()) != NULL)
        {
            q.pop();
            q.push(cur->_left);
            q.push(cur->_right);
        }
        //这个时候如果是完全二叉树,那么队中就全部为空,如果为非完全二叉树的话,那么队中就会存在不为空的元素。
        while (!q.empty())
        {
            cur = q.front();
            q.pop();
            if (cur != NULL)
            {
                return false;
            }
        }
        return true;
    }

3.由前序遍历和中序遍历重建二叉树(前序序列:1 2 3 4 5 6 - 中序序列: 3 2 4 1 6 5 )


重建二叉树,就是利用前序遍历第一个节点是根节点的特性确定根节点,然后通过中序遍历中根节点在中间,这样我们也可以得到左子树序列和右子树序列,然后转化为递归问题,就可以解决。

这里写图片描述

     Node* _RebuildBinaryTree (T* preorder, T* infixorder , int lengh)
     {
          if ( lengh == 0 || preorder == NULL || infixorder == NULL)
          {
              return NULL ;
          }
          T tmp = preorder[0 ];
          Node * root = new Node(tmp );
          int i = 0;
          for ( i = 0; i < lengh &&infixorder[ i] != tmp ; i ++)
              ;
          int leftlen = i;
          int rightlen = lengh - i - 1 ;
          if ( leftlen>0 )
              root->_left = _RebuildBinaryTree (preorder+ 1, infixorder, leftlen);
          if ( rightlen > 0)
              root->_right = _RebuildBinaryTree (preorder+ leftlen + 1, infixorder +leftlen + 1 , rightlen );

          return root ;
     }

4.寻找两个节点的最近公共节点


当我们在这里查找节点的时候,可以通过一些条件来限定:

1)如果是BST
如果二叉树是个二叉查找树,且root和两个节点的值(a, b)已知。两个节点的key去和root的key进行比较。
如果两个节点值都大于root的key,那么这两个节点就是在root的右边,如果两个节点的值都小于root的key,那么这两个节点都在root的左边。如果一大一小,那么root就是最近祖先节点。

这里写图片描述

Node *FindTwoCommonNode(Node* p1,Node* p2)
    {
        K minkey = 0;
        K maxkey = 0;
        if (p1->_key > p2->_key)
        {
            maxkey = p1->_key;
            minkey = p2->_key;
        }
        else
        {
            maxkey = p2->_key;
            minkey = p1->_key;
        }
        Node* cur = _root;
        while (cur)
        {
            //考虑两类情况,一种是在符合的节点
            if (cur->_key >= minkey&&cur->_key <= maxkey)
            {
                return cur;
            }
            //此时cur所指向节点比两个节点都大。所以两个节点都在左子树
            else if (cur->_key > minkey&&cur->_key > maxkey)
            {
                cur = cur->_left;
            }
            //对比上一步
            else
            {
                cur = cur->_right;
            }
        }
        return NULL;
    }

2)是二叉树有parent
此时可以分别从两个节点开始,沿着parent指针走向根节点,得到两个链表,然后求两个链表的第一个公共节点。这种方法,其实就是从二叉树演变成了链表求公共节点的问题,这个以前博客有些,就不再多介绍了。
这里写图片描述

3)思路:有两种情况,一是要找的这两个节点(a, b),在要遍历的节点(root)的两侧,那么这个节点就是这两个节点的最近公共父节点;
二是两个节点在同一侧,则 root->left 或者 root->right 为 NULL,另一边返回a或者b。那么另一边返回的就是他们的最小公共父节点。
递归有两个出口,一是没有找到a或者b,则返回NULL;二是只要碰到a或者b,就立刻返回。

这里写图片描述
示例代码:

//查找最近的两个公共节点
    Node* _FindTwoCommonNode(Node* root, Node* p1, Node *p2)
    {
        //当节点为空,这个时候返回
        if (root == NULL)
        {
            return NULL;
        }
        //判断节点是否为要找的节点,是则直接返回节点
        if (root == p1 || root == p2)
        {
            return root;
        }
        //递归右树和左树,寻找两个节点
        Node* left = _FindTwoCommonNode(root->_left, p1, p2);
        Node* right = _FindTwoCommonNode(root->_right, p1, p2);
        //判断是否在左子树和右子树中找到,如果在左右子树当中都找到了,那就说明当前的root就是最近祖先
        if (left&&right)
        //左右子树都存在就返回root,此时的root就是最近公共节点
            return root;   
        //否则返回找到的节点非空结点。
        return left ? left : right;   
    }

5.BST转排序双向链表


思路就是利用prenode进行连接。进行一个类似的中序的一个线索化过程。
所以如果有需要,可以先去看我前面的线索化的文章。
我们的思想就是,我们在这个工程中我们使用prenode作为记录上一个节点,
这里写图片描述

Node* _CovertSortList(Node *root,Node *&prenode)
    {
        if (root==NULL)
            return NULL;
        Node* cur = root;

        //先要找到BST的最小键值点,也就是最左节点。寻找最左节点的时候切记prenode是不能变的。
        if (root->_left)
            _CovertSortList(cur->_left, prenode);
        //找到以后,这个最左节点的左边链上prenode
        //当前节点我们用来连接左指针到上一个节点
        cur->_left = prenode;
        //这个时候考虑给前一个节点的右链上节点
        //在当前节点的时候,我们连接上一个节点的右指针到当前节点
        if (prenode != NULL)
            prenode->_right = cur;
        //改变前一个节点为当前节点
        prenode = cur;
        //考虑右子树的问题
        if (cur->_right)
            _CovertSortList(cur->_right,prenode);
        return root;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值