二叉树的N中遍历方式和拓展应用
(一)创建二叉树,如下图所示,一个标准的二叉树是所有位于根节点的左侧的子节点都是比根节点小的,右侧则都是大于根节点的。


- public class BinaryNode
- {
- public int val;
- public BinaryNode left;
- public BinaryNode right;
- public BinaryNode(int val)
- {
- this.val = val;
- }
- }
- public class BinaryTree
- {
- public static BinaryNode createBinaryTree(int[] array)
- {
- BinaryNode root = new BinaryNode(array[0]);
- for (int i = 1; i < array.Length; i++)
- {
- insertBinaryTreeNode(root, array[i]);
- }
- return root;
- }
- private static void insertBinaryTreeNode(BinaryNode root, int val)
- {
- if(root.val >= val)
- {
- if (root.left == null)
- {
- root.left = new BinaryNode(val);
- return;
- }
- else
- {
- insertBinaryTreeNode(root.left, val);
- }
- }
- else
- {
- if (root.right == null)
- {
- root.right = new BinaryNode(val);
- return;
- }
- else
- insertBinaryTreeNode(root.right, val);
- }
- }
- }
createBinaryTree
(二)前序遍历:根节点-左节点-右节点(即输出为:8,3,2,1,5,4,6,20,15,13,16,29,21,30)


- public static List<int>preOrderTraverse(BinaryNode root)
- {
- List<int> nodes = new List<int>();
- subPreOrderTraverse(root, nodes);
- return nodes;
- }
- private static void subPreOrderTraverse(BinaryNode root, List<int> nodes)
- {
- if(root != null)
- {
- nodes.Add(root.val);
- subPreOrderTraverse(root.left, nodes);
- subPreOrderTraverse(root.right, nodes);
- }
- }
preOrderTraverse
不使用递归方法实现的前序遍历,即深度优先遍历(depth first search, DFS),使用栈实现。


- public static List<int>depthFirstSearch(BinaryNode root)
- {
- Stack<BinaryNode> stack = new Stack<BinaryNode>();
- stack.Push(root);
- List<int> nodes = new List<int>();
- while (stack.Count != 0)
- {
- BinaryNode node = stack.Pop();
- nodes.Add(node.val);
- if (node.right != null)
- stack.Push(node.right);
- if (node.left != null)
- stack.Push(node.left);
- }
- return nodes;
- }
depthFirstSearch
(三)中序遍历:左节点-根节点-右节点(即输出为:1,2,3,4,5,6,8,13,15,16,20,21,29,30)。可见中序遍历的特点是输出的是升序数组。


- public static List<int>inOrderTraverse(BinaryNode root)
- {
- List<int> nodes = new List<int>();
- subInOrderTraverse(root, nodes);
- return nodes;
- }
- private static void subInOrderTraverse(BinaryNode root, List<int> nodes)
- {
- if (root != null)
- {
- subInOrderTraverse(root.left, nodes);
- nodes.Add(root.val);
- subInOrderTraverse(root.right, nodes);
- }
- }
inOrderTraverse
中序遍历的非递归方法实现,同样使用栈。


- public static List<int>inOrderTraverseNonRecursion(BinaryNode root)
- {
- List<int> nodes = new List<int>();
- Stack<BinaryNode> stack = new Stack<BinaryNode>();
- BinaryNode node = root;
- while(node!=null || stack.Count != 0)
- {
- if (node != null)
- {
- stack.Push(node);
- node = node.left;
- }
- else
- {
- node = stack.Pop();
- nodes.Add(node.val);
- node = node.right;
- }
- }
- return nodes;
- }
inOrderTraverseNonRecursion
根据中序遍历能得到升序的数组的特点,可以用于解决验证二叉树的问题。leetcode98:给定一个二叉树,判断其是否是一个有效的二叉搜索树。解题思路便可以使用中序遍历得到数组,判断是否为升序数组。以及求节点的最小差问题等(530)。


- public static bool IsValidBST(BinaryNode root)
- {
- List<int> nodes = new List<int>();
- subIsValidBST(root, nodes);
- if (nodes.Count > 1)
- return false;
- else
- return true;
- }
- private static void subIsValidBST(BinaryNode root,List<int>nodes)
- {
- if (root != null)
- {
- subIsValidBST(root.left, nodes);
- nodes.Add(root.val);
- if (nodes.Count > 1)
- {
- if (nodes[1] <= nodes[0])
- return;
- else
- nodes.RemoveAt(0);
- }
- subIsValidBST(root.right, nodes);
- }
- }
isValidBST
类似地,如果按照右节点-根节点-左节点的顺序输出,则会得到降序序列。
此外,中序遍历中还有个莫里斯遍历。其特点是不使用栈或递归,空间复杂度是常数。我感觉这个方法的核心思想在于对于没有右子树的节点,通过把右子树指向根节点来代替使用栈。但是因为这样会造成循环,因此需要遍历两边,第二遍把右子树到根节点的指向取消。
需要使用两个指针tmp和curNode。


