二叉树的非递归先序、中序、后序遍历

来源:互联网 发布:linux exp continue 编辑:程序博客网 时间:2024/05/21 18:48

算法思想:
先序:NLR的访问顺序,由于R节点,即右孩子的访问需要通过根节点的指针来实现,所以,需要设一个栈来存储根节点。具体看代码:

void preorder(btree t){ initstack(s);//初始化栈 btree p=t; while(p||!empty(s)){  if(p){//如果该节点非空   visit(p);//访问   push(s,p);//入栈,栈中元素全部非空   p=p->lchild;//走到最左  }  else{//空节点   pop(s,p);//退栈,栈中元素全部非空   p=p->lchild;//转向右子树  } }//while}

中序遍历和先序遍历几乎一样:

void midorder(btree t){ initstack(s); btree p=t; while(p||!empty(s)){  if(p){  push(s,p);  p=p->lchild;  }  else{  pop(s,p);  visit(p);  p=p->rchild;  } }}

后序遍历:LRN顺序。L和R都需要通过N的左右指针来指向,所以L和R未访问完之前,N都要放在栈内。具体为,从L返回时,N不能退栈,从R返回或R为空时,N退栈并访问。而要判断是从L返回还是后者,需要用一个指针r记录最近访问的节点来判断是从L还是R返回。

void postorder(btree t){ initstack(s); btree p=t,r=null;//r记录最近访问的节点,初始化为空 while(p||!empty(s)){  if(p){//走到最左   push(s,p);   p=p->lchild;  }  else{//p为空   gettop(s,p);//先获取栈顶,而不是退栈   if(p->rchild&&p->rchild!=r){//右孩子存在且未被访问过    //转向右子树并再走向左孩子    p=p->rchild;    push(s,p);    p=p->lchild;   }   else{//没有右孩子或者右孩子被访问过(从右边返回)    //退栈并访问该根节点    pop(s,p);    visit(p);    r=p;//用r记录最近访问的节点    p=null;//p置空,以防再次入栈   }//else  }//else }//while}

后序遍历的应用:找祖先,栈顶元素以下的元素全部为其祖先。具体为,把visit部分改为:依次输出栈内元素。
若找x、y的共同祖先,假设x在y的左边,则必然先遍历到x,此时先把栈内元素复制到另一个辅助栈(x的祖先),继续遍历到y时,依次退栈并和辅助栈中的元素比较,若遇到相等的则为共同祖先。

btree conancestor(btree t,btnode *x,btnode *y){//查找x,y的共同祖先并返回 initstack(s); initstack(s1);//辅助栈 btree p=t,r=null; while(p||!empty(s)){  if(p){   push(s,p);   p=p->lchild;  }  else{   gettop(s,p);   if(p->rchild&&p->rchild!=r){    p=p->rchild;    push(s,p);    p=p->lchild;   }   else{    pop(s,p);    if(p==x) stack s1=s;//将s栈中元素复制到辅助栈s1    if(p==y){     i=s1.top;     while(p!=s1.data[i]&&i>-1)      i--;     if(p==s1.data[i] return p;//找到共同祖先,返回p     pop(s,p);//没有找到,继续退栈    }//if(p==y)    r=p;    p=null;   }//else  }//else }//while}
阅读全文
1 0
原创粉丝点击