线索树(下)

补上一篇

基于上面的3个基本操作,下面是两种方式的遍历树
1,普通的非递归遍历二叉树(补充)
2,线索化的树上3种遍历方式

非递归遍历:
a,中序遍历
 思路:
 只要一直把树中最左的节点作为第一个节点输出即可,因此需要把搜索最左节点路径上的根节点存储起来,存储结构用栈(用于回溯) 一个临时节点temp(初始值为根节点),如果temp"非NULL"且存在左节点(非左线索), 则把左节点压入栈中(包括temp) 并把temp更新为temp的左节点,知道temp不存在 左节点(压入栈中);此时输出栈顶,同时栈顶节点如果存在右子树的,temp更新为 此节点的右节点,如果没有右子树(则"置temp为null")
代码:

template<class T>
void ttree<T>::iter_inorder( ){
    cout<<"非递归中序遍历:"<<endl;
    if(root->ltd) return;
    tree temp=root->lcd;
    stack<tree, vector<tree > > st;
    for(;;){
        for(; temp && !temp->ltd;temp=temp->lcd)
        st.push(temp);
        if(temp)st.push(temp);
        if(st.empty())break;
        temp=st.top();
        st.pop();
        cout<<temp->data<<" ";
        if(!temp->rtd) temp=temp->rcd;
	else temp=NULL;
     }
}
b.前序遍历(最简单)

思路:
 跟中序遍历的思路差不多,建立栈存储当前遍历的左节点及右节点
 简单,不用临时节点temp
 代码:

template<class T>
void ttree<T>::iter_preorder(){
    cout<<"非递归前序遍历:"<<endl;
    stack<tree, vector<tree> >st;
    if(root->ltd) return;
    tree temp=root->lcd;
    st.push(temp);
    for(;;){
        temp=st.top(); st.pop();
	cout<<temp->data<<" ";
	if(!temp->rtd) st.push(temp->rcd);
	if(!temp->ltd) st.push(temp->lcd);
	if(st.empty()) break;
    }		
}
c.后序遍历

思路:
 和中序遍历很接近,两者都是通过栈结构实现;跟中序遍历不同:前者只要让左节点先入栈;而后者是要保证左右节点都在根节点之前入栈;根据后序遍历的特点,后序遍历序列中根节点root一定是尾随其右子树根节点之后,因此可以设置一个标志前一个输出的节点,然后判断栈顶节点的右节点是否为标志节点->是:输出当前节点,置temp为NULL;否:栈顶节点右子树还没入栈,置temp为栈顶节点右子树的根节点
代码:

template<class T>
void ttree<T>::iter_postorder(){
    cout<<"非递归后序遍历:"<<endl;
    stack<tree, vector<tree> > st;
    if(root->ltd) return;
    tree temp=root->lcd;
    tree r=NULL; // tag the right tree 
    while(temp || !st.empty())
    {
        if(temp){
	    st.push(temp);
	    temp=temp->ltd? NULL:temp->lcd;
        }
        else{
            temp=st.top();
	    if(!temp->rtd && r!=temp->rcd){
	        temp=temp->rcd;
	    }
	    else {
	        st.pop(); cout<<temp->data<<" ";
	        r=temp; temp=NULL;
	    }
        }
    }
}
2,线索化的三种遍历:
a.中序遍历

 思路:

 在实现了求节点中序遍历后续节点的函数,中序遍历就基本上完成了,只要从根节点开始不断求后续节点即可

 代码:

template<class T>
void ttree<T>::tiorder()
{
    printf("线索中序遍历\n");
    tree temp=root;
    for(;;){
        temp=insucc(temp);
        if(temp==root) break;
	printf("%d ",temp->data);
    }
}
b.前序遍历
思路:
 前序遍历的遍历顺序是根 左子树 右子树;直接利用左链域可以遍历节点左子树,而从左子树返回到对应根节点的右子树,上面的非递归是用栈存储的,而在线索化的二叉树,可利用节点的后续节点找到左子树的根节点,而该根节点的右链域可以遍历其右子树由临时节点temp从右线索不断往会就可以找到根节点

代码: 

template <class T>
void ttree<T>::tpreorder()
{
    printf("线索前序遍历\n");
    if(root->ltd) return;
    tree temp=root->lcd;
    for(;temp;){
	 cout<<temp->data<<" ";
	 if(!temp->ltd) {
	     temp=temp->lcd;
	     continue;
	 }
	 if(!temp->rtd){
	     temp=temp->rcd;
	     continue;
	 }
	 if(temp->rcd==root) break;
	 while(temp->rtd)
	   temp=temp->rcd; //利用线索不断回溯
	 temp=temp->rcd; //所求的右子树
    }
}
c. 后序遍历

思路:
 我是通过求出一个节点在后序遍历中的后续节点,通过实现这个操作, 线索的后序遍历就跟线索的线索中序遍历的实现代码几乎一样,节点Node的后续节点(后序遍历):
先求出Node的父节点fNode,如果Node是fNode的右子树的根节点,则Node的后续节点就是fNode;否则Node的后续节点就是fNode的右子树的最左下节点
代码:

//后序遍历中的后继节点函数
template <class T>
tnode<T>* ttree<T>::lnsucc(tree& node)
{
    tree pnode=fPnode(node);
    if(pnode==node) return root;
    if(pnode->rtd || pnode->rcd==node) return pnode;
    else {	 //pnode 肯定有右子树
        pnode=pnode->rcd;  
	while(!pnode->ltd)
	  pnode=pnode->lcd;
	return pnode;
    }
}
			
template <class T>
void ttree<T>::tposorder()
{
    cout<<"线索后序遍历:"<<endl;
    if(root->ltd) return;
    tree temp=insucc(root);
    for(;temp!=root;) {
        cout<<temp->data<<" ";
        temp=lnsucc(temp);
    }		
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值