栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

二叉树非递归遍历【使用堆栈】[有误]

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

二叉树非递归遍历【使用堆栈】[有误]

 前中后序其实本质上都是同一条路径,只不过是print的时候不同。

这条路径对于每一个根结点来说都会经过三次,第一次就print是前序,第二次print是中序,第三次print就是后序。

 testcase:

124  5 67   38 9   【末尾三个空格。空格代表空树】

 中序遍历的片段:

//中序遍历 
void TraversalTree(TreeNode* tree){
	Stack stack;
	stack.top=NULL;
	TreeNode*p=tree;
	int flag=0;
	while(p){
		//flag标记左子树有没有遍历过,1:遍历过 
		while(p->left&&(!flag)){
			//当p为有左子树的根时,把p推入栈中 
			Push(&stack,p);
			p=p->left;
			//TODO
		}
		//1.若经历了循环,此时p为最尾部的左子树,打印。
		//2.若未经历循环,此时p为 左子树遍历完全的父节点 
		printf("%d ",p->value);
		//如果p有右子树,则对右子树进行同样的操作 
		if(p->right!=NULL){
			flag=0;
			p=p->right;
			//TODO
		}
		else{
			//没有的话说明该节左子树遍历完全 
			flag=1;
			//如果栈为空,说明完成遍历 
			if(stack.lenth==0){
				p=NULL;
				//TODO
			}
			//否则将子树的父结点弹出,以遍历过的形态进行循环 
			else
				p=Pop(&stack);
		}
	}
}

同理前序遍历:

//前序遍历 
void TraversalTree(TreeNode* tree){
	Stack stack;
	stack.top=NULL;
	TreeNode*p=tree;
	int flag=0;
	while(p){ 
		if(!flag){
			while(p->left){
				Push(&stack,p);
				printf("%d ",p->value);
				p=p->left;
				//TODO
			}
			printf("%d ",p->value);
		}
		if(p->right!=NULL){
			flag=0;
			p=p->right;
			//TODO
		}
		else{
			flag=1;
			if(stack.lenth==0){
				p=NULL;
				//TODO
			}
			else
				p=Pop(&stack);
		}
	}
}

后序

//后序遍历  
void PostOrder(TreeNode* tree){
	Stack stack;
	stack.top=NULL;
	stack.lenth=0;
	TreeNode*p=tree;
	//左右树均被遍历 
	int flag=0;
	int flag2=0;
	while(p){ 
		if(!flag){
			if(!p->left&&p){
				Push(&stack,p);
				//TODO
			}
			if(p->left){
				while(p->left){
					Push(&stack,p);
					p=p->left;
				}
				if(p->right!=NULL){
					Push(&stack,p);
					p=p->right;
					flag=0;
					continue;
					//TODO
				}
				printf("%d ",p->value);
				p=(stack.top)->node;
				flag=1;
				continue;
				//TODO
			}	
		} 
		if(p->right!=NULL&&!flag2){
			flag=0;
			p=p->right;
			//TODO
		}
		else{
			flag=1;
			flag2=1;
			if(stack.lenth==0){
				p=NULL;
				//TODO
			}
			else{
				p=Pop(&stack);
				int c=p->value;
				printf("%d ",c);
				if(stack.lenth==1){
					if(c==(stack.top)->node->left->value){
						p=(stack.top)->node;
						flag2=0;//TODO
					}
					else{
						p=(stack.top)->node;
						printf("%d ",p->value);
						return;
					}
					//TODO
				}
			}
		}
	}
}

完整代码如下:

#include
#include 

typedef struct TreeNode{
	TreeNode*left;
	TreeNode*right;
	int value;
}TreeNode;

typedef struct Node{
	Node*bottom;
	TreeNode* node;
}Node;

typedef struct Stack{
	Node*top;
	int lenth;
}Stack;

TreeNode* CreateTreeNode(){
	TreeNode*p=(TreeNode*)malloc(sizeof(TreeNode));
	p->value=0;
	p->left=NULL;
	p->right=NULL;
	return p;
}

Node* CreateNode(){
	Node*p=(Node*)malloc(sizeof(Node));
	p->node=NULL;
	p->bottom=NULL;
	return p;
}

void Push(Stack *stack,TreeNode* tree){
	Node *p=CreateNode();
	p->node=tree;
	p->bottom=(*stack).top;
	(*stack).lenth++;
	(*stack).top=p;
}

