详解二叉树的后序遍历

  • 后序遍历:首先遍历左子树,然后遍历右子树,最后访问根节点(左->右->根)
后序遍历的递归算法

思路:

  1. 遍历左子树
  2. 遍历右子树
  3. 访问根节点

代码如下:

//二叉树的后序遍历(递归)
void BinaryTreePostOrder(BTNode* root){
	if (root){
		BinaryTreePostOrder(root->lChild);
		BinaryTreePostOrder(root->rChild);
		putchar(root->data);
	}
}
后序遍历的非递归算法

思路:

借助栈来实现

  1. 传入二叉树根节点
  2. 从当前节点开始遍历左子树,将所有的节点入栈,且清空LT标记,直至左子树为空
  3. 访问栈顶,将其LT置位为1,访问他的右子树(如果右子树存在,返回至步骤2,如果右子树不存在,则继续执行)
  4. 取出栈顶并打印(出栈),通过检测他的父节点的LT是否也被置位为1(如果是,则一直打印并出栈,直到找到一个LT标记为清空状态的节点位置,返回至步骤2)

图解后续遍历的非递归算法
在这里插入图片描述

代码如下:

//二叉树的后序遍历(非递归)
void BinaryTreePostOrderNonR(BTNode* root)
{
	char tag[64];

	BTNode * cur = root;

	Stack st;
	StackInit(&st, 100);

	do{
		for (; cur; cur = cur->lChild) //类似中序,将当前节点及其左孩子们入栈
		{
			StackPush(&st, cur);
			tag[st.size - 1] = 0; //重置左子树访问标记(LT)
		}

		while (!StackIsEmpty(&st) && tag[st.size - 1])
			//前面的条件只在最后一次循环跳出的时候生效
			//后面的条件分两个情况:
			//1、当cur为空时,上面的for不进,此条件成立
			//2、当cur不为空,上面的for进,则此条件不成立
			//如果检测到当前的LT被置位(也就是情况1),那么在打印完当前节点后,再去直接检查上一个节点(父节点)是不是也要被打印了(LT置位,证明这是它的右子树,它也要被打印了),所以要用while循环打印
		{
			cur = StackTop(&st);
			putchar(cur->data);
			StackPop(&st);
		}

		if (!StackIsEmpty(&st)) //此条件只在最后一次循环跳出时生效
		{
			cur = StackTop(&st);
			//1、如果上面的while进了,那么证明左子树访问完毕了,给LT置位
			//2、如果上面的while没进,那么证明左子树不存在,给LT置位
			tag[st.size - 1] = 1;
			cur = cur->rChild;
			//左子树访问完毕后,访问右子树
		}
	} while (!StackIsEmpty(&st));
	//由于后序遍历中根节点是最后出栈的,所以在根节点出栈前,栈不可能为空
	//所以以栈是否为空来判定是否要跳出

	StackDestory(&st);
}

栈函数实现如下:

typedef char BTDataType;
// 二叉链的结构体
typedef struct BinaryTreeNode {
	BTDataType data;			// 当前节点值域
	struct BinTreeNode* lChild;	// 指向当前节点左孩子 
	struct BinTreeNode* rChild;// 指向当前节点右孩子 
}BTNode;

typedef BTNode* StDataType;
// 栈的结构体
typedef struct Stack {
	StDataType* array;	// 指向动态开辟的数组
	size_t size;		// 有效数据个数
	size_t capicity;	// 容量空间的大小
}Stack;

void StackInit(Stack* psl, size_t capicity)
{
	assert(psl);

	psl->capicity = capicity;
	psl->array = (StDataType *)malloc(capicity * sizeof(StDataType));
	assert(psl->array);

	psl->size = 0;
}

void StackDestory(Stack* psl)
{
	assert(psl);

	if (psl->array)
	{
		free(psl->array);
		psl->array = NULL;
		psl->size = 0;
		psl->capicity = 0;
	}
}

void CheckCapacity(Stack* psl)
{
	assert(psl);

	if (psl->size == psl->capicity)
	{
		psl->capicity *= 2;
		psl->array = (StDataType *)realloc(psl->array, psl->capicity * sizeof(StDataType));
	}
}

void StackPush(Stack* psl, StDataType x)
{
	assert(psl);

	CheckCapacity(psl);

	psl->array[psl->size] = x;
	psl->size++;
}

void StackPop(Stack* psl)
{
	assert(psl || psl->size);

	psl->size--;
}

StDataType StackTop(Stack* psl)
{
	if (StackIsEmpty(psl))
	{
		return (StDataType)0;
	}
	return psl->array[psl->size - 1];
}

int StackIsEmpty(Stack* psl)
{
	return psl->size == 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值