- def MorrisTraverse(self,root):
- nodes=[]
- curNode,tmp=root,None
- while curNode:
- if curNode.left:
- tmp=curNode.left
- while tmp.right and tmp.right!=curNode:
- tmp=tmp.right
- if tmp.right is None:
- tmp.right=curNode
- curNode=curNode.left
- else:
- nodes.append(curNode.val)
- tmp.right=None
- curNode=curNode.right
- else:
- nodes.append(curNode.val)
- curNode=curNode.right
- return nodes
MorrisTraverse
中序遍历得到的数组,可以看出来父节点和子节点之间的索引关系,索引为i的父节点的子节点的索引为:2*i+1和2*i+2。同理,索引为i的子节点的父节点的索引为(i-1)//2。
(四)后序遍历:左节点-右节点-根节点(即输出为:1,2,4,6,5,3,13,16,15,21,30,29,20,8)


- public static List<int>postOrderTraverse(BinaryNode root)
- {
- List<int> nodes = new List<int>();
- subPostOrderTraverse(root, nodes);
- return nodes;
- }
- private static void subPostOrderTraverse(BinaryNode root, List<int> nodes)
- {
- if(root != null)
- {
- subPostOrderTraverse(root.left, nodes);
- subPostOrderTraverse(root.right, nodes);
- nodes.Add(root.val);
- }
- }
postOrderTraverse


- def postorder(root):
- return postorder(root.left)+postorder(root.right)+[root.val] if root else []
Python-postOrder
(五)广度优先搜索(breath first search, BFS),也叫作层次遍历,输出为:8,3,20,2,5,15,29,1,4,6,13,16,21,30。使用队列实现。


- public static List<int>breathFirstSearch(BinaryNode root)
- {
- Queue<BinaryNode> queue = new Queue<BinaryNode>();
- queue.Enqueue(root);
- List<int> nodes = new List<int>();
- while(queue.Count != 0)
- {
- BinaryNode node = queue.Dequeue();
- nodes.Add(node.val);
- if (node.left != null)
- queue.Enqueue(node.left);
- if (node.right != null)
- queue.Enqueue(node.right);
- }
- return nodes;
- }
breathFirstSearch
根据BSF的特点,可以实现二叉树的锯齿形层次遍历。leetcode103:给定一个二叉树,返回其节点值的锯齿形层序遍历,即先从左往右,再从右往左进行下一层遍历。我用的方法如下:


- public static List<List<int>>zigzagLevelOrder(BinaryNode root)
- {
- List<List<int>> nodes = new List<List<int>>();
- Queue<BinaryNode> queue = new Queue<BinaryNode>();
- queue.Enqueue(root);
- int length = queue.Count;
- while (queue.Count != 0)
- {
- List<int> _nodes = new List<int>();
- while (length > 0)
- {
- BinaryNode node = queue.Dequeue();
- _nodes.Add(node.val);
- if (node.left != null)
- queue.Enqueue(node.left);
- if (node.right != null)
- queue.Enqueue(node.right);
- length--;
- }
- if (nodes.Count == 0)
- nodes.Add(_nodes);
- else if(nodes.Count ==1)
- {
- _nodes.Reverse();
- nodes.Add(_nodes);
- }
- else
- {
- if (nodes.Count % 2 == 0)
- nodes.Add(_nodes);
- else
- {
- _nodes.Reverse();
- nodes.Add(_nodes);
- }
- }
- length = queue.Count;
- }
- return nodes;
- }
zigzagLevelOrder
(六)二叉树的子树高度问题
leetcode平衡二叉树问题:给定一个二叉树,判断它是否是高度平衡的二叉树。高度平衡意味着一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1.此问题可以转化为二叉树的子树高度问题。


- public static bool isBalanced(BinaryNode node)
- {
- if (node == null)
- return true;
- if (Math.Abs(subTreeHeight(node.left) - subTreeHeight(node.right)) > 1)
- return false;
- return isBalanced(node.left) && isBalanced(node.right);
- }
- private static int subTreeHeight(BinaryNode node)
- {
- if (node == null)
- return 0;
- else
- {
- return Math.Max(subTreeHeight(node.left), subTreeHeight(node.right)) + 1;
- }
- }
binaryTreeHeight
类似地,还有求二叉树的最小深度问题,最小深度是从根节点到最近叶子节点的最短路径上的节点数量。例如root=[3,9,20,null,null,15,7],最小深度为2,即3-9两个节点。


