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

二叉树的遍历一般由递归实现,但如果数据量过大的话,递归有可能过深,效率不如非递归程序。利用栈的功能可实现二叉树的非递归遍历。

前序遍历:

方法1将根和左子树全部入栈,入栈前遍历该结点。然后逐一出栈判别出栈结点是否有右子树,没有右子树直接遍历,有右子树的将右子树看做整树,将树根和左子树全部入栈,入栈前遍历。

方法2将需要先遍历的结点先出栈,根结点入栈后先出栈遍历,将出栈元素的右子树和左子树分别入栈再出栈遍历。

中序遍历:将根和左子树全部入栈,然后逐一出栈,出栈过程遍历。同时判别是否有右子树,有右子树的按照上述方法入栈,再出栈遍历。

后序遍历:后续遍历较为麻烦。

第一种方法思想是在第三次经过根节点时遍历(第一次入栈,第二次由左子树向上遍历,第三次由右子树向上遍历),也就是左右子树均已遍历过再遍历根节点:
第一步:将树的根结点和左子树全部入栈;
第二步:逐一出栈过程中判别出栈结点是否有右子树;
第三步:1、出栈结点有右子树时分为两种情况:
                   (1)上一个遍历结点是左子树,说明右子树还没有遍历,将右子树按照第一步入栈。 
                   (2)上一个遍历结点是右子树,说明右子树已经遍历过,直接遍历本结点。
              2、出栈结点没有右子树,直接遍历。

第二种方法思想是将二叉树的二维结构利用两个堆栈转换为后序线性结构

第一步:1、创建A/B两个栈,将根节点入A栈
第二步:2、当A栈不空,定义变量ptemp=出A栈,temp入B栈
第三步:3、将temp的左子树和右子树分别入A栈,循环2/3步骤直至A栈空(左子树在A栈先入后出,在B栈后入先出) 
第四步:4、将B栈元素元素逐一出栈遍历

话不多说,上代码:

头文件:

#ifndef BINARYTREE_H
#define BINARYTREE_H
#include 
#include 
#include 
typedef struct node Node;//重定义类型名称 
typedef Node Bintree;//重定义树类型名称 
typedef int Elementtype;//重定义数据类型名称 
struct node{//声明结构体原型 
	Elementtype value;
	Node *left;
	Node *right;
};

typedef struct stnode stNode;//重定义栈结点名称
typedef Node* Element;//重定义栈数据名称
struct stnode{//声明栈结点结构体
	Element value;
	stNode *next;
};
typedef struct _stack{//声明栈结构体并重定义名称
	stNode *top;
	stNode *bottom;
}Stack;
#endif
Bintree *creat();//创建树 
Node *initNode();//初始化结点 
void clean(Bintree **pTr);//清空树,需要改变指针内容所有传入二级指针 
bool isempty(Bintree *pTr);//判树空 

void PreordertraversalStack(Bintree *);//前序遍历1(非递归) 
void PreordertraversalStack1(Bintree *pTr);//前序遍历2(非递归)

void InordertraversalStack(Bintree *);//中序遍历(非递归) 
 
void PostordertraversalStack(Bintree *pTr);//后序遍历(非递归)
void PostordertraversalStack1(Bintree *pTr);//后续遍历2(非递归)

/*栈操作函数*/
Stack *creatStack();
int isemptyStack(Stack *);
void pushStack(Stack *,Element value);
Element popStack(Stack*);
void cleanStack(Stack**);
Element gettopStack(Stack *pStack);

函数实现:

#include "binarytree.h"
Bintree *creat(){
	Bintree *pTr=NULL;
	Node *p=initNode();
	pTr=p;
	p->left=initNode();
	p->right=initNode();
	Node *q=p->right;
	p=p->left;
	p->left=initNode();
	p->right=initNode();
	q->left=initNode();
	q->right=initNode();
	return pTr;
}
Node *initNode(){
	Node *pNode=(Node*)malloc(sizeof(Node));
	scanf("%d",&pNode->value);
	pNode->left=pNode->right=NULL;
}
bool isempty(Bintree *pTr){
	return pTr==NULL;
}
void clean(Bintree **pTr){
	if(*pTr){
		clean(&(*pTr)->left);
		clean(&(*pTr)->right);
		free(*pTr);
		*pTr=NULL;
	}
}

void PreordertraversalStack(Bintree *pTr){//非递归前序遍历 
	Bintree *ptemp=pTr;
	Stack *pStack=creatStack();
	int flag=0;
	while(ptemp||!isemptyStack(pStack)){
		while(ptemp){
			printf("%-2d",ptemp->value);//根结点和左子树入栈前遍历 
			pushStack(pStack,ptemp);
			ptemp=ptemp->left;
		}
		if(!isemptyStack(pStack)){
			ptemp=popStack(pStack);
			ptemp=ptemp->right;
		}
	}
    cleanStack(&pStack); 
}
void PreordertraversalStack1(Bintree *pTr){//非递归前序遍历2将需要先遍历的结点先出栈 
	Element ptemp=pTr;
	Stack *pStack=creatStack();
	pushStack(pStack,ptemp);
	while(!isemptyStack(pStack)){
		ptemp=popStack(pStack);//根结点先出栈遍历 
		printf("%-2d",ptemp->value);
		pushStack(pStack,ptemp->right);//右结点先入后出 
		pushStack(pStack,ptemp->left);//左结点后入先出 
	}
	cleanStack(&pStack);
}
void InordertraversalStack(Bintree *pTr){//非递归中序遍历 
	Bintree *ptemp=pTr;
	Stack *pStack=creatStack();
	int flag=0;
	while(ptemp||!isemptyStack(pStack)){
		while(ptemp){
			pushStack(pStack,ptemp);
			ptemp=ptemp->left;
		}
		if(!isemptyStack(pStack)){
			ptemp=popStack(pStack);
			printf("%-2d",ptemp->value);//左子树和根结点出栈时遍历 
			ptemp=ptemp->right;
		}
	}
    cleanStack(&pStack); 
}

