数据结构-二叉树遍历及应用(非递归版本)

//先序遍历

void BinTreePreOrderLoop(BinTreeNode* root)
{
      //空树,直接返回
      if(root==NULL)
      {
            return ;
      }
      //定义一个栈,并初始化
      SeqStack stack;
      SeqStackInit(&stack);
      //定义一个节点,保存当前元素
      BinTreeNode* cur=NULL;
      //先入栈根节点
      SeqQueuePush(&stack,root);

       //循环取栈顶元素为当前元素(栈为空,循环结束)
       while(SeqStacKTop(&stack,&cur))
       {

                // 出栈当前元素
                SeqStackPop(&stack);
                //访问当前元素
                printf("%c ",cur->data);
                //把当前元素的右子树入栈
                SeqStackPush(&stack,cur->pright);
                //把当前元素的左子树入栈
                SeqStackPush(&stack,cur->pleft);
            }

      //循环结束,返回
      return ;

}
//中序遍历(非递归)
void BinTreeInOrderLoop(BinTreeNode* root  )
{
      //空树,直接返回
      if(root==NULL)
      {
            return ;
      }
      //定义一个栈并初始化
      SeqStack stack;

      SeqStackInit(&stack);
      //定义一个节点,指向根节点
      BinTreeNode* cur=root;
      while( 1)
      {    
            //判断当前节点是否为空,不为空,将当前元素出栈,
            //并且将cur=cur-
            while(  cur)
            {
                  SeqStackPush(&stack,cur);
                  cur=cur->pleft;
            }
             //为空,循环取栈顶元素,访问,出栈
              //让cur=cur->pright,重复上面步骤
            BinTreeNode* top=NULL;
            while(SeqStacKTop(&stack,&top))
            {
                  printf(  "%c ",cur->data);
                  SeqStackPop(&stack);

            }
            cur=cur->pleft;
      }
      return ;

}
//后序遍历
void BinTreePostOrderLoop(  BinTreeNode* root)
{
      if(root==NULL)
      {
            return ;
      }

      SeqStack stack;
       //定义一个指针cur指向root,用于保存当前节点
      BinTreeNode* cur=root;
      //定义一个指向当前节点的前一个节点
      BinTreeNode* pre=NULL;
      while( 1)
      {
            //循环判断当前节点是否为空,不为空,出栈当前元素,
            //,并且cur=cur->pleft
            while(cur)
            {
                  SeqStackPush(&stack,cur);
                  cur=cur->pleft;
            }
            //为空,循环取栈顶元素,

            BinTreeNode top=NULL;
            while(SeqStacKTop(&stack,&top))
            {
                  //对栈顶元素进行判定:如果栈顶元素的右子树为空,或者栈顶元素与访问元素的前一个元素不相同
                if(top->pleft==NULL||top->pright!=pre)
                {
                    //访问,并出栈,修改pre的值
                    printf("%c  ",top->data);
                    SeqStackPop(&stack);
                    pre=cur;
                }
                //如果不满足上面条件,让cur=cur->pright,重复上面步骤
                else
                {
                    cur=cur->pright;

                }
            }
            return ;
      }

}
求二叉树镜像(递归)
void BinTreeMirrorR(BinTreeNode* root)
{
      if(  root==NULL)
      {
            return ;
      }
      Swap(&root->pleft,root->pright);
      BinTreeMirrorR(root->pleft);
      BinTreeMirrorR(root->pright);
      return ;
      //层序遍历二叉树,将打印式访问变成交换当前节点的左右孩子
}
//求二叉树镜像,非递归(层序遍历二叉树,将打印式访问变成交换当前节点的左右孩子)
void BinTreeMirror(BinTreeNode*  root)
{
      if(root==NULL)
      {
            return ;
      }
      //定义一个队列,并初始化
      SeqQueue q;
      SeqQueueInit(&q);
      //将根节点入队列
      SeqQueuePush(&q,root);
      //定义一个节点,保存队首元素
      SeqQueue *cur=NULL;
      //循环判断队列是否为空,不为空,则进行交换当前节点的左右子树
      while(SeqQueueFront(&q,&cur))
      {
            Swap(&cur->pleft,&cur->pright);
            //将当前元素出队列
            SeqQueuePop(&q);
            //将当前元素的左子树入队
            if(cur->pleft)
            {
                  SeqQueuePush(&q,cur->pleft);
            }
            //将当前元素的右子树入队
            if(cur->pright)
            {
                  SeqQueuePush(&q,cur->pright);
            }
      }
      return ;
}
//判断是否是完全二叉树
int IsCompelteTree(BinTreeNode *root)
{
      if(root==NULL)
      {
            return 0;
      }
       //定义一个队列,并初始化
      SeqQueue q;
      SeqQueueInit(&q);
      //将根节点入队列
      SeqQueuePush(&q,root);
      //定义一个标志位,标志位为0,表示不需要进入第二阶段,标志位为1,需要进入第二阶段判断
      int flag=0;
      //定义一个cur,保存栈顶值
      BinTreeNode* cur=NULL;
      while(SeqQueueFront(&q,&cur))
      {

            SeqQueuePop(&q);
            //阶段一判断
            if(flag==0)
            {      
                  //如果左右子树均不为空,则说明是完全二叉树,不需要进入第二阶段

                  if(cur->pleft!=NULL&&cur->pright!=NULL)
                  {
                         //将左右子树入队
                         SeqQueuePush(&q,cur->pleft);
                        SeqQueuePush(&q,cur->pright);
                  }
                  //一旦出现一个节点只有右子树,则一定不是完全二叉树,返回0
                  else if(cur->pleft==NULL&&cur->pright!=NULL)
                  {
                        return 0;
                  }
                  //若当前节点只有左子树,将flags置为1,将cur的右子树入队,并进入第二阶段判断
                  else if(cur->pleft!=NULL&&cur->pright==NULL)
                  {
                        flag=1;
                        SeqQueuePush(cur->pleft);
                  }
                 // 若当前节点,没有左右子树,将flags置为1,也进入阶段二
                  else
                  {
                        flag=1;
                  }
            }
            //阶段二判断
            else
            { 
                  //任何节点都必须没有左右子树,则是完全二叉树,否则不是完全二叉树
                  if(cur->pleft==NULL&&cur->pright==NULL)
                  {
                        ;
                  }
                  else
                  {
                        return 0;
                  }
            }
      }
      //当遍历结束,所有条件满足,没有出现返回值0,则一定是完全二叉树,返回1
      return 1;


}

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针

