二叉树总结

//二叉树节点定义:
struct BinaryTreeNode
{
    int m_nValue;
    BinaryTreeNode* m_pLeft;
    BinaryTreeNode* m_pRight;
};
/*
 *       二叉树中节点的个数
 *用递归解比较好:如果二叉树为空,节点树为0;不为空,二叉树的节点个数= 左子树 + 右子树 +1;
 **/
int GetNodeNum(BinaryTreeNode * pRoot)
{
    if (pRoot == NULL)
    {
        return 0;
    }
    else
    {
        return GetNodeNum(pRoot->m_pLeft) + GetNodeNum(pRoot->m_pRight) + 1;
    }
}
/*
 *         求二叉树的深度
 * 用递归解比较好:如果二叉树的深度为空,返回0.
 * 不为空,那么二叉树的深度就是max(左子树深度,右子树深度);  
 **/
int GetDepth(BinaryTreeNode* pRoot)
{
    if (pRoot == NULL)
    {
        return 0;
    }
    int depthLeft = GetDepth(pRoot->m_pLeft);
    int depthRight = GetDepth(pRoot->m_pRight);
    return depthLeft > depthRight ? (depthLeft + 1) : (depthRight + 1);
}
/*
 *          前序遍历, 中序遍历,后序遍历
 *前序遍历思路递归:如果二叉树为空,空操作;
 *          不为空, 访问根,左 ,右
 *  中序和后序是顺序不一样罢了!改改顺序
 **/
void PreOrderTraverse(BinaryTreeNode* pRoot)
{
    if (pRoot == NULL)
    {
        return;
    }
    print(pRoot); //访问根节点
    PreOrderTraverse(pRoot->m_pLeft);//前序遍历左子树
    PreOrderTraverse(pRoot->m_pRight);//前序遍历右子树
}
/*
 *          分层遍历二叉树(按层次从上往下,从左往右)
 *思路:类似于广度优先遍历,使用队列实现, 队列初始化,将根节点压入队列。当队列不为空的时候弹出节点访问,
 *若左子结点或右子节点不为空,入队。解释的不是很清楚,看代码吧, 结合起来理解可能会好一点。
 **/
void LevelTraverse(BinaryTreeNode* Root)
{
    if (Root == NULL)
    {
        return;
    }
    queue<BinaryTreeNode *> q;
    q.push(Root);
    while (!q.empty())
    {
        BinaryTreeNode * pNode = q.front();
        q.pop();
        visit(pNode);
        if (pNode->m_pLeft != NULL)
        {
            q.push(pNode->m_pLeft);
        }
        if (pNode->m_pRight != NULL)
        {
            q.push(pNode->m_pRight);
        }
    }
    return;
}
/*
 *              将二叉查找树变为有序的双向链表(要求不能创建新的节点,只能调整指针)
 *递归:如果二叉查找树为空,不需要转换,对应双向链表的第一个节点为NULL,最后一个节点是NULL。
 *如果左子树为空,对应双向有序链表的第一个节点是根节点,左边不需要其他操作;如果左子树不为空,
 *转换左子树,二叉查找树对应双向有序链表的第一个节点就是左子树转换后双向有序链表的第一个节点,
 *同时将根节点和左子树转换后的双向有序链表的最后一个节点链接;
 *如果左子树为空,对应双向有序链表的最后一个节点是根节点,右边不需要其他操作。如果不为空,
 *对应双向链表的最后一个节点就是右子树装换后双向有序链表的最后一个节点,同时将根节点
 *和右子树装换后的双向有序链表的第一个节点链接。
 **/
/*
 *Root 二叉查找树的根节点指针
 *pFirstNode 转换后双向有序链表的第一个节点指针。
 *pLastNode 转换后双向有序链表的最后一个节点指针。
 **/
