资讯详情

数据结构学习——树形结构之非递归遍历二叉树

以上介绍了二叉树和递归遍历二叉树的内容。有兴趣的朋友可以去看看:递归遍历二叉树的树形结构


一. 非递归前序遍历

二.非递归中序遍历

三. 非递归后序遍历

四.数据结构专栏


一. 非递归前序遍历

前序遍历(DLR,lchild,data,rchild),它是一种二叉树遍历,又称先根遍历、先序遍历、前序周游。你可以记得做根。先访问根结点,然后遍历左子树,最后遍历右子树。 前序遍历先访问根结点,再遍历左子树,最后遍历右子树。遍历左右子树时,仍先访问 根点,然后遍历左子树,最后遍历右子树。 若 如果二叉树是空的,返回将结束,否则: (1)访问根结点。 (2)前序遍历左子树 。 (3)前序遍历右子树 。 需要注意的是,前序遍历仍然用于遍历左右子树。

如图所示:

除了使用递归,二叉树的遍历也可以通过非递归来实现。事实上,大多数可以通过递归解决的问题都可以通过另一种数据结构来解决。这种数据结构是堆栈。因为递归和堆栈具有可追溯性的特点。 如何借助栈来实现二叉树的非递归遍历呢?下面以二叉树的前序遍历为例,看一看具体过程: 1. 二叉树根节点首先遍历A,放入栈中。

2. 左儿童节点2,遍历根节点1,放入栈中。

3. 左儿童节点4,遍历节点2,放入栈中。

4. 节点4既没有左孩子也没有右孩子。我们需要回到最后一个节点2。但现在不是递归操作。如何追溯?别担心,栈已经存储了刚才的路径。让旧栈顶元素4离开栈,您可以再次访问节点2,获得节点2的右儿童节点5。此时,节点2没有使用价值(已访问左右儿童)。节点2离开栈,节点5进入栈。

5. 节点5既没有左孩子也没有右孩子。我们需要再次追溯到节点1。所以让节点5离开栈。 右儿童根节点1为节点3,节点1出栈,节点3入栈。

6. 节点3的右孩子是节点6,节点3出栈,节点6进栈。

7. 节点6既没有左孩子也没有右孩子,所以节点6离开了栈。这时,栈是空的,遍历结束了。

代码如下:

////前序遍历的非递归实现  import java.util.Stack;  public class Test {  public static void main(String[] args) {   TreeNode[] node = new TreeNode[10];   for (int i = 0; i < 10; i  ) {    node[i] = new TreeNode(i);   }   for (int i = 0; i < 10; i  ) {    if (i * 2   1 < 10)     node[i].left = node[i * 2   1];    if (i * 2   2 < 10)     node[i].right = node[i * 2   2];   }   // 非递归实现   preOrderRe(node[0]);  }   public static void preOrderRe(TreeNode biTree) {   Stack<TreeNode> stack = new Stack<TreeNode>();   //循环体biTree设置为指向左或右节点,因此可能为空。但只要栈不空,就会循环   while (biTree !但只要栈不空,就会循环   while (biTree != null || !stack.isEmpty()) {    ///一直到最左边的左节点结束    while (biTree != null) {     System.out.print(biTree.value " ");     stack.push(biTree);     biTree = biTree.left;    }    //只要栈不是空的,就可以从栈上的左节点回到当前的根节点,然后是右子节点    if (!stack.isEmpty()) {     biTree = stack.pop();     biTree = biTree.right;    }   }  } }  //节点结构 class TreeNode {  int value;  TreeNode left;  TreeNode right;   TreeNode(int value) {   this.value = value;  } }

二.非递归中序遍历

中序遍历(LDR)是 一种二叉树遍历,又称 中根遍历,中序周游。二叉树中,先左后根再右。巧记:左根右。 先遍历左子树,再访问根结点,最后遍历右子树 若 如果二叉树是空的,返回将结束。 否则: (1)中序遍历左子树 (2)访问根结点 (3)中序遍历右子树

如图所示:

中序遍历结果:DBEAFC

现代码:

