15-Data structure-traversal of binary tree, recursive and non-recursive

Introduction:
        This article is mainly code implementation, binary tree traversal, recursion and non-recursion (using stack). Mainly for easy understanding, detailed comments are directly added to the code, which is convenient for review and later dictation. Mainly understand its basic ideas and lay the foundation for its proficient application in the later stage.

The meaning of traversal is to perform various operations on the binary tree, patronize each node in place, and perform operations on the current node when reaching the root node.


Table of contents:

Table of contents

1. Preorder traversal.

1.1 Preorder traversal—recursion

1.2 Preorder traversal—non-recursive

2. In-order traversal

2.1 In-order traversal—recursion

2.2 In-order traversal—non-recursive

3. Post-order traversal

3.1 Postorder traversal—recursion

3.2 Post-order traversal—non-recursive

   5. General code

5.1 Code

5.2 Operation result chart


1. Preorder traversal.

1.1 Preorder traversal—recursion

        Introduction: The preorder is: first visit the root node, then visit its left child, and then visit the right child (left and right of the root).

//前序遍历,递归 
void PreOrder(BTNode *node)
{
	if(node==NULL)//当前结点为空时,返回上一层递归空间 
	{
		printf("#");
		return;
	}
	//结点非空时 
	visit(node);
	PreOrder(node->lchild);
	PreOrder(node->rchild);
}

1.2 Preorder traversal—non-recursive

        Introduction: Non-recursive, it is to use the stack (which is an array to store the tree node pointers, plus a top mark top) to store the pointers of the tree nodes. When the tree is not empty, it is pushed into the stack first, and then when the stack is not empty, the pop operation is performed. When popping the stack in pre-order traversal, after popping the stack, first access the node information, and then determine whether the node has a right child. If so, the pointer of the right child is stored on the stack. Then determine whether there is a left child, and if so, store the left child pointer on the stack.

//前序遍历,非递归 
void Stack_PreOrder(BTNode *node)
{
	if(node==NULL)//树为空,不处理
	return;

    //创建一个栈,存放树结点类型的地址 
	BTNode* Stack[10];
	int top=-1;
	//工作指针,随着p指针,记录树的当前结点位置 
	BTNode *p=NULL;
	//当树非空时,进行操作 
	if(node !=NULL)
	{
		//入栈 
		top++;
		Stack[top]=node;
		
		//随后进行出栈操作,只有栈非空时,才可出栈 
		while(top != -1)
		{
			//取出此时栈顶元素 
			p=Stack[top];
			top--;
			//然后进行访问当前结点的相关操作 
			visit(p);
			//访问完根,在看该根的右孩子,入栈 ,因为是栈,先进后出,而前序为根左右,根出来后,右入栈,之后左入栈,最后出栈是栈顶出 
			if(p->rchild!=NULL)
			{
				top++;
				Stack[top]=p->rchild;
			}
			//访问完右孩子,在看该根的左孩子,入栈 
			if(p->lchild!=NULL)
			{
				top++;
				Stack[top]=p->lchild;
			}			
		}		
	}
}

2. In-order traversal

2.1 In-order traversal—recursion

        Introduction: left root right. If you don't understand why, you can draw a picture. Every time you enter a new function, it is a new space.

//中序遍历-递归 
void InOrder(BTNode *node)
{
	
	if(node==NULL)
	{
		printf("#");
		return;
	}
	InOrder(node->lchild);
	visit(node);
	InOrder(node->rchild);
}

2.2 In-order traversal—non-recursive

        Introduction: In fact, whether it is stack or recursion, there are only two steps that need to be operated. The first step is to enter a series of operations into the new tree. After the operation is completed, enter the second step and enter the child tree in the other direction. The operation in this tree is still the first step of advancement, and then proceed to the second step.

        Idea: In-order traversal is a non-recursive operation, with a do-while loop in the outermost circle, which is executed first and then judged. If the stack is not empty, or the node is not empty, an in-order traversal operation is performed.

        The operation in do-while: first operate on the left subtree: keep traversing, pushing elements onto the stack, and then change the pointer address to the left child of the node. It will not stop until the left child is empty. At this point, the left operation of the left root in the right is completed. Then pop the element from the stack, perform the root operation on the left root and right middle, and access the root node. This is the first step. Then in the second part, enter the direction tree, that is, change the node pointer to the right child address,

