【数据结构】——二叉树的非递归遍历

之前的文章,我们详细的讲述了二叉树的创建、遍历等的实现,但是都是以递归的方式。其实我们知道递归的过程是一个不断开辟栈帧的过程,会影响算法的执行效率,那么这篇文章主要是站在C语言的角度为大家分析一下二叉树的非递归前序、中序、后序遍历~

1、二叉树的前序遍历
(1)第一步:建立一个二维指针,用来存储每一个结点的地址,定义栈顶指针top,初始化为-1,并将根结点存入栈中
(2)第二步:栈顶指针不为-1的时候就进入while循环,输出当前栈顶元素p的数据域,代表前序遍历的第一个结点为根结点
(3)第三步:如果当前的p结点拥有右子树,将这个右子树结点存入栈中,没有则不存(因为栈是先进后出,所以先存右子树,再存左子树)
(4)第四步:如果当前的p结点拥有左子树,将这个左子树结点存入栈中,没有则不存
(5)再判断top是否为-1,之后重复执行2,3,4步骤。

void  PreOrder(BitTree *bt)
{
 BitTree **s;
 BitTree *p;
 int top = -1;
 //创建栈
 s = (BitTree **) malloc((N+1)*sizeof(BitTree*));
 //初始化栈
 s[++top] = bt;
 //非递归前序遍历
 while(top != -1)
 {
  p = s[top--];
  printf("%c",p->ch);
  if(p->rchild)
   s[++top]=p->rchild;
  if(p->lchild)
   s[++top]=p->lchild;
 }
 free(s);
}

2、二叉树的中序遍历
(1)第一步:与非递归前序遍历相同,同样需要一个二维指针的栈,栈顶元素初始化为-1;
(2)首先if的判断条件,这个二叉树不为空
(3)再进入if条件语句中的while循环,这个循环是将根结点相连所有左子树全部存入栈中
(4)退出循环过后,再判断第二个while循环的条件,栈不为空,则进入while循环
(5)首先输出距离与根结点相连最远的左子树
(6)如果这个结点拥有右子树,先将这个右子树结点存入栈中
(7)再判断这个结点是否拥有左子树,有的话将与这个结点相连的所有左子树存入栈中,没有就不执行while循环
(8)在判断top是否为-1,成立进入循环,重复上述步骤即可;

void InOrder(BitTree *bt)
{
 BitTree **s;
 BitTree*p,*q;
 int top = -1;
 s = (BitTree **) malloc((N+1)*sizeof(BitTree*));//创建栈
 if(bt)
 {
  while(bt)//一直遍历左子树知道该结点的左子树空为止
  {
   s[++top] = bt;//将所有左孩子存入栈中
   bt =bt->lchild;//指向下一个左子树
  }
  while(top != 1)//栈空时结束循环
  {
   p = s[top--];//刚开始将p指向左下角的左孩子,并且移向该结点的父结点
   printf("%c",p->ch);//输出左下角的结点
   while(p->rchild)//遍历移动后结点有没有右结点
   {
    s[++top] = p->rcihld;//将这个结点的右子树入栈
    q = p->rchild;//这个右子树结点赋值给q
    while(q->lchild)//判断结点q有没有左子树
    {
     s[++top] = q->lchild;//有左子树,将与这个结点相连的所有左子树都入栈
     q = q->lchild;
    }
    break;//结束当前循环,回到第二个while循环继续刚才步骤
   }
  }
 }
}

3、二叉树的后序遍历

1> 同样建立一个二维指针的栈,用来存储每个结点的地址;
2> 进入do-while循环,首先,将与根结点相连的所有左子树都存入栈中;
3> 将BitTree类型的指针p赋空,判断while循环是否成立;
4> 如果这个最后一个结点的右子树==p,则输出当前结点的数据域,栈顶指针–;
5> 并将这个结点赋给指针p表示这个结点已经访问过,并且已经输出;
6> 如果当前结点的右子树!=p,则接着访问这个结点的右子树,并且结束while循环,判断do-while循环的判断条件;
7> 重复上述过程,知道不满足do-while循环的判断条件;

void PostOrder(BitTree* bt)
{
 BitTree **s;
 BitTree *p;
 int top = -1;
 s = (BitTree **) malloc((N+1)*sizeof(BitTree*));
 do
 {
  while(bt)//一直遍历左子树直到该左子树的左孩子为空为止
  {
   s[++top] = bt;//将所有左孩子存入栈中
   bt = bt->lchild;//指向下一个左结点
  }
  p = NULL;
  while(top != -1)
  {
   bt = s[top];
   if(bt->rchild == p)//p表示为空或者右子节点被访问过了
   {
    printf("%c",bt->ch);
    top --;
    p = bt;//p记录下刚刚访问的结点
   }
   else
   {
    bt = bt->rchild;//访问右子树结点
    break;
   }
  }
 }while(top != 1;
}
发布了62 篇原创文章 · 获赞 7 · 访问量 2579

猜你喜欢

转载自blog.csdn.net/qq_43412060/article/details/104379048