这里写图片描述

class Solution {
public:
    TreeLinkNode* GetNext(TreeLinkNode* pNode)
    {
        if(pNode==NULL)
        {
            return NULL;
        }
        TreeLinkNode* next=NULL;
        //有右子树,返回该右子树的最左孩子
        if(pNode->right!=NULL)
        {
             TreeLinkNode* RightNode=pNode->right;
            while(RightNode->left!=NULL)
            {
                RightNode=RightNode->left;
            }
            next=RightNode;
        }
        //遍历父节点
        else if(pNode->next!=NULL)
        {
            TreeLinkNode* parentnode=pNode->next;
            TreeLinkNode* curnode=pNode;
            while(curnode->next!=NULL&&curnode==parentnode->right)
            {
                curnode=parentnode;
                parentnode=parentnode->next;

            }
            next=parentnode;

        }
        return next;

    }
};

重构二叉树

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

这里写图片描述

1.创建根节点,根节点肯定是前序遍历的第一个数
2.找到中序遍历根节点所在位置,存放于变量gen中
3.//对于中序遍历,根节点左边的节点位于二叉树的左边,根节点右边的节点位于二叉树的右边
4.利用上述这点,对二叉树节点进行归并
和shell排序的思想类似,取出前序和中序遍历根节点左边和右边的子树
5.递归,再对其进行上述所有步骤,即再区分子树的左、右子子数,直到叶节点

class Solution {

    public:

        struct TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> in) {

            int inlen=in.size();

            if(inlen==0)

                return NULL;

            vector<int> left_pre,right_pre,left_in,right_in;

            //创建根节点,根节点肯定是前序遍历的第一个数

            TreeNode* head=new TreeNode(pre[0]);

            //找到中序遍历根节点所在位置,存放于变量gen中

            int gen=0;

            for(int i=0;i<inlen;i++)

            {

                if (in[i]==pre[0])

                {

                    gen=i;

                    break;

                }

            }

            //对于中序遍历,根节点左边的节点位于二叉树的左边,根节点右边的节点位于二叉树的右边

            //利用上述这点,对二叉树节点进行归并

            for(int i=0;i<gen;i++)

            {

                left_in.push_back(in[i]);

                left_pre.push_back(pre[i+1]);//前序第一个为根节点

            }

            for(int i=gen+1;i<inlen;i++)

            {

                right_in.push_back(in[i]);

                right_pre.push_back(pre[i]);

            }

            //和shell排序的思想类似,取出前序和中序遍历根节点左边和右边的子树

            //递归,再对其进行上述所有步骤,即再区分子树的左、右子子数,直到叶节点

           head->left=reConstructBinaryTree(left_pre,left_in);

           head->right=reConstructBinaryTree(right_pre,right_in);

           return head;

        }

    };
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值