二叉树遍历:
遍历是对树的一种最基本的运算,所谓遍历二叉树,就是按一定的规则和顺序走遍二叉树的所有结点,使每一个结点都被访问一次,而且只被访问一次。由于二叉树是非线性结构,因此,树的遍历实质上是将二叉树的各个结点转换成为一个线性序列来表示。
设L、D、R分别表示遍历左子树、访问根结点和遍历右子树, 则对一棵二叉树的遍历有三种情况:DLR(称为先根次序遍历),LDR(称为中根次序遍历),LRD (称为后根次序遍历)。
树的结点的数据结构:
class Node {
public char val;
public Node left;//左子树结点
public Node right;//右子树结点
public Node(char val) {
this.val = val;
}
}
设计树的形状:
前序遍历:
// 前序遍历
void preOrderTraversal(Node root) {
//节点为空结束方法
if(root == null) {
return;
}
//访问根节点对其进行操作
System.out.print(root.val + " ");
//访问根的左节点
preOrderTraversal(root.left);
//访问根的右节点
preOrderTraversal(root.right);
}
- 给方法传入根结点不为访问该结点(上面代码的访问方式就是输出该结点的val值A)。
- 递归调用该方法传入该结点的左子树的结点。
- 若不为空访问该结点,重复2的操作。
- 直到访问到传入结点为空也就是上图访问D的左结点的时候,return结束方法返回在传入结点是B的时候的那个方法内。
- 然后执行给方法传入是B结点的时候的那个方法的preOrderTraversal(root.right);访问B的右结点。
- 此时再次调用方法传入的是E结点。
- E不为空访问E,然后再次调用preOrderTraversal(root.left)。
- 传入F不为空,访问F然后再访问F的左结点为空,右结点也为空,该方法执行完,返回上一个方法。
- E的右为空方法执行结束,返回上一个方法。
- B的方法执行完毕返回上一个方法。
- 此时回到最初的那个传入的是A结点的那个方法,然后访问A的右节点C。
- 访问C结点,然后C的左结点为空,访问C的右结点G。
- 访问G结点后,G的左右结点都为空,方法执行结束,返回上一个方法。
- 传入结点为C的方法执行结束,返回最初的那个方法。
- 最初的那个方法执行结束,该树全遍历完。
中序遍历:
// 中序遍历
void inOrderTraversal(Node root) {
//节点为空结束方法
if(root == null) {
return;
}
//访问根的左节点
inOrderTraversal(root.left);
//访问根节点对其进行操作
System.out.print(root.val + " ");
//访问根的右节点
inOrderTraversal(root.right);
}
后序遍历:
// 后序遍历
void postOrderTraversal(Node root) {
//节点为空结束方法
if(root == null) {
return;
}
//访问根的左节点
postOrderTraversal(root.left);
//访问根的右节点
postOrderTraversal(root.right);
//访问根节点对其进行操作
System.out.print(root.val + " ");
}
三种遍历方式大同小异,有相同的地方也有不同的地方。
**- 相同的地方:都是对二叉树的一种遍历,都是在每次调用遍历方法的时候对结点要进行判空,如果该结点的左结点或者右结点不为空就会一直调用下去,知道为空。
- 不同的地方:不同点还是在于对每个结点的访问时间不同,所谓前中后序遍历,其实还是对结点的访问的前中后,例如前序遍历结点只要不为空,前序遍历会先访问结点再进行调用方法访问其左结点和右结点。**
代码执行结果:
前序遍历
A B D E G C F
中序遍历
D B G E A C F
后序遍历
D G E B F C A
迭代实现:
//非递归实现先序遍历链表返回
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
if(root == null) {
return list;
}
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.empty()) {
TreeNode node = stack.pop();
list.add(node.val);
if(node.right != null) {
stack.push(node.right);
}
if(node.left != null) {
stack.push(node.left);
}
}
return list;
}
//非递归实现中序遍历链表返回
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
if(root == null) {
return list;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
while(true) {
while(cur != null) {
stack.push(cur);
cur = cur.left;
}
if(stack.empty()) {
break;
}
TreeNode node = stack.pop();
list.add(node.val);
cur = node.right;
}
return list;
}
//非递归实现后序遍历链表返回
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
if(root == null) {
return list;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode cur = root;
TreeNode prev = null;
while(true) {
while(cur != null) {
stack.push(cur);
cur = cur.left;
}
if(stack.empty()) {
break;
}
TreeNode node = stack.peek();
if(node.right == null || node.right == prev) {
list.add(node.val);
stack.pop();
prev = node;
}else {
cur = node.right;
}
}
return list;
}