遍历(Traverse)
- 就是按照某种次序访问树中的所有结点,且每个结点恰好访问一次
- 也就是说,按照被访问的次序,可以得到由树中所有结点排成的一个序列
- 树的遍历也可以看成是人为的将非线性结构线性化
- 这里的“访问”是广义的,可以是对结点作各种处理,例如输出结点信息、更新结点信息等
- 在我们的现实中,并不真正的“访问”这些结点,而是得到一个结点的线性序列,以线性表的形式输出
将整个二叉树看做三部分:根、左子树、右子树。如果规定先遍历左子树、在遍历右子树,那么根据根的遍历顺序就有三种遍历方式:
左子树 右子树 根
- 先序/根遍历DLR:根 左子树 右子树
- 中序/根遍历LDR:左子树 根 右子树
- 后序/根遍历LRD:左子树 右子树 根
注意:由于树的递归定义,其实对三种遍历的概念其实也是一个递归的描述过程
- 先序/根遍历DLR:1 4 5 2 3 6 7
- 中序/根遍历LDR:4 5 1 3 2 6 7
- 后序/根遍历LRD:5 4 3 7 6 2 1
如果按层次遍历,没有递归
面试题:已知一棵二叉树的后序遍历的序列为5 4 3 7 6 2 1,中序遍历的序列为4 5 1 3 2 6 7,则其先序遍历的序列是什么?
只要给定中序遍历,先序遍历或者后序遍历再给一个,就可以求出另一个
后序遍历最后肯定是根,所以确定1是根
所以4 5是左子树,3 2 6 7是右子树
依此类推
/**
*二叉链表的结点
**/
public class Node{
Object value;//结点值
Node leftChild;//左子树的引用
Node rightChild;//右子树的引用
private Node(Object value, Node leftChild, Node rightChild){
super();
this.value=value;
this.leftChild = leftChild;
this.rightChild = rightChild;
}
public Node(Object value){
super();
this.value = value
}
public String toString(){
return "Node [value="+value+", leftChild="+leftChild+", rightChild="+rightChild+"]";
}
}
/**
*二叉树的接口
*可以有不同的实现类,每个类可以使用不同的存储结构,比如顺序结构、链式结构
**/
public interface BinaryTree{
//是否空树
public boolean isEmpty();
//树结点数量
public int size();
//获取二叉树的高度
public int getHeight();
//查询指定的结点
public Node findKey(int value);
//前序递归遍历
public void preOrderTraverse();
//中序遍历递归操作
public void inOrderTraverse();
//后序遍历递归操作
public void postOrderTraverse();
//后序遍历递归操作
post void postOrderTraverse(Node node);
//中序遍历非递归操作
public void inOrderByStack();
//前序遍历非递归操作
public void preOrderByStack();
//后序遍历非递归操作
public void postOrderByStack();
//按照层次遍历二叉树
public void levelOrderByStack();
}
public class LinkedBinaryTree implements BinaryTree{
private Note root; //根结点
public LinkedBinaryTree(){
super();
}
public LinkedBinaryTree(Node root){
super();
this.root = root;
}
public boolean isEmpty(){
return root == null;
}
public void preOrderTraverse(){
//输出根结点的值
if(root!=null){
System.out.print(root.value+" ");
//对左子树进行先序遍历
//构建一个二叉树,根是左子树的根
BinaryTree leftTree = new LinkedBinaryTree(root.leftChild);
leftTree.preOrderTraverse();
//对右子树进行先序遍历
//构建一个二叉树,根是右子树的根
BinaryTree rightTree = new LinkedBinaryTree(root.rightChild);
rightTree.preOrderTraverse();
}
}
public void inOrderTraverse(){
System.out.println("中序遍历");
this.inOrderTraverse(root);
System.out.println();
}
private void inOrderTraverse(Node root){
if(root!=null){
//遍历左子树
this.inOrderTraverse(root.leftChild)
//输出根的值
System.out.println(root.value+" ")
//遍历右子树
this.inOrderTraverse(root.rightChild)
}
}
public void postOrderTraverse(){
System.out.println("后序遍历");
this.postOrderTraverse(root);
System.out.println();
}
private void postOrderTraverse(Node node){
if(node!=null){
//遍历左子树
this.postOrderTraverse(node.leftChild);
//遍历右子树
this.postOrderTraverse(node.rightChild);
//输出根的值
System.out.print(node.value+" ");
}
}
public int getHeight(){
System.out.println("二叉树的高度是:");
return this.getHeight(root);
}
private int getHeight(Node root){
if(root==null){
return 0;
}else{
//获取左子树的高度
int nl=this.getHeight(root.leftChild);
//获取右子树的高度
int nr=this.getHeight(root.rightChild);
//返回左子树、右子树较大高度并加1
return nl>nr?nl+1:nr+1;
}
}
public int size(){
System.out.println("二叉树结点个数:");
return this.size(root);
}
private int size(Node root){
if(root == null){
return 0;
}else{
//获取左子树的size
int nl = this.size(root.leftChild);
//获取右子树的size
int nr = this.size(root.rightChild);
//返回左子树、右子树size只和并加一
return nl+nr+1
}
}
public Node findKey(int value){
return this.findKey(value,root);
}
public Node findKey(Object value, Node root){
if(root==null){//递归结束条件1:结点为空,可能是整个树的根结点,也可能是递归调用中叶子结点的左孩子和右孩子
return null;
}else if(root != null && root.value == value){//递归结束条件2:找到了
return root;
}else{//递归体
Node node1 = this.findKey(value,root.leftChild);
Node node2 = this.findKey(value,root.rightChild);
if(node1!null && node1.value == value){
return node1;
}else if(node2!null && node2.value == value){
return node2;
}else{
return null;
}
}
}
public void inOrderByStack(){
System.out.println("中序非递归遍历:");
//创建栈
Deque<Node> stack = new LinkedList<Node>();
Node current = root;
while(current!=null||!stack.isEmpty()){
while(current != null){
stack.push(current);
current = current.leftChild();
}
if(!stack.isEmpty()){
current = stack.pop();
System.out.println(current.value+" ");
current = current.rightChild;
}
}
}
public void levelOrderByStack(){
System.out.println("按照层次遍历二叉树");
if(root==null) return;
Queue<Node> queue = new LinkedList<Node>();
queue.add(root);
while(queue.size()!=0){
int len = queue.size();
for(int i=0;i<len;i++){
Node temp = queue.poll();
System.out.println(temp.value+" ");
if(temp.leftChild!=null) queue.add(temp.leftChild);
if(temp.rightChild!=null) queue.add(temp.rightChild);
}
}
}
}
public class Test{
public static void main(String[] args){
//创建一个二叉树
Node node5 = new Node(5,null,null);
Node node4 = new Node(4,null,node5);
Node node3 = new Node(3,null,null);
Node node7 = new Node(7,null,null);
Node node6 = new Node(6,null,node7);
Node node2 = new Node(2,node3,node6);
Node node1 = new Node(1,node4,node2);
BinaryTree btree = new LinkedBonaryTree(node1);
//判断二叉树是否为空
System.out.println(btree.isEmpty());
//先序遍历递归
btree.preOrderTraverse();
//中序遍历递归
btree.inOrderTraverse();
//后序遍历递归
btree.postOrderTraverse();
//二叉树的高度
System.out.println(btree.getHeight());
//二叉树的结点数量
System.out.println(btree.size());
//按照层次遍历(借助队列)
btree.levelOrderByStack();
//在二叉树中查找某个值
System.out.println(btree.findKey(1));
}
}