import java.util.Stack;  public class Test {  public static void main(String[] args) {   TreeNode[] node = new TreeNode[10];   for (int i = 0; i < 10; i  ) {    node[i] = new TreeNode(i);   }   for (int i = 0; i < 10; i  ) {    if (i * 2   1 < 10)     node[i].left = node[i * 2   1];    if (i * 2   2 < 10)     node[i].right = node[i * 2   2];   }         //中序遍历   midOrderRe(node[0]);  }   public static void midOrderRe(TreeNode biTree) {   Stack<TreeNode> stack = new Stack<TreeNode>();   while (biTree != null || != null || !stack.isEmpty()) {    while (biTree != null) {     stack.push(biTree);     biTree = biTree.left;    }    if (!stack.isEmpty()) {     biTree = stack.pop();     System.out.print(biTree.value " ");     biTree = biTree.right;    }   }  } }  //节点结构 class TreeNode{  int value;  TreeNode left;  TreeNode right;    TreeNode(int value){   this.value = value;  } }

三. 非递归后序遍历

&nbp;     后序遍历(LRD)是 二叉树遍历的一种,也叫做 后根遍历、后序周游,可记做左右根。后序遍历有 递归算法和非递归算法两种。在二叉树中,先左后右再根。巧记:左右根。 后序遍历首先遍历左子树,然后遍历右子树,最后访问根结点,在遍历左、右子树时,仍然先遍历左子树,然后遍历右子树,最后遍历根结点。即: 若 二叉树为空则结束返回,否则:  (1)后序遍历左子树 (2)后序遍历右子树 (3)访问根结点

如图所示

后序遍历结果:DEBFCA

    首先要搞清楚先序、中序、后序的非递归算法共同之处:用栈来保存先前走过的路径,以便可以在访问完子树后,可以利用栈中的信息,回退到当前节点的双亲节点,进行下一步操作。

    后序遍历的非递归算法是三种顺序中最复杂的,原因在于,后序遍历是先访问左、右子树,再访问根节点,而在非递归算法中,利用栈回退到时,并不知道是从左子树回退到根节点,还是从右子树回退到根节点,如果从左子树回退到根节点,此时就应该去访问右子树,而如果从右子树回退到根节点,此时就应该访问根节点。所以相比前序和后序,必须得在压栈时添加信息,以便在退栈时可以知道是从左子树返回,还是从右子树返回进而决定下一步的操作。

实现代码:

import java.util.Stack;

public class Test {
	public static void main(String[] args) {
		TreeNode[] node = new TreeNode[10];// 以数组形式生成一棵完全二叉树
		for (int i = 0; i < 10; i++) {
			node[i] = new TreeNode(i);
		}
		for (int i = 0; i < 10; i++) {
			if (i * 2 + 1 < 10)
				node[i].left = node[i * 2 + 1];
			if (i * 2 + 2 < 10)
				node[i].right = node[i * 2 + 2];
		}
		// 后序遍历非递归实现
		postOrderRe(node[0]);
	}

	public static void postOrderRe(TreeNode biTree) {
		int leftFlag = 1;// 在辅助栈里表示左节点
		int rightFlag = 2;// 在辅助栈里表示右节点
		Stack<TreeNode> stack = new Stack<TreeNode>();
		// 辅助栈,用来判断子节点返回父节点时处于左节点还是右节点。
		Stack<Integer> stackHelp = new Stack<Integer>();
		while (biTree != null || !stack.empty()) {
			while (biTree != null) {
				// 将节点压入栈1,并在栈2将节点标记为左节点
				stack.push(biTree);
				stackHelp.push(leftFlag);
				biTree = biTree.left;
			}
			while (!stack.empty() && stackHelp.peek() == rightFlag) {
				// 如果是从右子节点返回父节点,则任务完成,将两个栈的栈顶弹出
				stackHelp.pop();
				System.out.print(stack.pop().value + " ");
			}
			if (!stack.empty() && stackHelp.peek() == leftFlag) {
				// 如果是从左子节点返回父节点,则将标记改为右子节点
				stackHelp.pop();
				stackHelp.push(rightFlag);
				biTree = stack.peek().right;
			}
		}
	}
}

//节点结构
class TreeNode {
	int value;
	TreeNode left;
	TreeNode right;

	TreeNode(int value) {
		this.value = value;
	}
}

四. 数据结构专栏

https://blog.csdn.net/weixin_53919192/category_11908333.html?spm=1001.2014.3001.5482https://blog.csdn.net/weixin_53919192/category_11908333.html?spm=1001.2014.3001.5482

标签: 热过载继电器lrd06c热继电器lrd1321n10

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台