TreeNode* Pop(Stack* stack){
	Node* p=(*stack).top;
	TreeNode* number=(*stack).top->node;
	(*stack).top=(*stack).top->bottom;
	(*stack).lenth--;
	return number;
}
//中序遍历 
void TraversalTree(TreeNode* tree){
	Stack stack;
	stack.top=NULL;
	TreeNode*p=tree;
	int flag=0;
	while(p){
		while(p->left&&!flag){
			Push(&stack,p);
			p=p->left;
			//TODO
		}
		printf("%d ",p->value);
		if(p->right!=NULL){
			flag=0;
			p=p->right;
			//TODO
		}
		else{
			flag=1;
			if(stack.lenth==0){
				p=NULL;
				//TODO
			}
			else
				p=Pop(&stack);
		}
	}
}

void CreateTree(TreeNode** root){
	char c;
	c=getchar();
	if(c==' '){
		*root=NULL;
		//TODO
	}
	else{
		*root=(TreeNode*)malloc(sizeof(TreeNode));
		if(*root==NULL){
			exit(1); 
			//TODO
		}
		(*root)->value=c-48;
		CreateTree(&((*root)->left));
		CreateTree(&((*root)->right));
	}
}

int main(){
	TreeNode* tree=(TreeNode*)malloc(sizeof(TreeNode));
	CreateTree(&tree);
	TraversalTree(tree);
	return 0; 
}

正确版本:

中序:

void InOrder(TreeNode* tree){
	Stack stack;
	stack.lenth=0;
	stack.top=NULL;
	TreeNode*p=tree;
	while(p||stack.lenth){
		while(p){
			Push(&stack,p);
			p=p->left;
			//TODO
		}
		if(stack.lenth){
			p=Pop(&stack);
			printf("%d ",p->value);
			p=p->right;
			//TODO
		}
	}
}

前序:(改为第一次遇到就print)

void PreOrder(TreeNode* tree){
	Stack stack;
	stack.lenth=0;
	stack.top=NULL;
	TreeNode*p=tree;
	while(p||stack.lenth){
		while(p){
			Push(&stack,p);
			printf("%d ",p->value);
			p=p->left;
			//TODO
		}
		if(stack.lenth){
			p=Pop(&stack);
			p=p->right;
			//TODO
		}
	}
}

前序和中序都是把根和左放在遍历完右树前输出。

而后序则是需要遍历完左右子树后才遍历根。所以为了防止多次遍历和胡乱pop,需要加一个tag来看是第几次经过根结点。如果是第二次经过结点,需要把它给push回去,并往它的右边遍历,同时将tag++;是第三次的话才能print出来,并且把p设置为空

这里设置为空思路很巧妙。


void PostOrder(TreeNode* tree){
	Stack stack;
	stack.lenth=0;
	stack.top=NULL;
	TreeNode*p=tree;
	while(p||stack.lenth){
		while(p){
			p->tag=1;
			Push(&stack,p);
			p=p->left;
			//TODO
		}
		if(stack.lenth){
			p=Pop(&stack);
			if(p->tag==1){
				p->tag++;
				Push(&stack,p);
				p=p->right; 
			}
			else if(p->tag==2){
				printf("%d ",p->value);
				p=NULL;
				//TODO
			}
		}
	}
}

如果删去p=NULL,而改成:

void PostOrder(TreeNode* tree){
	Stack stack;
	stack.lenth=0;
	stack.top=NULL;
	TreeNode*p=tree;
	while(1){
		while(p&&!p->tag){
			p->tag=1;
			Push(&stack,p);
			p=p->left;
			//TODO
		}
		if(stack.lenth){
			p=Pop(&stack);
			if(p->tag==1){
				p->tag++;
				Push(&stack,p);
				p=p->right; 
			}
			else if(p->tag==2){
				printf("%d ",p->value);
				if(!stack.lenth){
					break;
					//TODO
				}
				//TODO
			}
		}
	}
}

改变大while和小while循环条件,最后加了个终止条件。这也是可以的。

这说明了,设置为空的目的其实跟这个大抵是一样的,都是表明,这个根节点已经左右外加自己都完了,不用再来一遍了。原代码跟改后代码都使用了手段让其跳过左树遍历再pop一个出来。原来的代码使用p=NULL就可以安全退出循环,这个就达咩了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/690800.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号