二叉树:
二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个结点最多只能有两棵子树,且有左右之分。
二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个结点。(百度百科)
二叉树的深度优先遍历:
二叉树的深度优先遍历有三种方式:前序遍历、中序遍历、后序遍历。
上图所示为一颗二叉树,它还是一颗AVL树,不知道AVL的可以查看(AVL):
以上图为例,该树的前序遍历为:4、2、1、3、6、5、7;
中序遍历为:1、2、3、4、5、6、7;
后序遍历为:1、3、2、5、7、6、4;
代码实现:
- 首先创建一个二叉树对象,root为树的根节点:
class Tree<T> {
T root;
Tree<T> left;
Tree<T> right;
public Tree(T root) {
this.root = root;
}
}
- 遍历的递归实现,通过递归算法可以实现二叉树的遍历:
//前序遍历
public static void frontTree(Tree tree) {
if (null == tree) {
return;
}
System.out.print(tree.root+" ");
frontTree(tree.left);
frontTree(tree.right);
}
//中序遍历
public static void middleTree(Tree tree) {
if (null == tree) {
return;
}
middleTree(tree.left);
System.out.print(tree.root+" ");
middleTree(tree.right);
}
//后序遍历
public static void behindTree(Tree tree) {
if (null == tree) {
return;
}
behindTree(tree.left);
behindTree(tree.right);
System.out.print(tree.root+" ");
}
- 遍历的非递归实现,以下主要采用栈这种数据结构来实现:
//前序遍历
public static void frontNoTree(Tree tree) {
if (tree == null) {
return;
}
Stack<Tree> stack = new Stack<Tree>();
stack.push(tree);
while (!stack.empty()) {
tree = stack.pop();
System.out.print(tree.root + " ");
if (tree.right != null) {
stack.push(tree.right);
}
if (tree.left != null) {
stack.push(tree.left);
}
}
}
//中序遍历
public static void middleNoTree(Tree tree) {
if (tree == null) {
return;
}
Stack<Tree> stack = new Stack<>();
while (!stack.empty() || tree != null) {
while (tree != null) {
stack.push(tree);
tree = tree.left;
}
tree = stack.pop();
System.out.print(tree.root + " ");
tree = tree.right;
}
}
//后序遍历
public static void behindNoTree(Tree tree) {
if (null == tree) {
return;
}
Stack<Tree> stack = new Stack<Tree>();
Tree p = tree;
while (!stack.empty() || tree != null){
while (tree != null){
stack.push(tree);
tree = tree.left;
}
tree = stack.peek().right;
if (tree == null || tree == p){
tree = stack.pop();
System.out.print(tree.root + " ");
p = tree;
tree = null;
}
}
}
二叉树的广度优先遍历:
根据上图中的二叉树进行广度优先遍历:4、2、6、1、3、5、7;
可以看出广度优先遍历实际上就是层级遍历,从第一层遍历到第三层。
代码实现:
- 递归实现,在递归实现中需要都得到树的高度,然后根据高度一层层访问:
//首先要知道树的高度
public static Integer lengthTree(Tree tree){
if (tree == null){
return 0;
}
return Math.max(lengthTree(tree.left),lengthTree(tree.right))+1;
}
//设置访问一层的方法
public static void yiceng(Tree tree, Integer length) {
if (tree == null || length < 1){
return;
}
if (length == 1){
System.out.print(tree.root + " ");
return;
}
yiceng(tree.left, length - 1);
yiceng(tree.right, length - 1);
}
//递归层次遍历
public static void guangduTree(Tree tree){
if (tree == null){
return;
}
Integer treeLength = lengthTree(tree);
//i=1表示从第一行开始,直到第三层
for (int i = 1; i < treeLength + 1; i++) {
yiceng(tree, i);
}
}
- 非递归实现,主要是采用队列的形式去实现:
//非递归层次遍历:采用队列实现
public static void guangduNoTree(Tree tree){
if (tree == null){
return;
}
Queue<Tree> queue = new LinkedList<Tree>();
queue.offer(tree);//等同于add方法,不同在于add超出队列界限会抛出异常,offer会返回false
while (!queue.isEmpty()){
Integer size = queue.size();
for (int i = 0; i < size; i++) {
tree = queue.poll();//检索队列的head元素,然后删除
if (tree.left != null){
queue.offer(tree.left);
}
if (tree.right != null){
queue.offer(tree.right);
}
System.out.print(tree.root + " ");
}
}
}
测试一下上面的方法:
public static void main(String[] args) {
//初始化一颗树
Tree a = new Tree(1);
Tree b = new Tree(2);
Tree c = new Tree(3);
Tree d = new Tree(4);
Tree e = new Tree(5);
Tree f = new Tree(6);
Tree g = new Tree(7);
d.left = b;
d.right = f;
b.left = a;
b.right = c;
f.left = e;
f.right = g;
System.out.print("递归前序:");
frontTree(d);
System.out.println();
System.out.print("递归中序:");
middleTree(d);
System.out.println();
System.out.print("递归后序:");
behindTree(d);
System.out.println();
System.out.print("非递归前序:");
frontNoTree(d);
System.out.println();
System.out.print("非递归中序:");
middleNoTree(d);
System.out.println();
System.out.print("非递归后序:");
behindNoTree(d);
System.out.println();
System.out.print("递归层次遍历(广度优先遍历):");
guangduTree(d);
System.out.println();
System.out.print("非递归层次遍历(广度优先遍历):");
guangduNoTree(d);
}
运行结果:
递归前序:4 2 1 3 6 5 7
递归中序:1 2 3 4 5 6 7
递归后序:1 3 2 5 7 6 4
非递归前序:4 2 1 3 6 5 7
非递归中序:1 2 3 4 5 6 7
非递归后序:1 3 2 5 7 6 4
递归层次遍历(广度优先遍历):4 2 6 1 3 5 7
非递归层次遍历(广度优先遍历):4 2 6 1 3 5 7
写博客是为了记录自己容易忘记的东西,也是对自己学习的总结,大家一起加油!