- public static int MinDepth(BinaryNode node)
- {
- if (node == null)
- return 0;
- if (node.left == null && node.right != null)
- return MinDepth(node.right) + 1;
- if (node.right == null && node.left != null)
- return MinDepth(node.left) + 1;
- return Math.Min(MinDepth(node.left) , MinDepth(node.right)) + 1;
- }
minDpeth
二叉树的N中遍历方式和拓展应用的更多相关文章
- C++编程练习(8)----“二叉树的建立以及二叉树的三种遍历方式“(前序遍历、中序遍历、后续遍历)
树 利用顺序存储和链式存储的特点,可以实现树的存储结构的表示,具体表示法有很多种. 1)双亲表示法:在每个结点中,附设一个指示器指示其双亲结点在数组中的位置. 2)孩子表示法:把每个结点的孩子排列起来 ...
- 基于Java的二叉树的三种遍历方式的递归与非递归实现
二叉树的遍历方式包括前序遍历.中序遍历和后序遍历,其实现方式包括递归实现和非递归实现. 前序遍历:根节点 | 左子树 | 右子树 中序遍历:左子树 | 根节点 | 右子树 后序遍历:左子树 | 右子树 ...
- 二叉树及其三种遍历方式的实现(基于Java)
二叉树概念: 二叉树是每个节点的度均不超过2的有序树,因此二叉树中每个节点的孩子只能是0,1或者2个,并且每个孩子都有左右之分. 位于左边的孩子称为左孩子,位于右边的孩子成为右孩子:以左孩子为根节点的 ...
- POJ 2255 Tree Recovery && Ulm Local 1997 Tree Recovery (二叉树的前中后序遍历)
链接:poj.org/problem?id=2255 本文链接:http://www.cnblogs.com/Ash-ly/p/5463375.html 题意: 分别给你一个二叉树的前序遍历序列和中序 ...
- K:二叉树的非递归遍历
相关介绍: 二叉树的三种遍历方式(先序遍历,中序遍历,后序遍历)的非递归实现,虽然递归方式的实现较为简单且易于理解,但是由于递归方式的实现受其递归调用栈的深度的限制,当递归调用的深度超过限制的时候, ...
- SDUT-3344_数据结构实验之二叉树五:层序遍历
数据结构实验之二叉树五:层序遍历 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 已知一个按先序输入的字符序列,如abd ...
- 二叉树 Java 实现 前序遍历 中序遍历 后序遍历 层级遍历 获取叶节点 宽度 ,高度,队列实现二叉树遍历 求二叉树的最大距离
数据结构中一直对二叉树不是很了解,今天趁着这个时间整理一下 许多实际问题抽象出来的数据结构往往是二叉树的形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显 ...
- 二叉树(前序,中序,后序,层序)遍历递归与循环的python实现
二叉树的遍历是在面试使比较常见的项目了.对于二叉树的前中后层序遍历,每种遍历都可以递归和循环两种实现方法,且每种遍历的递归实现都比循环实现要简洁.下面做一个小结. 一.中序遍历 前中后序三种遍历方法对 ...
- Java实现二叉树及相关遍历方式
Java实现二叉树及相关遍历方式 在计算机科学中.二叉树是每一个节点最多有两个子树的树结构.通常子树被称作"左子树"(left subtree)和"右子树"(r ...
随机推荐
- 首页页面(html+css+js)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- Xml的一些基本概念(摘抄自w3school.com.cn)
一个Xml的文档示例: 点击查看代码 <?xml version="1.0" encoding="ISO-8859-1"?> <note> ...
- 斯坦福 CS183 & YC 创业课系列中文笔记
欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远. 在线阅读 ApacheCN 面试求职交流群 724187166 ApacheCN 学习资源 目录 Zero to One 从0到1 ...
- HowToDoInJava Spring 教程·翻译完成
原文:HowToDoInJava 协议:CC BY-NC-SA 4.0 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远. ApacheCN 学习资源 目录 Spring 5 Spr ...
- NoSuchMethodError错误
发生原因: 一个项目中包含有相同名字,但内容不同的包 解决办法:删除其中暂时不用的包 后记:如果不知道哪一个包是多余的,直接用IDE查找:找到该类,然后将该包进行反编译,再次导入该项目,再找到该类,出 ...
- Mac系统如何显示隐藏文件
Command+Shift+. 可以显示隐藏文件.文件夹,再按一次,恢复隐藏:finder下使用Command+Shift+G 可以前往任何文件夹,包括隐藏文件夹.
- linux中统计文件中一个字符串出现的次数
要统计一个字符串出现的次数,这里现提供自己常用两种方法: 1. 使用vim统计 用vim打开目标文件,在命令模式下,输入 :%s/objStr//gn 2. 使用grep: grep -o objSt ...
- uniapp自定义顶部搜索框兼容微信小程序
zhuanzai: uniapp自定义顶部搜索框兼容微信小程序 自定义组件 navbarvue (胶囊底部高度 - 状态栏的高度) + (胶囊顶部高度 - 状态栏内的高度) = 导航栏的高度 < ...
- 为什么后台给前台Date是时间戳,而前台给后台则直接是时间字符串?
一.因为时间的格式有很多种,不同的页面可能对不同的时间显示需求不同.比如: 05-8-8 上午9:17 2005-8-8 9:17:42 2005年8月8日 上午09时17分42秒 2005年8月8日 ...
- k8s之yaml文件详解
k8s之yaml文件详解 目录 k8s之yaml文件详解 1. k8s支持的文件格式 2. YAML语言格式 3. 查看api资源版本标签 4. 编写nginx-test.yaml资源配置清单 4.1 ...