中序遍历
顺序为:左子树->跟节点->右子树
先遍历左子树,然后遍历跟节点,最后遍历右子树,以此轮推,直到遍历完所有节点。
6
-------------
4 8
-------- -------
2 5 7 9
--------
1 3
如上二叉树中序遍历结果为:1 2 3 4 5 6 7 8 9
一件很巧合的事情,遍历结果为一组已排序的序列,熟悉二叉搜索树的同学会发现,上边的二叉树其实是符合搜索二叉树。
二叉搜索树特征如下:
1.每个节点的值大于其左子树上所有节点的值(如果左子树不为空)
2.每个节点的值小于其右子树上所有节点的值(如果右子树不为空)
3.所有左子树和右子树自身也必须是二叉搜索树
检查如上二叉树结构,完全符合二叉树的所有特征,所以可以判定如上二叉树是一颗二叉搜索树。当把二叉树所有节点从左到右依次映射到一个序列中,所得到的序列即为一个按照升序排列的序列。
可以使用此方法来验证一颗二叉树,是否是一个二叉搜索树。
所以一切巧合皆有因果,那么如何来实现验证二叉搜索树的算法呢,没错就是本片文章所将的 二叉搜索树中序遍历
下面来说说二叉搜索树中序遍历逻辑:
1.二叉树能直接访问的只有跟节点,所有第一步拿到跟节点6是必须的,但是目的并不是访问它,而是需要获取跟节点6的最深的左子树,通过递归或者迭代,得到左子树节点4,节点4的左子树2,节点2的左子树节点1,节点1即为我们第一个要访问的节点
2.节点1没有子节点,所以节点2的左子树上所有节点(1)
已访问,则回溯访问节点1 的父节点2
3.接着访问节点2的右子树节点3
4.此时节点4的左子树上所有节点(1, 2, 3)
都已访问,则从节点2回溯访问其父节点4
5.接着访问节点4的右子树节点5
6.此时节点6的左子树上所有节点(1, 2, 3, 4, 5)
都已访问,则从节点4回溯访问其父节点6
7.节点6左子树已访问结束,开始访问节点6的右子树,拿到节点8但是不访问,而是要从节点8通过递归或者迭代,得到其最深的左子树节点7,访问节点7
8.节点7没有子节点,所以节点8的左子树上所有节点(7)
已访问,则从节点7回溯访问其父节点8
9.接着访问节点8的右子树节点9
10.至此二叉树的所有节点 (1, 2, 3, 4, 5, 6, 7, 8, 9)
都已访问,则遍历结束
先序遍历的两种实现:地柜实现、迭代试下
// 节点定义如下
public class TreeNode
{
public int val;
public TreeNode left;
public TreeNode right;
public TreeNode(int val = 0, TreeNode left = null, TreeNode right = null)
{
this.val = val;
this.left = left;
this.right = right;
}
}
递归实现如下
public IList<int> InorderTraversal(TreeNode root)
{
// 集合存储访问节点的值
IList<int> list = new List<int>();
// 调用递归函数
InorderTraversal(root, list);
return list;
}
public void InorderTraversal(TreeNode node, IList<int> list)
{
if (null == node)
{
return;
}
// 递归调用左子树
InorderTraversal(node.left, list);
// 将节点值存储到集合中
list.Add(node.val);
// 递归访问右子树
InorderTraversal(node.right, list);
}
迭代实现如下
//迭代实现
public IList<int> InorderTraversal2(TreeNode root)
{
// 集合存储访问节点的值
IList<int> list = new List<int>();
// 以栈结构(先进后出)来构建节点访问次序
Stack<TreeNode> stack = new Stack<TreeNode>();
// 先将跟节点入栈
stack.Push(root);
// 新建临时节点从 root 开始
TreeNode node = root;
while (stack.Count > 0)
{
// 迭代直到得到最深的左子树
while (null != node && (null != node.left))
{
stack.Push(node.left);
node = node.left;
}
// 节点出栈
node = stack.Pop();
if (null != node)
{
// 将节点的值存入集合中
list.Add(node.val);
// 如果有子树不为空,则将右子树入栈
if (null != node.right)
{
stack.Push(node.right);
}
// 令节点等于其右子树,此时右子树可以为空
node = node.right;
}
}
return list;
}
至此二叉树中序遍历的原理以及实现均已奉上