所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问,对二叉树的遍历就是将非线性结构的二叉树中的节点排列在一个线性序列上的过程。访问结点所做的操作依赖于具体的应用问题。
遍历是二叉树上最重要的运算之一,是二叉树上进行其它运算之基础。
如果采用顺序结构来保存二叉树,遍历二叉树非常容易,直接遍历底层数组即可。如果采用链表来保存,则有以下两类遍历方式:
- 深度优先遍历:先访问树中最深层次的节点
- 广度优先遍历:逐层访问每层节点,先访问根节点,然后访问第二层的节点。。。以此类推。因此广度优先遍历又称为按层遍历。
对于深度优先遍历算法,可以分为以下3种:
- DLR:前序遍历(PreorderTraversal亦称(先序遍历))
- LDR:中序遍历(InorderTraversal)
- LRD:后序遍历(PostorderTraversal)
深度遍历的先序遍历、中序遍历、后序遍历这三种遍历方式都是针对根节点(D)而言的。先处理根节点的就是先序遍历,其次处理根节点的就是中序遍历,最后处理根节点的就是后序遍历。
三种递归遍历算法的搜索路线相同(如下图虚线所示)。
具体线路为:
从根结点出发,逆时针沿着二叉树外缘移动,对每个结点均途径三次,最后回到根结点。
1、先序遍历
(1)访问根节点
(2)递归遍历左子树
(3)递归遍历右子树
Java实现代码:
//实现先序遍历 public List<TreeNode> preIterator(){ return preIterator(root); } private List<TreeNode> preIterator(TreeNode node) { List<TreeNode> list = new ArrayList<TreeNode>(); //处理根节点 list.add(node); //递归处理左子树 if(node.left != null){ list.addAll(preIterator(node.left)); } //递归处理右子树 if(node.right != null){ list.addAll(preIterator(node.right)); } return list; }
2、中序遍历
(1)递归遍历左子树
(2)访问根节点
(3)递归遍历右子树
Java实现代码:
public List<TreeNode> inIterator(){ return inIterator(root); } private List<TreeNode> inIterator(TreeNode node){ List<TreeNode> list = new ArrayList<TreeNode>(); //递归处理左子树 if(node.left != null){ list.addAll(inIterator(node.left)); } //处理根节点 list.add(node); //递归处理右子树 if(node.right != null){ list.addAll(inIterator(node.right)); } return list; }
3、后序遍历
(1)递归遍历左子树
(2)递归遍历右子树
(3)访问根节点
Java实现代码:
public List<TreeNode> postIterator(){ return postIterator(root); } private List<TreeNode> postIterator(TreeNode node){ List<TreeNode> list = new ArrayList<TreeNode>(); //递归处理左子树 if(node.left != null){ list.addAll(postIterator(node.left)); } //递归处理右子树 if(node.right != null){ list.addAll(postIterator(node.right)); } //处理根节点 list.add(node); return list; }
4、广度优先(按层)遍历
先遍历第一层(根节点),再遍历根节点的两个子节点(第二层)。。。逐层遍历二叉树的所有节点。
为了实现广度优先遍历,可以借助具有“FIFO”特征的队列实现,如下:
(1)建立一个队列(先进先出),把树的根节点压入队列;
(2)从队列中弹出一个节点(第一次弹出的就是根节点),然后把该节点的左、右节点压入队列,如果没有子节点,则说明已经到达叶子节点;
(3)循环重复执行第(2)步,直到队列为空。当队列为空时,说明所有的叶子节点都已经过了队列,也就完成了遍历。
Java实现代码:
public List<TreeNode> breadthFirst(){ Queue<TreeNode> queue = new ArrayDeque<TreeNode>(); List<TreeNode> list = new ArrayList<TreeNode>(); if(root != null){ //将根元素加入到“队列” queue.offer(root); } while(!queue.isEmpty()){ //将该队列的“队尾”的元素添加到List中 list.add(queue.peek()); TreeNode p = queue.poll(); //如果左子节点不为null,将它加入到“队列” if(p.left != null){ queue.offer(p.left); } if(p.right != null){ queue.offer(p.right); } } return list; }