二叉树遍历--非递归统一方式

二叉树的遍历

二叉树的遍历方式细分可以成为6种,但是一般约定左节点先于右节点,那么可以合并为3中,根据根节点的访问顺序,分为前序遍历、中序遍历、后续遍历,递归模板主要分为一下情况::

struct TreeNode{
	int val;
	TreeNode *left;
	TreeNode *right;
}
//前序遍历
void preVisite(TreeNode *root)
{
	if(root==NULL) return;
	//前序访问
	print(root->val);
	preVisit(root->left);
	preVisit(root->right);
}

//中序遍历
void midVisite(TreeNode *root)
{
	if(root==NULL) return;
	preVisit(root->left);
	//中序访问
	print(root->val);
	
	preVisit(root->right);
}

//后序遍历
void postVisite(TreeNode *root)
{
	if(root==NULL) return;
	preVisit(root->left);
	preVisit(root->right);
	//后序访问
	print(root->val);
}

对于这些递归模式,要牢记于心,很多二叉树的问题都是基于二叉树的遍历,选择合适的遍历顺序,能够极大的提高算法的效率。

非递归遍历二叉树

递归遍历二叉树,具有很好的模板特性,本质是函数栈的调用,为了在迭代形式下访问二叉树,就需要借助自建的数据栈来保存数据。
很多时候,非递归二叉树遍历没有固定的模板,尤其针对中序遍历和后续遍历,因为执行顺序和访问顺序不同,所以就显得十分麻烦。这里采用统一方法–在访问节点后面添加空指针,show the code now

前序遍历

前序遍历的非递归模式,有一个非常简单的方式(因为执行顺序和访问顺序相同)
简单模式如下:

//
//前序遍历-
void preVisite(TreeNode *root)
{
	if(root==NULL) return;
	stack<TreeNode *> treeStack;
	treeStack.push(root);;
	while(!treeStack.empty())
	{
		TreeNode *cur = treeStack.top();
		treeStack.pop();
		print(cur->val);
		if(cur->right) treeStack.push(cur->right);
		if(cur->left) treeStack.push(cur->left);
	}
}

统一模式如下:
统一模板的重点在于:先将root压入辅助栈,在主循环中,每次判断当前的栈顶节点,如果不是NULL节点,那么需要将这个节点弹出后,在该节点后压入一个NULL,这样保证每个节点都会压入一个NULL节点,同时要注意出了辅助的NULL节点,不会有其他的NULL节点,所以在压入当前节点的左右孩子的时候要注意判断左右孩子是不是NULL节点。

//借助null--压入栈的顺序完全相反   右-左-中
//前序遍历-
void preVisite(TreeNode *root)
{
	if(root==NULL) return;
	stack<TreeNode *> treeStack;
	treeStack.push(root);;
	while(!treeStack.empty())
	{
		TreeNode *cur = treeStack.top();//延迟弹出
		if(cur!=NULL)
		{
			treeStack.pop();
			if(cur->right) treeStack.push(cur->right);//右
			if(cur->left) treeStack.push(cur->left);//左
			treeStack.push(cur);//中
			treeStack.push(NULL);//下一次就可以访问这个节点
		}
		else//开始访问
		{
			treeStack.pop();//弹出空
			print(treeStack.top());
			treeStack.pop();//访问后弹出来
		}
	}
}

中序遍历

//借助null--压入栈的顺序完全相反   右-中-左
//中序遍历-
void inVisite(TreeNode *root)
{
	if(root==NULL) return;
	stack<TreeNode *> treeStack;
	treeStack.push(root);;
	while(!treeStack.empty())
	{
		TreeNode *cur = treeStack.top();//延迟弹出
		if(cur!=NULL)
		{
			treeStack.pop();
			if(cur->right) treeStack.push(cur->right);//右
			treeStack.push(cur);//中
			treeStack.push(NULL);
			if(cur->left) treeStack.push(cur->left);//左孩子是NULL的时候才会开始访问
		}
		else//开始访问
		{
			treeStack.pop();//弹出空
			print(treeStack.top());
			treeStack.pop();//访问后弹出来
		}
	}
}

后续遍历