/*非递归后续遍历方法1基本思想在第三次经过根节点时遍历(第一次入栈,第二次由左子树向上遍历,第三次由右子树向上遍历),也就是左右子树均已遍历过再遍历根节点:
第一步:将树的根结点和左子树全部入栈;
第二步:逐一出栈过程中判别出栈结点是否有右子树;
第三步:出栈结点有右子树时分为两种情况:
	1、上一个结点是左子树,说明右子树还没有遍历,将右子树按照第一步入栈。 
	2、上一个结点是右子树,说明右子树已经遍历过,直接遍历。
 		出栈结点没有右子树,直接遍历。 
*/
void PostordertraversalStack(Bintree *pTr){//非递归后序遍历1
	Bintree *ptemp=pTr;
	Stack *pStack=creatStack();
	Element p=NULL;//用于记录每次遇到根结点时的上一个结点 
	while(ptemp||!isemptyStack(pStack)){
		while(ptemp){//根和左子树入栈 
			pushStack(pStack,ptemp);
			ptemp=ptemp->left;
		}
		if(!isemptyStack(pStack)){//栈不空,逐一出栈 
			ptemp=popStack(pStack);
			if(!ptemp->right){//出栈结点右子树为空直接遍历 
				printf("%-2d",ptemp->value);
				p=ptemp;//记录此次遍历的结点 
				ptemp=NULL;
			}else if(ptemp->right==p){//出栈结点有右子树且右子树等于上次遍历结点 
				printf("%-2d",ptemp->value);
				p=ptemp;
				ptemp=NULL;
			}else{//出栈结点有右子树且不等于上次遍历的结点 
				pushStack(pStack,ptemp);//重新入栈 
				ptemp=ptemp->right;//将该结点的右子树返回到循环开始入栈 
			}
		}
	}
	cleanStack(&pStack); 
}
/*非递归后续遍历方法2主要思想是将二叉树的二维结构利用两个堆栈转换为后序线性结构
具体步骤:	1、创建A/B两个栈,将根节点入A栈
			2、当A栈不空,定义变量ptemp=出A栈,temp入B栈
			3、将temp的左子树和右子树分别入A栈,循环2/3步骤直至A栈空
			(左子树在A栈先入后出,在B栈后入先出) 
			4、将B栈元素元素逐一出栈遍历*/
void PostordertraversalStack1(Bintree *pTr){
	Stack *pStackA=creatStack();
	Stack *pStackB=creatStack();
	pushStack(pStackA,pTr);
	while(!isemptyStack(pStackA)){
		Element ptemp=popStack(pStackA);
		pushStack(pStackB,ptemp);
		pushStack(pStackA,ptemp->left);
		pushStack(pStackA,ptemp->right);
	}
	while(!isemptyStack(pStackB)){
		Element ptemp=popStack(pStackB);
		printf("%-2d",ptemp->value);
	}
}


/*栈操作函数*/
Stack *creatStack(){
	Stack *pStack=(Stack*)malloc(sizeof(Stack));
	pStack->bottom=pStack->top=NULL;
	return pStack; 
}
int isemptyStack(Stack *pStack){
	return pStack->bottom==NULL;
}
void pushStack(Stack *pStack,Element value){
    if(value){
        stNode *pNode=(stNode*)malloc(sizeof(stNode));
	    pNode->value=value;
	    pNode->next=NULL;
	    if(isemptyStack(pStack)){
		    pStack->bottom=pStack->top=pNode;
	    }else{
		    pNode->next=pStack->top;
		    pStack->top=pNode;
	    }
    }
}
Element popStack(Stack *pStack){
	Element res=NULL;
	if(!isemptyStack(pStack)){
		res=pStack->top->value;
		stNode *ptemp=pStack->top;
		if(pStack->bottom==pStack->top){
			pStack->bottom=pStack->top=NULL;
		}else{
			pStack->top=pStack->top->next;
		}
		free(ptemp);ptemp=NULL;
	}
	return res;
}
void cleanStack(Stack **pStack){
	while(!isemptyStack(*pStack)){
		popStack(*pStack);
	}
	free(*pStack);
	*pStack=NULL;
}
Element gettopStack(Stack *pStack){
	if(!isemptyStack(pStack)){
		return pStack->top->value;
	}else{
		return NULL;
	}
}

main函数:

#include 
#include 
#include "binarytree.h"
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char *argv[]) {
	Bintree *pTr=creat();
//	Preordertraversal(pTr);printf("\n");
	PreordertraversalStack(pTr);printf("\n\n");
//	Inordertraversal(pTr);printf("\n");
	InordertraversalStack(pTr);printf("\n\n");
//	Postordertraversal(pTr); printf("\n");
	PostordertraversalStack(pTr);printf("\n\n");
	clean(&pTr);
	if(isempty(pTr))printf("树已清空\n");
	return 0;
}

你可能感兴趣的:(数据结构,算法,c语言)