二叉树遍历算法的六种c语言实现 递归与非递归

二叉树遍历分为三种:

  1. 先序遍历:先访问根结点,其次左节点,最后右节点

  2. 中序遍历:先访问左结点,其次跟节点,最后右节点

  3. 后序遍历:先访问左结点,其次右节点,最后根节点

三种遍历的递归算法实现形式类似,仅仅是访问顺序不同,非常简洁。如下:

//节点定义
typedef struct node {
	int val;
	struct node *left;
	struct node *right;
}*pnode, node;
//后序遍历递归算法
void postOrderRecursive(pnode root)
{
	if (root)
	{
		//访问左子树
		postOrderRecursive (root->left);
		
		//访问右子树
		postOrderRecursive (root->right);

		//访问根结点
		printf("%d ", root->val);		
	}
	return ;
}


//中序遍历递归算法
void inOrderRecursive(pnode root)
{
	if (root)
	{
		//访问左子树
		inOrderRecursive (root->left);

		//访问根结点
		printf("%d ", root->val);

		//访问右子树
		inOrderRecursive (root->right);		
	}
	return ;
}


//先序遍历递归算法
void preOrderRecursive(pnode root)
{
	if (root)
	{
		printf("%d ", root->val);

		//访问左子树
		preOrderRecursive (root->left);
		//访问右子树
		preOrderRecursive (root->right);		
	}
	return ;
}

递归算法属于必知必会的基础,面试如果问到此类问题,一般都会让给出非递归实现。话说,递归算法一般都可以转换成循环和栈的非递归实现。

对于先序遍历来说,先将根结点入栈,进入循环,取栈顶,先将节点右孩子和左孩子依次进栈,访问该节点,按照此节奏,循环处理,直到栈空。即,每次取出栈顶元素,将其右左孩子节点依次进栈,访问即可。

//先序遍历非递归
void preOrderNonRec(pnode root)
{
	pnode stack[1000], curr, prev;
	int top, end;

	if (root == NULL)
		return ;

	top = end = 0;

	//根结点入栈
	stack[top++] = root;

	while (top > 0)
	{
		//取栈顶
		curr = stack[--top];

		//右子树入栈
		if (curr->right)
			stack[top++] = curr->right;

		//左子树入栈	
		if (curr->left)
			stack[top++] = curr->left;

		//访问节点	
		printf ("%d ", curr->val);	
	}
	printf("\n");
	return ;
}

对于中序遍历的非递归算法,依然是栈加循环的方式,处理上和上一步略微有点区别。

先将根结点入栈,当前节点指向左孩子,只要当前节点的左孩子存在,则继续循环处理,即父节点进栈,节点指向左孩子,直到节点为空,这时,从栈中取出栈顶,对于栈中取出的元素,总是先访问,然后指向右孩子,继续第一步处理,即父节点进栈,节点指向左孩子。这里需要注意的有两点:1. 从栈中取出来的元素访问后无需再进栈。2. 对于栈中取出的元素,总是先访问,然后指向右孩子。

//中序遍历,非递归
void inorderNonRec(pnode root)
{
	pnode stack[1000], curr;
	int top, end;

	if (root == NULL)
		return ;

	top = end = 0;
	//根结点进栈
	stack[top++] = root;

	//当前节点指向左孩子
	curr = root->left;

	while (curr || top > 0)
	{
		//节点存在,则父节点进栈,指向左孩子
		if (curr)
		{
			if (curr->left)
			{
				stack[top++] = curr;
				curr = curr->left;
				continue;
			}
		}
		else
		{
			curr = stack[--top];
		}

		//取栈顶,访问后,指向右孩子
		printf("%d ", curr->val);
		curr = curr->right;
	}
	printf("\n");

	return ;
}

后序遍历的非递归实现依然是循环加栈处理。和中序遍历一样,不过处理上略微有点不同。相当之处仍然是父节点先进栈,指向左孩子。不同的地方在于,从栈中取出元素时,此时不访问,而是如果存在右孩子,则父节点继续进栈,节点指向其右孩子。如果右孩子不存在,则访问该节点,同时记录当前访问的节点。继续出栈,同上步,如果存在右孩子,父节点继续进栈,节点指向其右孩子,此时,为防止死循环,需要将右孩子和之前访问的节点比较,如果相同,则无需进栈,此时直接访问即可。不理解的同学请画一颗二叉树辅助思考。

