二叉树面试题——上

二叉树其他面试题链接:二叉树面试题——下


一、创建一棵二叉树

思路:利用数组把二叉树用代码表示出来,例如创建下面这颗树:

int a[] = { 1, 2, 3, '#', '#', 4, '#', '#', 5, 6, '#', '#', '#' };

  传参时把数组名、数组下标以及非法值传过去。invalid是‘#’的ascll码值,代表NULL,如果某节点的左右孩子都是‘#’,那他就是叶子。

  创建使用的是递归法,具体代码实现如下:
(PS:此处传数组下标采用的是传址方式,因为递归法会有多层函数栈帧,用传值的方法的话,在这层函数栈帧里修改了下标并不会影响其它栈帧里面下标的值,那样就会导致创建树失败!)

typedef int BTSTDataType;

typedef struct BinaryTreeNode
{
    struct BinaryTreeNode* _left;
    struct BinaryTreeNode* _right;
    BTSTDataType _data;
}BTNode;

BTNode* BuyBTNode(BTSTDataType x)
{
    BTNode* node = (BTNode*)malloc(sizeof(BTNode));
    assert(node != NULL);

    node->_left = NULL;
    node->_right = NULL;
    node->_data = x;

    return node;
}

BTNode* CreateBTree(BTSTDataType* a, size_t* pIndex, BTSTDataType invalid)// 创建二叉树
{
    BTNode* root = NULL;

    if (a[*pIndex] != invalid)
    {
        root = BuyBTNode(a[*pIndex]);
        (*pIndex)++;
        root->_left = CreateBTree(a, pIndex, invalid);
        (*pIndex)++;
        root->_right = CreateBTree(a, pIndex, invalid);
    }

    return root;
}

二、前序遍历(非递归法)

思路:用栈结构来实现非递归前序遍历:
这里写图片描述

  1. 创建一个栈s并初始化;
  2. 从树根开始,把1,2,3依次入栈并输出;
  3. 访问3的左孩子时,它为NULL,内层循环结束;
  4. 3出栈,访问3的右孩子;
    ………….
void BTreePrevOrderNonR(BTNode* root)
{
    Stack s;
    StackInit(&s);
    BTNode* top = NULL;
    BTNode* cur = root;

    while (cur != NULL || StackEmpty(&s) != 0)
    {
        while (cur != NULL)
        {
            printf("%d ", cur->_data);
            StackPush(&s, cur);
            cur = cur->_left;
        }

        top = StackTop(&s);
        StackPop(&s);

        cur = top->_right; //子问题
    }
}

三、中序遍历(非递归法)

思路:和上一题大致相同,只是改变了输出函数的位置。

void BTreeInOrderNonR(BTNode* root)
{
    Stack s;
    StackInit(&s);
    BTNode* top = NULL;
    BTNode* cur = root;

    while (cur != NULL || StackEmpty(&s) != 0)
    {
        while (cur != NULL)
        {
            StackPush(&s, cur);
            cur = cur->_left;
        }

        top = StackTop(&s);
        printf("%d ", top->_data);
        StackPop(&s);

        cur = top->_right;
    }
}

四、后序遍历(非递归法)

思路:加一个prev指针,它指向上一个访问的节点。

  1. 首先 1、2、3依次入栈;
  2. 访问3的左孩子,为NULL,跳出内层循环,top = 3;
  3. 输出3,prev = 3,节点3出栈;
  4. top = 2,跳过if进入else,cur = 4;
  5. 4入栈,cur = NULL,top = 4,prev = 4,4出栈;
  6. top = 2,进入if,输出2,prev = 2,2出栈;
    ……………….
void BTreePostOrderNonR(BTNode* w)
{
    Stack s;
    StackInit(&s);
    BTNode* cur = root;
    BTNode* top = NULL;
    BTNode* prev = NULL;//z

    while (cur != NULL || StackEmpty(&s) != 0)
    {
        while (cur != NULL)
        {
            StackPush(&s, cur);
            cur = cur->_left;
        }

        top = StackTop(&s); 
        //判断top的右树有没有访问过

        if (NULL == top->_right || top->_right == prev)
        {
            printf("%d ", top->_data);
            prev = top;
            StackPop(&s);
        }
        else
        {
            //右子树还没有访问过,子问题方式访问
            cur = top->_right;
        }
    }
}

五、求树的节点个数

思路:一棵树的节点个数 = 它左子树节点个数 + 它右子树节点个数 + 加它本身

size_t BTreeSize(BTNode* root)//节点个数
{
    if (NULL == root)
    {
        return 0;
    }
    //转换成子问题:树节点个数等于左子树节点个数 + 右子树节点个数 + 加自己
    return BTreeSize(root->_left) + BTreeSize(root->_right) + 1;
}

