二叉树的基本知识
二叉树的四种遍历方式
不要较真,其实也可以分为两种:广度优先(层级)和深度优先(前序、中序、后序)
基本概念不再赘述。复杂度:设二叉树中元素数目为n。这四种遍历算法的空间复杂性均为O (n),时间复杂性为O(n)。
二叉树数据结构
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode() {}
TreeNode(int val) { this.val = val; }
TreeNode(int val, TreeNode left, TreeNode right) {
this.val = val;
this.left = left;
this.right = right;
}
}
1
/ \
2 5
/ \
3 4
前序遍历
遍历顺序:根节点-> 左节点-> 右节点
代码实现:
/**
* 前序遍历 根 -> 左 -> 右
*/
public void preOrder(TreeNode tree){
if (tree == null){
return;
}
System.out.print(tree.val);
preOrder(tree.left);
preOrder(tree.right);
}
非递归方式
//java 中使用 Deque, Stack已经弃用。
//Deque 的使用用法:push、pop。
public void perOrderIter(TreeNode root){
if (root == null){
return;
}
Deque<TreeNode> stack = new ArrayDeque<>();
StringBuilder result = new StringBuilder();
stack.push(root);
while(!stack.isEmpty()){
TreeNode treeNode = stack.pop();
result.append(treeNode.val);
if (treeNode.right != null){
stack.push(treeNode.right);
}
if (treeNode.left != null){
stack.push(treeNode.left);
}
}
System.out.println(result.toString());
}
中序遍历
遍历顺序:左节点-> 根节点-> 右节点
代码实现
/**
* 中序遍历 左 -> 根 -> 右
* 结果:32415
*/
public void midOrder(TreeNode tree){
if (tree == null){
return;
}
midOrder(tree.left);
System.out.print(tree.val);
midOrder(tree.right);
}
/**
* 迭代式中序遍历 左 -> 根 -> 右
* 这个比较难,重点关注一下。
*/
public void minOrderIter(TreeNode root){
if (root == null){
return;
}
Deque<TreeNode> stack = new ArrayDeque<>();
StringBuilder result = new StringBuilder();
while(root != null || !stack.isEmpty()){
//此处的目的是放入将根节点放入,然后将根节点的左节点压在根节点上面。
while (root != null){
stack.push(root);
root = root.left;
}
//调出栈
root = stack.pop();
result.append(root.val);
root = root.right;
}
System.out.println(result.toString());
}
后序遍历
遍历顺序:左节点-> 右节点-> 根节点
/**
* 后序遍历 左 -> 右 -> 根
* 结果:34251
*/
public void postOrder(TreeNode tree){
if (tree == null){
return;
}
postOrder(tree.left);
postOrder(tree.right);
System.out.print(tree.val);
}
/**
* 迭代式后序遍历
* 后序遍历更复杂!!!!
* 先遍历左节点 -> 右节点 -> 根节点
* 1
* / \
* 2 5
* / \
* 3 4
* / \
* 7 8
*/
public void postOrderIter(TreeNode root){
if (root == null){
return;
}
Deque<TreeNode> stack = new ArrayDeque<>();
StringBuilder result = new StringBuilder();
TreeNode pre = null; //记录前置节点
while(root != null || !stack.isEmpty()){
//把所有的左子树节点都放入栈中
while(root != null){
stack.push(root);
root = root.left;
}
//找到当前节点
root = stack.pop();
//如果当前节点的右节点为空
//这里为什么会有对pre的判断,是为了避免重复处理。
//拿例子:当8已经处理完了之后,应该处理4节点,当时发现4也是有右子树的,但是8已经处理过了,通过pre达标,那么8也不用处理。
if (root.right == null || pre == root.right){
result.append(root.val);
//设置前置节点
pre = root;
//置为空的目的是处理栈中堆积的父节点。
root = null;
} else{
//右节点非空,说明当前节点这个时候不能够处理,就把当前节点再放回去。
stack.push(root);
//把当前节点的右节点作为root进行处理。
root = root.right;
}
}
System.out.println(result.toString());
}
层级遍历
/**
* 层级遍历
* 递归的方式
* 递归需要存储每个的层级 对应的数据都有什么,借助额外的数据结构
*/
public List<StringBuilder> result = new ArrayList<>();
public void levelOrder(TreeNode root, int level) {
if (root == null) {
return;
}
//当数组大小等于层级时,初始化该层级需要的存储空间
if (result.size() == level) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(root.val);
result.add(level, stringBuilder);
} else {
result.get(level).append(root.val);
}
levelOrder(root.left, level + 1);
levelOrder(root.right, level + 1);
}
/**
* 迭代式层级遍历
* 借助额外的数据结构:队列,特性:先进先出
* queue 的基本用法:add(offer),remove(poll)
*/
public void levelOrderIter(TreeNode root) {
if (root == null) {
return;
}
StringBuilder result = new StringBuilder();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
TreeNode current = queue.poll();
result.append(current.val);
if (current.left != null){
queue.add(current.left);
}
if (current.right != null){
queue.add(current.right);
}
}
System.out.println(result.toString());
}
额外:
/**
* 获取二叉树的最大深度
*/
public int getMaxDepth(TreeNode root){
if (root == null){
return 0;
}
return Math.max(getMaxDepth(root.left)+1,getMaxDepth(root.right)+1);
}
文章作者: 冯廷鑫
文章链接: http://fengtingxin.github.io/2022/06/12/二叉树的基本知识/
一个入行不久的Java开发,越学习越感觉知识太多,自身了解太少,只能不断追寻