二叉树相关面试题(上)

一,将二叉搜索树转换为一个排序的双向链表。
提示:要求不能创建任何新的结点,只能调整树中节点的指向。
eg:
这里写图片描述
搜索二叉树:左节点的值小于父节点的值,右节点的值大于父节点的值。
思路:二叉树中每个节点有两个指向子节点的指针,双向链表中每个节点也有两个指针,两个节点结构相似,同时二叉搜索树也是一种排序的数据结构。因此理论上可能实现二叉搜索树和排序双向链表的转换。
步骤:在将二叉搜索树转换为排序双向链时,原先指向左子节点的指针调为链表中指向前一个节点的指针,原先指向右子节点的指针调为链表中指向后一个节点的指针。
按照中序遍历的顺序,当我们遍历转换到根节点时,它的左子树已经转换为一个排序的链表,并且处在链表中最后一个节点的是当前最大值的节点。把8和根节点连接起来,此时链表中最后一个节点就是10,接着去遍历转换右子树,并把根节点和右子树中最小的节点连接起来。
这里写图片描述
代码实现:

#include<iostream>
#include<Windows.h>
using namespace std;
//定义二叉树节点结构
struct BSTNode 
{
    BSTNode* _left;
    BSTNode* _right;
    int _data;

    BSTNode(int data,BSTNode* left = NULL,BSTNode* right = NULL)
        :_data(data)
        ,_left(left)
        ,_right(right)
    {}
};

//插入新节点到树中
void Insert(BSTNode*& tree,int data)
{
    if(NULL == tree)
    {
        tree = new BSTNode(data,NULL,NULL);
    }
    else if(data < tree->_data)
    {
        Insert(tree->_left,data);
    }
    else if(data > tree->_data)
    {
        Insert(tree->_right,data);
    }
    else
    {
        return ;
    }
}
//查找二叉搜索树tree的最左节点
BSTNode* Findleftnode(BSTNode* tree)
{
    if(tree == NULL)
    {
        return NULL;
    }
    while(tree->_left != NULL)
    {
        tree = tree->_left;
    }
    return tree;
}
//遍历二叉树的各个节点,并进行指针调解
void ConvertNode(BSTNode* tree,BSTNode*& lastnodeList)
{
    if(tree == NULL)
    {
        return;
    }
    if(tree->_left != NULL)//将左子树进行转换
    {
        ConvertNode(tree->_left,lastnodeList);
    }
    tree->_left = lastnodeList;
    if(lastnodeList != NULL)//调整最后一个节点的指针,使它指向此时的父节点
    {
        lastnodeList->_right = tree;
    }
    lastnodeList = tree;
    if(tree->_right != NULL)//将右子树进行转换
    {
        ConvertNode(tree->_right,lastnodeList);
    }
}
//将二叉搜索树tree转化为双向链表,并返回头结点
BSTNode* BSTNodetolist(BSTNode* tree)
{
    if(tree == NULL)
    {
        return NULL;
    }
    BSTNode* head = Findleftnode(tree);//将二叉树最左边的节点转化为链表的头结点
    BSTNode* lastnodeList = NULL;

    ConvertNode(tree,lastnodeList);//进行转换
    return head;
}
//以中序遍历打印二叉搜索树tree
void Printtree(BSTNode* tree)
{
    if(tree == NULL)
    {
        return;
    }
    Printtree(tree->_left);
    cout<<tree->_data<<" ";
    Printtree(tree->_right);
}
//打印链表
void PrintList(BSTNode* head)
{
    if(head == NULL)
    {
        return;
    }
    BSTNode* node = head;
    while(node!=NULL)
    {
        cout<<node->_data<<" ";
        node = node->_right;
    }
    cout<<endl;
}
int main()
{
    BSTNode* tree = NULL;
    int a[] = {10,6,14,4,8,12,16};
    for(size_t i = 0;i<(sizeof(a)/sizeof(a[0]));i++)
    {
        Insert(tree,a[i]);
    }
    Printtree(tree);
    cout<<endl;
    BSTNode* head = BSTNodetolist(tree);
    PrintList(head);
    return 0;
}

这里写图片描述

2.判断一棵树是否是完全二叉树
完全二叉树的概念:设二叉树的深度是h,除了最后一层其它层的节点数达到最大个数,第h层所有的节点都连续集中在最左边。
这里写图片描述
思路:层序遍历思想,利用队列queue实现。
考虑到四种不同的情况:
(1)如果树为空,直接返回false
(2)如果一个节点的左右孩子均不为空,pop掉该节点,将其左右孩子入队列。
(3)如果一个节点左孩子为空右孩子不为空,该树不符合完全二叉树的特点,返回false。
(4)如果一个节点左孩子不为空且右孩子为空,或者左右孩子均为空,如果该节点之后的队列中所有的节点均为叶子节点,该树则为完全二叉树。
代码实现:

struct Node
{
    int _data;
    Node* _left;
    Node* _right;

    Node(int x)
        :_data(x)
        ,_left(NULL)
        ,_right(NULL)
    {}
};
//创建二叉树
class Binarytree
{
public:
    Binarytree(const int a[],int size,int invalide)
    {
        int index = 0;
        _root = CreateBinarytree(a,size,index,invalide);
    }
    Node* CreateBinarytree(const int a[],int size,int &index,int invalide)
    {
        Node* root = NULL;
        if(index < size && a[index] !=invalide)
        {
            root = new Node(a[index]);
            root ->_left = CreateBinarytree(a,size,++index,invalide);
            root ->_left = CreateBinarytree(a,size,++index,invalide);
        }
        return root;
    }
    //判断是否是完全二叉树
    bool IsComplateBinarytree()
    {
        if(_root == NULL)
        {
            return false;
        }
        queue<Node*>q;
        q.push(_root);
        while(!q.empty())
        {
            Node* cur = q.front();
            //1.左右孩子均不为空
            if(cur->_left&&cur->_right)
            {
                q.pop();
                q.push(cur->_left);
                q.push(cur->_right);
            }
            //2.左孩子为空且右孩子不为空
            if(cur->_left == NULL && cur->_right)
            {
                return false;
            }
            //3.左孩子不为空且右孩子为空,或者左右孩子均为空
            if((cur->_left && cur->_right == NULL) || (cur->_left == NULL)&&(cur->_right == NULL))
            {

                if(cur->_left && cur->_right == NULL)
                {
                    q.push(cur->_left);

                }
                q.pop();
                while(!q.empty())
                {
                    cur = q.front();
                    if((cur->_left == NULL)&&(cur->_right == NULL))
                    {
                        q.pop();
                    }
                    else
                    {
                        return false;
                    }
                }
                return true;
            }
        }
        return true;
    }
private:
    Node* _root;
};
int main()
{
    int a1[]={1,2,'#',3,'#','#',4,5,'#',6,'#',7,'#','#',8};  //0
    //int a2[]={1,2,3,'#','#',4,'#','#',5,6};  //1
    Binarytree tr(a1,20,'#');
    cout<<tr.IsComplateBinarytree()<<endl;
    return 0;
}
  • 0
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值