void Convert(BinaryTreeNode* Root, BinaryTreeNode* &pFirstNode, BinaryTreeNode* &pLastNode)
{
    BinaryTreeNode *pFirstLeft, *pFistRight, *pLastRight, *pLastLeft;
    if (Root == NULL)
    {
        pFirstNode = NULL;
        pLastNode = NULL;
        return;
    }
    if (Root->m_pLeft == NULL)
    {
        //如果左子树为空,对应双向有序链表的第一个节点是根节点。
        pFirstNode = Root;
    }
    else
    {
        Convert(Root->m_pLeft, pFirstLeft, pLastLeft);
      //二叉查找树对应双向有序链表的第一个节点就是左子树转换后双向有序链表的第一个节点。
        pFirstNode = pFirstLeft;
        //将根节点和左子树转换后的双向链表的最后一个节点连接;
        Root->m_pLeft = pLastLeft;
        pLastLeft->m_pRight = Root;
    }
    if (Root->m_pRight ==NULL)
    {
        pLastNode = Root;
    }
    else
    {
        Convert(Root->m_pRight, pFistRight, pLastRight);
        pLastNode = pLastRight;
        Root->m_pRight = pFistRight;
        pFistRight->m_pLeft = Root;
    }
    return;
}
/*
 *          二叉树第k层的节点个数
 *递归解法:如果二叉树为空或者k<1,返回0;如果不为空且k=1,返回1;
 *如果二叉树不为空且k>1;返回左子树中k-1层节点的个数和右子树k-1层节点的个数的和。
 **/
int GetNodeNumKthLevel(BinaryTreeNode* Root, int k)
{
    if (Root == NULL|| k<1)
    {
        return 0;
    }
    if (k == 1)
    {
        return 1;
    }
    int numLeft = GetNodeNumKthLevel(Root->m_pLeft, k - 1);
    int numRight = GetNodeNumKthLevel(Root->m_pRight, k - 1);
    return numLeft + numRight;
}
/*
 *      二叉树中叶子节点的个数
 *递归解法:如果二叉树为空 返回0;
 *如果二叉树不为空,但只有一个根节点 返回1;
 *如果二叉树不为空,且左右子树不同时为空,返回左子树和右子树叶子节点的个数。
 **/
int GetLeafNum(BinaryTreeNode* Root)
{
    if (Root == NULL)
    {
        return 0;
    }
    if (Root->m_pLeft ==NULL&&Root->m_pRight==NULL)
    {
        return 1;
    }
    int numLeft = GetLeafNum(Root->m_pLeft);
    int numRight = GetLeafNum(Root->m_pRight);
    return numRight + numLeft;
}
/*          判断两颗二叉树是否相同
 *结构相同意味着对应的左子树和对应的右子树的结构都相同。
 *递归解法:
 *如果两颗二叉树都为空,返回真。 如果一个为空,一个不为空返回假。
 *如果两颗二叉树都不为空,就看左右子树是否相同,其他返回假。
 **/
bool StructureCmp(BinaryTreeNode* Root1, BinaryTreeNode* Root2)
{
    if (Root2== NULL && Root1==NULL)
    {   
        return true;
    }   
    else if (Root1==NULL||Root2==NULL)
    {
        return false;
    }
    bool leftResult = StructureCmp(Root1->m_pLeft, Root2->m_pLeft);
    bool rightResult = StructureCmp(Root1->m_pRight, Root2->m_pRight);
    return (leftResult&rightResult);
}
/*  判断二叉树是不是平衡二叉树
 *递归解法: 如果为空,返回真。
 *如果不为空,如果左右子树都是AVL树并且左右子树的高度差相差不大于1,返回真;否则,返回假;
 **/
bool IsAVL(BinaryTreeNode* Root,int &Hight)
{
    if (Root == NULL)
    {
        Hight = 0;
        return true;
    }
    int hightLeft;
    bool resultLeft = IsAVL(Root->m_pLeft,hightLeft);
    int hightRight;
    bool resultRight = IsAVL(Root->m_pRight,hightRight):
    if (resultLeft && resultRight && abs(hightRight - hightLeft) <=1)
    {
        Hight = max(hightLeft, hightRight) + 1;
        return true;
    }
    else
    {
        Hight = max(hightLeft, hightRight) + 1;
        return false;
    }
}
/*
 *        二叉树的镜像
 *递归解法: 如果二叉树为空,返回空;
 *如果不为空,求左右子树的镜像, 然后交换左子树和右子树;
 **/
