二叉树算法

问题一:完成一个函数,输入一颗二叉树,该函数输出它的镜像。二叉树节点定义如下:

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

解题思路:二叉树的镜像过程可以理解为所有左右子节点交换的过程,先前序遍历这个树的每个节点,如果遍历到的节点有子节点,就交换它的两个子节点。当交换完所有非叶节点的左右子节点后,就得到了树的镜像。

void GetMirrorTree(BinaryTreeNode * pNode)
{
    if(pNode == nullptr)
        return;
    if(pNode->m_pLeft == nullptr && pNode->m_pRight == nullptr)
        return;

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

    if(pNode->m_pLeft)
        GetMirrorTree(pNode->m_pLeft);
    if(pNode->m_pRight)
        GetMirrorTree(pNode->m_pRight);
}

问题二:实现一个函数,用来判断一棵二叉树是不是对称的。如果一个二叉树和它的镜像一样,那么它是对称的。

解题思路:利用二叉树遍历算法,二叉树一共有前序遍历、中序遍历和后序遍历。前序遍历是先遍历父节点,再遍历它的左子节点,最后遍历它的右子节点;定义一种类前序遍历的遍历算法:先遍历父节点,再遍历它的右子节点,最后遍历它的左子节点,如果两种遍历算法遍历的结果是一样的,那么二叉树就是对称的。

bool isSymmetry(BinaryTreeNode *pNode1, BinaryTreeNode *pNode2)
{
    if(pNode1 == nullptr && pNode2 == nullptr)
        return true;

    if(pNode1 == nullptr || pNode2 == nullptr)
        return false;

    if(pNode1->m_nValue != pNode2->m_nValue)
        return false;

    return isSymmetry(pNode1->m_pLeft, pNode2->m_pRight) &&
           isSymmetry(pNode1->m_pRight, pNode2->m_pLeft);
}

bool isSymmetrical(BinaryTreeNode *pNode)
{
    return isSymmetry(pNode, pNode);
}

问题三:从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

解题思路:这其实是一种二叉树遍历方法,只不过不是前序、中序和后序遍历。可以这样考虑,先打印根节点,然后把根节点的两个子节点保存到一个容器中,此时,容器里就有两个节点了,然后取出容器中第一个节点打印,并把该节点的两个自己欸但放入容器后面,以此方法处理。从容器中取数按照先入先出的方法,因此容器应该是一个队列。

void PrintNodeFromTopToBottom(BinaryTreeNode *pTreeRoot)
{
    if(!pTreeRoot)
        return;

    std::deque<BinaryTreeNode *> dequeTreeNode;

    dequeTreeNode.push(pTreeNode);

    while(dequeTreeNode.size())
    {
        BinaryTreeNode *pNode = dequeTreeNode.front();
        dequeTreeNode.pop();

        printf("%d ", dequeTreeNode->m_nValue);
        if(pNode->m_pLeft)
            dequeTreeNode.push_back(pNode->m_pLeft);

        if(pNode->m_pRight)
            dequeTreeNode.push_back(pNode->m_pRight);
    }
}

问题四:从上到下按层打印二叉树,同一层的节点按从左到右的顺序打印,每一层打印到一行。

解题思路:和上面的题一样,通过一个队列来保存将要打印的节点,另外为了把二叉树的每一行打印到一行里,需要两个变量,一个用来表示当前层中还没有打印的节点,另一个用来表示下一层节点的数目。

void PrintHierarchy(BinaryTreeNode *pTreeRoot)
{
    if(pTreeRoot == nullptr)
        return;

    std::queue<BinaryTreeNode*> nodes;
    nodes.push(pTreeRoot);
    int nextLevel = 0;
    int toBePrinted =1;

    while(!node.size())
    {
        BinaryTreeNode *pNode = nodes.front();
        printf("%d ", pNode->m_nValue);
        
        if(pNode->m_pLeft)
        {
            nodes.push(pNode->m_pLeft);
            ++nextLevel;
        }
        if(pNode->m_pRight)
        {
            nodes.push(pNode->m_pRight);
            ++nextLevel;
        }

        nodes.pop();
        --toBePrinted;
        if(toBePrinted == 0)
        {
            printf("\n");
            toBePrinted = nextLevel;
            nextLevel = 0;
        }
    }
}

问题五:之字形打印二叉树,实现一个函数按照之字形顺序打印二叉树,即第一行从左到右的顺序打印,第二行从右到左的顺序打印,第三行又是从左到右的顺序打印,一次类推。

解题思路:按之字形顺序打印二叉树需要两个栈,我们再打印某一层节点时,把下一层的子节点保存到相应的栈里。如果当前打印的时奇数层,则先保存左子节点再保存右子节点到第一个栈里;如果当前打印的时偶数层,则先保存右子节点再保存左子节点到第二个栈里。

void Print(BinaryTreeNode *pTreeRoot)
{
    if(pTreeRoot == nullptr)
        return;

    std::stack<BinaryTreeNode*> levels[2];
    int current = 0;
    int next  = 1;

    levels[current].push(pTreeRoot);
    while(!levels[0].empty() || !levels[1].empty())
    {
        BinaryTreeNode *pNode = levels[current].top();
        levels[current].pop();

        printf("%d ",pNode->m_nValue);
        
        if(current == 0)
        {
            if(pNode->m_pLeft != nullptr)
                levels[next].push(pNode->m_pLeft);
            if(pNode->m_pRight != nullptr)
                levels[next].push(pNode->m_pRight);
        }
        else
        {
            if(pNode->m_pRight != nullptr)
                levels[next].push(pNode->m_pRight);
            if(pNode->m_pLeft != nullptr)
                levels[next].push(pNode->m_pLeft);
        }

        if(levels[current].empty())
        {
            printf("\n");
            current = 1 - current;
            next = 1 - next;
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值