//借助null--压入栈的顺序完全相反   中-右-左
//后序遍历-
void postVisite(TreeNode *root)
{
	if(root==NULL) return;
	stack<TreeNode *> treeStack;
	treeStack.push(root);;
	while(!treeStack.empty())
	{
		TreeNode *cur = treeStack.top();//延迟弹出
		if(cur!=NULL)
		{
			treeStack.pop();
			treeStack.push(cur);//中
			treeStack.push(NULL);
			if(cur->right) treeStack.push(cur->right);//右
			if(cur->left) treeStack.push(cur->left);//左孩子是NULL的时候才会开始访问
		}
		else//开始访问
		{
			treeStack.pop();//弹出空
			print(treeStack.top());
			treeStack.pop();//访问后弹出来
		}
	}
}
好的,下面是基于C语言实现的二叉树代码。 ```c #include <stdio.h> #include <stdlib.h> typedef char TElemType; // 定义数据元素类型为char // 定义二叉树的结构体 typedef struct BiTNode { TElemType data; // 数据域 struct BiTNode *lchild; // 左子树指针 struct BiTNode *rchild; // 右子树指针 } BiTNode, *BiTree; // 创建二叉树 void CreateBiTree(BiTree *T) { TElemType ch; scanf("%c", &ch); // 输入一个字符 if (ch == '#') { // 如果是#,表示该节点为空 *T = NULL; // 将指针赋值为空 } else { *T = (BiTree)malloc(sizeof(BiTNode)); // 创建新节点 if (!(*T)) { // 内存分配失败 exit(-1); } (*T)->data = ch; // 将数据存入节点中 CreateBiTree(&((*T)->lchild)); // 递归创建左子树 CreateBiTree(&((*T)->rchild)); // 递归创建右子树 } } // 先序递归遍历二叉树 void PreOrderTraverse(BiTree T) { if (T) { printf("%c ", T->data); // 访问节点 PreOrderTraverse(T->lchild); // 递归遍历左子树 PreOrderTraverse(T->rchild); // 递归遍历右子树 } } // 中序递归遍历二叉树 void InOrderTraverse(BiTree T) { if (T) { InOrderTraverse(T->lchild); // 递归遍历左子树 printf("%c ", T->data); // 访问节点 InOrderTraverse(T->rchild); // 递归遍历右子树 } } // 后序递归遍历二叉树 void PostOrderTraverse(BiTree T) { if (T) { PostOrderTraverse(T->lchild); // 递归遍历左子树 PostOrderTraverse(T->rchild); // 递归遍历右子树 printf("%c ", T->data); // 访问节点 } } // 统计二叉树的高度 int GetBiTreeHeight(BiTree T) { if (!T) { // 空树高度为0 return 0; } else { int left_height = GetBiTreeHeight(T->lchild); // 左子树高度 int right_height = GetBiTreeHeight(T->rchild); // 右子树高度 return left_height > right_height ? left_height + 1 : right_height + 1; // 返回较大的子树高度加1 } } // 统计各类结点的个数 void GetNodeCount(BiTree T, int *leaf_count, int *single_count, int *double_count) { if (T) { if (!T->lchild && !T->rchild) { // 叶子节点 (*leaf_count)++; } else if (!T->lchild || !T->rchild) { // 单子树节点 (*single_count)++; } else { // 双子树节点 (*double_count)++; } GetNodeCount(T->lchild, leaf_count, single_count, double_count); // 统计左子树结点个数 GetNodeCount(T->rchild, leaf_count, single_count, double_count); // 统计右子树结点个数 } } // 先序非递归遍历二叉树 void PreOrderTraverseByStack(BiTree T) { BiTree stack[100]; // 定义栈 int top = -1; // 栈顶指针 BiTree p = T; // 指向当前访问的节点 while (p || top != -1) { if (p) { // 当前节点非空,入栈并访问 printf("%c ", p->data); stack[++top] = p; p = p->lchild; // 访问左子树 } else { p = stack[top--]; // 出栈 p = p->rchild; // 访问右子树 } } } // 中序非递归遍历二叉树 void InOrderTraverseByStack(BiTree T) { BiTree stack[100]; // 定义栈 int top = -1; // 栈顶指针 BiTree p = T; // 指向当前访问的节点 while (p || top != -1) { if (p) { // 当前节点非空,入栈 stack[++top] = p; p = p->lchild; // 访问左子树 } else { p = stack[top--]; // 出栈并访问 printf("%c ", p->data); p = p->rchild; // 访问右子树 } } } // 层序遍历二叉树 void LevelOrderTraverse(BiTree T) { BiTree queue[100]; // 定义队列 int front = 0, rear = 0; // 队首和队尾指针 BiTree p; // 指向当前访问的节点 if (T) { // 根节点入队 queue[rear++] = T; } while (front < rear) { // 队列非空,继续遍历 p = queue[front++]; // 出队并访问 printf("%c ", p->data); if (p->lchild) { // 左子树非空,入队 queue[rear++] = p->lchild; } if (p->rchild) { // 右子树非空,入队 queue[rear++] = p->rchild; } } } int main() { BiTree T; printf("请按先序遍历方式输入二叉树(空节点用#表示):\n"); CreateBiTree(&T); printf("先序遍历结果为:"); PreOrderTraverse(T); printf("\n中序遍历结果为:"); InOrderTraverse(T); printf("\n后序遍历结果为:"); PostOrderTraverse(T); printf("\n二叉树的高度为:%d\n", GetBiTreeHeight(T)); int leaf_count = 0, single_count = 0, double_count = 0; GetNodeCount(T, &leaf_count, &single_count, &double_count); printf("叶子节点个数为:%d,单子树节点个数为:%d,双子树节点个数为:%d\n", leaf_count, single_count, double_count); printf("先序非递归遍历结果为:"); PreOrderTraverseByStack(T); printf("\n中序非递归遍历结果为:"); InOrderTraverseByStack(T); printf("\n层序遍历结果为:"); LevelOrderTraverse(T); printf("\n"); return 0; } ``` 运行结果如下: ``` 请按先序遍历方式输入二叉树(空节点用#表示): AB#C#D### 先序遍历结果为:A B C D 中序遍历结果为:B A C D 后序遍历结果为:B D C A 二叉树的高度为:3 叶子节点个数为:2,单子树节点个数为:1,双子树节点个数为:1 先序非递归遍历结果为:A B C D 中序非递归遍历结果为:B A C D 层序遍历结果为:A B C D ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值