BinaryTreeNode* Mirror(BinaryTreeNode* Root)
{
    if (Root == NULL)
    {
        return NULL;
    }
    BinaryTreeNode* pLeft = Mirror(Root->m_pLeft);
    BinaryTreeNode* pRight = Mirror(Root->m_pRight);
    //交换左子树和右子树
    Root->m_pLeft = pRight;
    Root->m_pRight = pLeft;
    return Root;
}
/*      求二叉树中两个节点的最低公共祖先节点
 *递归:如果两个节点分别在根节点的左子树和右子树,则返回根节点。
 *如果:两个节点都在左子树,则递归处理左子树,若都在右子树,递归处理右子树;
 **/
bool FindNode(BinaryTreeNode* Root, BinaryTreeNode* pNode)
{
    if (pRoot == NULLl || pNode == NULL)
    {
        return false;
    }
    if (Root == pNode)
    {
        return true;
    }
    bool found = FindNode(Root->m_pLeft, pNode);
    if (!found)
    {
        found = FindNode(Root->m_pRight, pNode);
    }
    return found;
}
BinaryTreeNode* GetLastCommonParent(BinaryTreeNode* Root, BinaryTreeNode* pNode1, BinaryTreeNode* pNode2)
{
    if (FindNode(Root->m_pLeft,pNode1))
    {
        if (FindNode(Root->m_pRight,pNode2)
        {
            return Root;
        }
        else
        {
            return GetLastCommonParent(Root->m_pLeft, pNode1, pNode2);
        }
    }
    else
    {
        if (FindNode(Root->m_pLeft, pNode2))
        {
            return Root;
        }
        else
        {
            return GetLastCommonParent(Root->m_pRight, pNode1, pNode2);
        }
    }
}
/*递归解法效率,有很多重复的遍历,看一下非递归解法。
 *先求从根节点到两个节点的路径,然后再比较对应路径的节点就行,最后一个相同的节点,也就是
 *他们在二叉树中的最低公共祖先节点。
 **/
bool GetNodePath(BinaryTreeNode* Root, BinaryTreeNode* Node, list<BinaryTreeNode*> &path)
{
    if (Root == pNode)
    {
        path.push_back(Root);
        return true;
    }
    if (Root == NULL)
    {
        return false;
    }
    path.push_back(Root);
    bool found = GetNodePath(Root->m_pLeft, pNode, path);
    if (!found)
    {
        found = GetNodePath(Root->m_pRight, pNode, path);
    }
    if (!found)
    {
        path.pop_back();
    }
    return found;
}
BinaryTreeNode* GetLastCommonParent(BinaryTreeNode* Root, BinaryTreeNode* pNode1, BinaryTreeNode* pNode2)
{
    if (Root->NULL || pNode1 == NULL || pNode2 == NULL)
    {
        return  NULL;
    }
    list<BinaryTreeNode*> path1;
    bool bResult1 = GetNodePath(Root, pNode1, path1);
    list<BinaryTreeNode*> path2;
    bool bResult2 = GetNodePath(Root, pNode2, path2);
    if (!bResult1 || !bResult2)
    {
        return NULL;
    }
    BinaryTreeNode* pLast = NULL;
    list<BinaryTreeNode*>::const_iterator iter1 = path1.begin();
    list<BinaryTreeNode*>::const_iterator iter2 = path2.begin();
    while (iter1 != pahth1.end() && iter2!= path2.end())
    {
        if (*iter1 == *iter2)
        {
            pLast = *iter1;
        }
        else
        {
            break;
        }
        iter1++;
        iter2++;
    }
    return pLast;
}
/*
 *          求二叉树中接节点的最大距离(二叉树中相距最远的两个节点之间的距离)
 *如果二叉树为空,返回0,同时记录左子树和右子树的深度,都为0;
 *如果二叉树不为空,最大距离要么是左子树的最大距离要么是右子树的最大距离,要么是左子树节点中到根节点的最大距离+
 *右子树节点到根节点的最大距离。同时记录左子树和右子树节点到根节点的最大距离。
 **/
int GetMaxDistance(BinaryTreeNode* Root, int& maxLeft, int& maxRight)
{
    if (Root == NULL)
    {
        maxLeft = 0;
        maxRight = 0;
        return 0;
    }
    int maxLL, maxLR, maxRL, maxRR;
    int maxDistLeft, maxDisRight;
    if (Root->m_pLeft != NULL)
    {
        maxDistLeft = GetMaxDistance(Root->m_pLeft, maxLL, maxLR);
        maxLeft = max(maxLL, maxLR) + 1;
    }
    else
    {
        maxDistLeft = 0;
        maxLeft = 0;
    }
    if (Root->m_pRight != NULL)
    {
        maxDisRight = GetMaxDistance(Root->m_pRight, maxRL, maxRR);
        maxRight = max(maxRL, maxRR) + 1;
    }
    else
    {
        maxDisRight = 0;
        maxRight = 0;
    }
}
/*          判断二叉树是不是完全二叉树
 *若设二叉树的深度为h,除第h层外,其他各层(1~h-1)的节点数3都达到了最大个数,第h层的节点都连续集中在
 *最左边,这就是完全二叉树。
 *按层次(从上到下,从左到右)遍历二叉树,当遇到一个节点的左子树为空时,则该节点的右子树必须为空,则后面
 *遍历的节点左右子树都必须为空,否则不是完全二叉树。
 **/
bool IsCompleteBinaryTree(BinaryTreeNode* Root)
{
    if (Root == NULL)
    {
        return false;
    }
    queue<BinaryTreeNode*> q;
    q.push(Root);
    bool  mustHaveNoChild = false;
    bool result = true;
    while (!q.empty())
    {
        BinaryTreeNode* Node = q.front();
        q.pop();
        if (mustHaveNoChild)
        {
            if (Node->m_pLeft!=NULL||Node->m_pRight!=NULL)
            {
                retuslt = false;
                break;
            }
            else
            {
                if (Node->m_pLeft!=NULL && Node->m_pRight!= NULL)
                {
                    q.push(Node->m_pLeft);
                    q.push(Node->m_pRight);
                }
                else if (Node->m_pLeft != NULL && Node->m_pRight == NULL)
                {
                    mustHaveNoChild = true;
                    q.push(Node->m_pLeft);
                }
                esle if (Node->m_pLeft == NULL && Node->m_pRight != NULL)
                {
                    result = false;
                    break;
                }
                else
                {
                    mustHaveNoChild = true;
                }
            }
        }
    }
    return false;
}
/*              由前序遍历和中序遍历重建二叉树
 *二叉树前序遍历序列中,第一个元素总是树的根节点的值。中序遍历序列中,左子树的节点的值位于根节点的左边,
 *右子树的值总在根节点的右边。
 *递归解法:如果前序遍历的结果为空或者中序遍历的结果为空,返回NULL。
 *创建根节点,前序遍历的第一个数据就是根节点的数据,在中序遍历中找到根节点的位置,可分别到知,左子树和右子树
 *的前序和中序遍历序列,重建左右子树。
 *同样的有:中序遍历和后序遍历序列,类似的可以重建一颗二叉树,但是前序遍历序列和后序遍历序列不能重建一颗二叉树。
 **/
BinaryTreeNode* reBuildingTree(int *PreOder, int* InOder, int nodeNum)
{
    if (PreOder == NULL || InOder ==NULL ||nodeNum <= 0)
    {
        return NULL;
    }
    BinaryTreeNode* Root = new BinaryTreeNode;
    //前序遍历的第一个节点就是根节点。
    Root->m_nValue = PreOder[0];
    Root->m_pLeft = NULL;
    Root->m_pRight = NULL;
    //查找根节点所在中序遍历中的位置,中序遍历中,根节点左边变为左子树,右边变为右子树。
    int rootPositionInorder = -1;
    for (int  i = 0; i < nodeNum; i++)
    {
        if (InOder[i] == Root->m_nValue)
        {
            rootPositionInorder = i;
            break;
        }
    }
    if (rootPositionInorder  == -1)
    {
        throw std::exception("Invalid input");
    }
    //left tree
    int nodeNumLeft = rootPositionInorder;
    int *preoderLeft = PreOder + 1;
    int *inoderLeft = InOder;
    Root->m_pLeft = reBuildingTree(preoderLeft, inoderLeft, nodeNumLeft);
    //right tree
    int nodeNumRight = nodeNum - nodeNumLeft - 1;
    int *preoderright = PreOder + 1 + nodeNumLeft;
    int *inorderright = InOder + nodeNumLeft + 1;
    Root->m_pRight = reBuildingTree(preoderright, inorderright, nodeNumRight);
    return Root;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值