//后序遍历,非递归
void postOrderNonRec(pnode root)
{
	pnode stack[1000], curr, prev;
	int top, end;

	if (root == NULL)
		return ;

	top = end = 0;

	//根结点入栈
	stack[top++] = root;

	//指向左孩子
	curr = root->left;
	
	while (curr || top > 0)
	{
		//只要存在孩子节点,则父节点进栈,指向其孩子节点。
		if (curr)
		{
			if (curr->left || curr->right)
			{
				stack[top++] = curr;
				if (curr->left)
					curr = curr->left;
				else
					curr = curr->right; 	
				continue;
			}
		}
		else
		{
			//取栈顶,如果存在右孩子且和上一个访问节点不一样,则父节点
			//继续进栈,指向右孩子。
			curr = stack[--top];

			if (curr->right && curr->right != prev)
			{
				stack[top++] = curr;				
				curr = curr->right;
				continue;
			}
		}

		//访问节点同时保存访问的位置。
		printf("%d ", curr->val);
		prev = curr;
		curr = NULL;
	}
	printf("\n");
	return ;
}

=============================================================================================

Linux应用程序、内核、驱动、后台开发交流讨论群(745510310),感兴趣的同学可以加群讨论、交流、资料查找等,前进的道路上,你不是一个人奥^_^。

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
先定义二叉树的结构体: ```c typedef struct node { int data; struct node *left; struct node *right; } Node; ``` 递归实现二叉树前序遍历: ```c void preorder_traversal_recursive(Node *root) { if (root == NULL) { return; } printf("%d ", root->data); preorder_traversal_recursive(root->left); preorder_traversal_recursive(root->right); } ``` 递归实现二叉树中序遍历: ```c void inorder_traversal_recursive(Node *root) { if (root == NULL) { return; } inorder_traversal_recursive(root->left); printf("%d ", root->data); inorder_traversal_recursive(root->right); } ``` 递归实现二叉树后序遍历: ```c void postorder_traversal_recursive(Node *root) { if (root == NULL) { return; } postorder_traversal_recursive(root->left); postorder_traversal_recursive(root->right); printf("%d ", root->data); } ``` 非递归实现二叉树前序遍历: ```c void preorder_traversal_iterative(Node *root) { if (root == NULL) { return; } Node *stack[100]; int top = -1; stack[++top] = root; while (top >= 0) { Node *cur = stack[top--]; printf("%d ", cur->data); if (cur->right != NULL) { stack[++top] = cur->right; } if (cur->left != NULL) { stack[++top] = cur->left; } } } ``` 非递归实现二叉树中序遍历: ```c void inorder_traversal_iterative(Node *root) { if (root == NULL) { return; } Node *stack[100]; int top = -1; Node *cur = root; while (top >= 0 || cur != NULL) { while (cur != NULL) { stack[++top] = cur; cur = cur->left; } cur = stack[top--]; printf("%d ", cur->data); cur = cur->right; } } ``` 非递归实现二叉树后序遍历: ```c void postorder_traversal_iterative(Node *root) { if (root == NULL) { return; } Node *stack1[100], *stack2[100]; int top1 = -1, top2 = -1; stack1[++top1] = root; while (top1 >= 0) { Node *cur = stack1[top1--]; stack2[++top2] = cur; if (cur->left != NULL) { stack1[++top1] = cur->left; } if (cur->right != NULL) { stack1[++top1] = cur->right; } } while (top2 >= 0) { printf("%d ", stack2[top2--]->data); } } ``` 其中,非递归实现二叉树后序遍历需要用到两个,第一个用于辅助遍历,第二个用于存储遍历结果。具体实现过程如下: 1. 将根节点压入第一个中。 2. 在循环中,从第一个中弹出一个节点,将其压入第二个中。 3. 如果该节点有左子节点,则将其左子节点压入第一个中。 4. 如果该节点有右子节点,则将其右子节点压入第一个中。 5. 循环结束后,第二个中存储的就是后序遍历的结果,依次弹出即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值