//中序遍历-非递归
void StackInOrder(BTNode *node)
{
	if(node==NULL)//树为空,则不处理
	return;

    printf("中序遍历-非递归:");
	BTNode* p=node;
	BTNode* Stack[10];
	int top=-1;
	do
	{
		//当结点不为空时,入栈,并进入左孩子。 ——访问左孩子 
		while(p!=NULL)
		{
			top++;
			Stack[top]=p;
			p=p->lchild;
		}
		//一直遍历左,遍历到空,此时,出栈
		p=Stack[top];
		top--;
		
		visit(p);//访问根 
		p=p->rchild;//根访问完,随后,访问右孩子。随后,右孩子中,又是新的树,然后再进行左根右操作,形成循环,从上面再来一圈。 
		
	}while(top!=-1 || p!=NULL);//只要树不为空,或者栈内有元素,就一直进行操作。 
	
} 

3. Post-order traversal

3.1 Postorder traversal—recursion

        Introduction: left and right roots.

// 后序遍历-递归
void PostOrder(BTNode *node)
{
	if(node==NULL)
	{
		printf("#");
		return;
	}
	PostOrder(node->lchild);
	PostOrder(node->rchild);
	visit(node);
}

3.2 Post-order traversal—non-recursive

        Introduction: This is more troublesome, but we still use the stroke method. According to the stroke method, the root node is visited twice, the first time when it is pushed into the stack, and the second time when it is judged whether to pop out of the stack, it depends on which point it is from. If the layer returns to the root node, if it returns from the right child, it will perform a stack operation, first record the current node, and then pop the stack. Otherwise, pop the right subtree node from the stack,

        Here, it is slightly different from the in-order. The status of stacking and popping needs to be judged, so it is necessary to use the top pointer of the stack to compare at all times.

The root node is pushed into the stack first, and then when the stack is not empty , the traversal operation continues. The first step of advancement is the push operation on the stack (when the upper layer traverses, that is, when the left child of the top pointer is not the right child, the working pointer is updated to the left child, and then the left child is pushed onto the stack). The second step, the left child At the end, you need to pop the stack at this time, so take out the top element of the current stack. If the tree has no left child, or pre has the same address as the right child, pop the stack and record the pointer p before popping. Otherwise Then push the right child onto the stack.

void StackPostOrder(BTNode *node)
{
	printf("后序遍历-非递归:");
	if(node==NULL)
	return; 
	
	BTNode *p=node;//工作指针 
	BTNode *pre=NULL;//表示上层结点位置 
	//栈 
	BTNode *Stack[10];
	int top=-1;
	//先跟根节点入栈,为了方便第一次判断
	top++;
	Stack[top]=p;
	 
	do
	{
		//先判断上层结点是否遍历过,没有,则进行左子树都入栈,入到底
		if(pre!=Stack[top]->lchild && pre!=Stack[top]->rchild)
		{
			p=Stack[top]->lchild;//上次没有遍历过左右孩子,那么开始栈顶元素的左孩子入栈操作。
			while(p!=NULL)
			{
				top++;
				Stack[top]=p;
				p=p->lchild;	
			}	
		}
		//左孩子方向弄到底后,开始判断,是否需要出栈输出。
		p=Stack[top];//记录此时的栈顶元素
		if(p->rchild==NULL || pre==p->rchild)//如果右孩子为空,或者上一层和当前结点的右孩子相等,则输出 
		{
			pre=p;//记录当前结点地址 
			visit(p);//输出 
			top--;//输出了,栈内指针减少 
		}
		else
		{
			top++;
			Stack[top]=p->rchild;//右孩子入栈	
		} 
		
		
	}while(top!=-1); 
}

   5. General code

5.1 Code