六、求树的叶子个数

size_t BTreeLeafSize(BTNode* root) //计算树叶子的数量
{
    if (NULL == root)
    {
        return 0;
    }

    if (root->_left == NULL && root->_right == NULL)
    {
        return 1;
    }

    return BTreeLeafSize(root->_left) + BTreeLeafSize(root->_right);
}

七、求第K层节点个数

思路:树tree第K层节点个数 = 它左子树第K-1层节点个数 + 它右子树第K-1层节点个数

size_t BTreeKLevelSize(BTNode* root, size_t k)
{
    if (NULL == root)
    {
        return 0;
    }

    if (1 == k)
    {
        return 1;
    }

    return BTreeKLevelSize(root->_left, k - 1) + BTreeKLevelSize(root->_right, k - 1);
}

八、求树的深度

思路:一棵树的深度 = 它左、右子树深度较大的那个子树的深度 + 1

size_t BTreeDepth(BTNode* root)
{
    if (NULL == root)
    {
        return 0;
    }

    size_t leftDepth = BTreeDepth(root->_left);
    size_t rightDepth = BTreeDepth(root->_right);
    //树的深度 = 它左右两个子树深度较大的那个 + 1;
    return leftDepth > rightDepth ? leftDepth + 1 : rightDepth + 1;
}

九、在树中查找指定节点

BTNode* BTreeFind(BTNode* root, BTSTDataType x)
{
    if (NULL == root)
    {
        return NULL;
    }

    if (x == root->_data)
    {
        return root;
    }

    BTNode* leftRet = BTreeFind(root->_left, x);
    if (leftRet != NULL)
    {
        return leftRet;
    }

    BTNode* rightRet = BTreeFind(root->_right, x);
    if (rightRet != NULL)
    {
        return rightRet;
    }

    return NULL;
}

十、层序遍历

思路:创建一个队列q并初始化;
1. 根节点1入队,*front = 1,输出1,1出队;
2. 把1的左、右孩子2和5入队;
3. *front = 2,输出2,2出队;
4. 把2的左、右孩子3和5入队;
5. *front = 5,输出5,5出队;
6. 把5的左孩子6入队(5的右孩子为NULL);
………………….

void BTreeLevelOrder(BTNode* root)
{
    Queue q;
    QueueInit(&q);

    if (root != NULL)
    {
        QueuePush(&q, root);
    }
    while (QueueEmpty(&q) != 0)
    {
        BTNode* front = QueueFront(&q);
        printf("%d ", front->_data);
        QueuePop(&q);

        if (front->_left != NULL)
        {
            QueuePush(&q, front->_left);
        }
        if (front->_right != NULL)
        {
            QueuePush(&q, front->_right);
        }
    }
}

十一、判断一棵树是否为完全二叉树(方法1)

1. 方法一

思路:采用和上一题相似的方法,把树的节点按层入队,当遇到NULL时,入队部分结束,进入下一个循环,把队列里的元素出队,如果此时队列的元素都是NULL,那这棵树就是完全二叉树;如果还有非空元素,那就是非完全二叉树。

int IsCompleteBTree(BTNode* root)// 判断完全二叉树 
{
    Queue q;
    QueueInit(&q);

    if (root != NULL)
    {
        QueuePush(&q, root);
    }
    while (QueueEmpty(&q) != 0)
    {
        BTNode* front = QueueFront(&q);
        QueuePop(&q);

        if (NULL == front)
        {
            break;
        }
        else
        {
            QueuePush(&q, front->_left);
            QueuePush(&q, front->_right);
        }
    }

    while (QueueEmpty(&q) != 0)
    {
        BTNode* front = QueueFront(&q);

        if (front != NULL)
        {
            return 0; //不是完全二叉树
        }
        QueuePop(&q);
    }
    return 1; //是完全二叉树
}

2. 方法二

思路:利用一个flag变量,先还是层序的方法进出队,遇到NULL时,flag = 0;如果下次再出队的遇到非空元素且此时flag = 0,那这就是非完全二叉树。

int IsCompleteBTree1(BTNode* root)// flag的方式判断  非递归遍历 
{
    Queue q;
    QueueInit(&q);
    int flag = 1;

    if (root != NULL)
    {
        QueuePush(&q, root);
    }
    while (QueueEmpty(&q) != 0)
    {
        BTNode* front = QueueFront(&q);
        QueuePop(&q);

        if (front->_left != NULL)
        {
            if (0 == flag)
            {
                return 0;
            }

            QueuePush(&q, front->_left);
        }
        else
        {
            flag = 0;
        }

        if (front->_right != NULL)
        {
            if (0 == flag)
            {
                return 0;
            }

            QueuePush(&q, front->_right);
        }
        else
        {
            flag = 0;
        }
    }
    return 1;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值