#include <stdio.h>
#include <stdlib.h>
//创建树,孩子链表 
typedef struct BTNode
{
	int data;
	struct BTNode *rchild,*lchild;
	
}BTNode; 
//创建树结点,并初始化
BTNode* BuyNode(int x)
{
	BTNode* node=(BTNode*)malloc(sizeof(BTNode));
	node->data=x;
	node->lchild=NULL;
	node->rchild=NULL;
	
	return node;	
} 
//手动创建树
BTNode* CreatTree()
{
	BTNode* node1=BuyNode(1);
	BTNode* node2=BuyNode(2);
	BTNode* node3=BuyNode(3);
	BTNode* node4=BuyNode(4);
	BTNode* node5=BuyNode(5);
	
	node1->lchild=node2;
	node1->rchild=node3;
	node2->lchild=node4;
	node2->rchild=node5;
	return node1;		
} 
//访问当前结点时的操作 
void visit(BTNode *node)
{
	printf("%d",node->data);	
} 
//前序遍历,递归 
void PreOrder(BTNode *node)
{
	if(node==NULL)//当前结点为空时,返回上一层递归空间 
	{
		printf("#");
		return;
	}
	//结点非空时 
	visit(node);
	PreOrder(node->lchild);
	PreOrder(node->rchild);
}
//前序遍历,非递归 
void Stack_PreOrder(BTNode *node)
{
	if(node==NULL)
	return;
	
	printf("前序遍历-非递归:");
	//创建一个栈,存放树结点类型的地址 
	BTNode* Stack[10];
	int top=-1;
	//工作指针,随着p指针,记录树的当前结点位置 
	BTNode *p=NULL;
	//当树非空时,进行操作 
	if(node !=NULL)
	{
		//入栈 
		top++;
		Stack[top]=node;
		
		//随后进行出栈操作,只有栈非空时,才可出栈 
		while(top != -1)
		{
			//取出此时栈顶元素 
			p=Stack[top];
			top--;
			//然后进行访问当前结点的相关操作 
			visit(p);
			//访问完根,在看该根的右孩子,入栈 ,因为是栈,先进后出,而前序为根左右,根出来后,右入栈,之后左入栈,最后出栈是栈顶出 
			if(p->rchild!=NULL)
			{
				top++;
				Stack[top]=p->rchild;
			}
			//访问完右孩子,在看该根的左孩子,入栈 
			if(p->lchild!=NULL)
			{
				top++;
				Stack[top]=p->lchild;
			}			
		}		
	}
}
//中序遍历-递归 
void InOrder(BTNode *node)
{
	
	if(node==NULL)
	{
		printf("#");
		return;
	}
	InOrder(node->lchild);
	visit(node);
	InOrder(node->rchild);
}
//中序遍历-非递归
void StackInOrder(BTNode *node)
{
	if(node==NULL)
	return;
	
	printf("中序遍历-非递归:");
	BTNode* p=node;
	BTNode* Stack[10];
	int top=-1;
	do
	{
		//当结点不为空时,入栈,并进入左孩子。 ——访问左孩子 
		while(p!=NULL)
		{
			top++;
			Stack[top]=p;
			p=p->lchild;
		}
		//一直遍历左,遍历到空,此时,出栈
		p=Stack[top];
		top--;
		
		visit(p);//访问根 
		p=p->rchild;//根访问完,随后,访问右孩子。随后,右孩子中,又是新的树,然后再进行左根右操作,形成循环,从上面再来一圈。 
		
	}while(top!=-1 || p!=NULL);//只要树不为空,或者栈内有元素,就一直进行操作。 
	
}
// 后序遍历-递归
void PostOrder(BTNode *node)
{
	if(node==NULL)
	{
		printf("#");
		return;
	}
	PostOrder(node->lchild);
	PostOrder(node->rchild);
	visit(node);
}
//后序遍历-非递归
void StackPostOrder(BTNode *node)
{
	printf("后序遍历-非递归:");
	if(node==NULL)
	return; 
	
	BTNode *p=node;//工作指针 
	BTNode *pre=NULL;//表示上层结点位置 
	//栈 
	BTNode *Stack[10];
	int top=-1;
	//先跟根节点入栈,为了方便第一次判断
	top++;
	Stack[top]=p;
	 
	do
	{
		//先判断上层结点是否遍历过,没有,则进行左子树都入栈,入到底
		if(pre!=Stack[top]->lchild && pre!=Stack[top]->rchild)
		{
			p=Stack[top]->lchild;//上次没有遍历过左右孩子,那么开始栈顶元素的左孩子入栈操作。
			while(p!=NULL)
			{
				top++;
				Stack[top]=p;
				p=p->lchild;	
			}	
		}
		//左孩子方向弄到底后,开始判断,是否需要出栈输出。
		p=Stack[top];//记录此时的栈顶元素
		if(p->rchild==NULL || pre==p->rchild)//如果右孩子为空,或者上一层和当前结点的右孩子相等,则输出 
		{
			pre=p;//记录当前结点地址 
			visit(p);//输出 
			top--;//输出了,栈内指针减少 
		}
		else
		{
			top++;
			Stack[top]=p->rchild;//右孩子入栈	
		} 
		
		
	}while(top!=-1); 
}
int main()
{
	BTNode* root=CreatTree();
	//前序遍历打印
	printf("前序遍历-递归:"); 
	PreOrder(root);//递归 
	printf("\n"); 
	Stack_PreOrder(root);//非递归,栈来做 
	printf("\n"); 
	printf("中序遍历-递归:");
	InOrder(root); 
	printf("\n"); 
	StackInOrder(root); 
	printf("\n"); 
	printf("后续遍历-递归:");
	PostOrder(root);
	printf("\n"); 
	StackPostOrder(root);
	return 0;
 } 

5.2 Operation result chart

Guess you like

Origin blog.csdn.net/m0_59844149/article/details/132611661