why
MySQL、Hbase、HashMap等底层分别通过B树、B+树、红黑树等来提高性能
而这些树的基础为二叉树,熟悉二叉树的基本操作后再去学习这些技术会事半功倍
what
二叉树,顾名思义,每个节点最多仅有两个子节点,被广泛应用于搜索的场景
时间复杂度一般为 O(depth) 也就是树的高度
空间复杂度一般为 O(node.number)也就是树的节点数
本篇博客计划记录二叉树的递归/非递归遍历、按层打印,
以及序列化/反序列化、重建二叉树 //此行是还没实现的
HOW
递归方式遍历二叉树
由于递归方式比较简单,因此三种遍历的方式写在一块
public int[][] convert(TreeNode root) {
List<Integer> qianxuList = new ArrayList();
List<Integer> zhongxuList = new ArrayList();
List<Integer> houxuList = new ArrayList();
qianxu(qianxuList,root);
zhongxu(zhongxuList,root);
houxu(houxuList,root);
int [][]result = new int[3][qianxuList.size()];
for (int i=0; i < qianxuList.size(); i++){
result [0][i] = qianxuList.get(i);
result [1][i] = zhongxuList.get(i);
result [2][i] = houxuList.get(i);
}
return result;
}
//递归前序遍历
public static void qianxu(List<Integer> list,TreeNode root) {
if (null == root)
return;
list.add(root.val);
qianxu(list,root.left);
qianxu(list,root.right);
}
//递归中序遍历
public static void zhongxu(List<Integer> list,TreeNode root) {
if (null == root)
return;
zhongxu(list,root.left);
list.add(root.val);
zhongxu(list,root.right);
}
//递归前序遍历
public static void houxu(List<Integer> list,TreeNode root) {
if (null == root)
return;
houxu(list,root.left);
houxu(list,root.right);
list.add(root.val);
}
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
非递归遍历
由于递归遍历的代价相对较大(java里面会用帧栈来存储中间结果),因此非递归遍历的方式还是有学习的必要
- 前序遍历二叉树
① 将根节点放到栈内
② 遍历栈,栈为空则停止
③ 进行出栈操作,将当前节点的值记录到集合内
④ 若是当前节点的右节点不为空,则进栈;若是当前节点的左节点不为空,也进栈
⑤ 重复2-4步骤
public static void qianxu(List<Integer> list,TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
if (null == root)
return;
stack.push(root);
while(!stack.isEmpty()){
TreeNode node = stack.pop();
list.add(node.val);
if (null != node.right){
stack.push(node.right);
}
if (null != node.left){
stack.push(node.left);
}
}
}
- 中序遍历二叉树
① 将根节点放到栈内,判断根节点是否有左子节点,若有则继续往里面放,然后再判断左子节点是否有左子节点,若有则继续重复该
② 遍历栈,栈为空则停止
③ 进行出栈操作,将当前节点的值记录到集合
④ 判断当前节点是否有右子节点,若有则重复1步骤
public static void zhongxu(List<Integer> list,TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
if (null == root) return;
stack.push(root);
while(null != root.left){
stack.push(root.left);
root = root.left;
}
while(!stack.isEmpty()){
TreeNode node = stack.pop();
list.add(node.val);
if (null != node.right){
stack.push(node.right);
node = node.right;
while(null != node.left){
stack.push(node.left);
node = node.left;
}
}
}
}
- 后序遍历二叉树
① 创建两个栈分别为栈A和栈B
② 将根节点放到栈A
③ 遍历栈A,当栈A为空的时候停止
④ 栈A出栈,取出节点放到栈B;同时先把该节点的左子节点放到栈A里,再把该节点的右子节点放到栈B里
⑤ 重复步骤4直到栈A为空,然后对栈B进行出栈操作即可
public static void houxu(List<Integer> list,TreeNode root) {
if (null == root) return;
Stack<TreeNode> stackA = new Stack<>();
Stack<TreeNode> stackB = new Stack<>();
stackA.push(root);
while(!stackA.isEmpty()){
TreeNode node = stackA.pop();
stackB.push(node);
if (null != node.left){
stackA.push(node.left);
}
if (null != node.right){
stackA.push(node.right);
}
}
while(!stackB.isEmpty()){
TreeNode node = stackB.pop();
list.add(node.val);
}
}
按层遍历二叉树
① 创建一个队列,以及两个指针last和nextLast分别指向当前层的最后一个节点
以及下层最后一个节点,同时定义变量depth用于记录当前遍历的层数
② 将根节点放入队列,指针last和nextLast都指向根节点
③ 遍历队列,直到队列为空才停
④ 取出队列中的节点,存储该节点的值,如果该节点有左右子节点,分别按顺序放到队列里,并且调制nextLast去指向最后加入队列的那个节点;同时如果该节点被last指向,则表示该层已经遍历完毕,depth自增1,last指向nextLast
⑤ 重复4步骤直到队列为空
public static void main(String []args){
TreeNode treeNode1 = new TreeNode(1);
TreeNode treeNode2 = new TreeNode(2);
TreeNode treeNode3 = new TreeNode(3);
TreeNode treeNode4 = new TreeNode(4);
TreeNode treeNode5 = new TreeNode(5);
treeNode1.left = treeNode2;
treeNode1.right = treeNode3;
treeNode2.left = treeNode4;
treeNode2.right = treeNode5;
int [][]result = printTreeByDepth(treeNode1);
for (int i=0;i<result.length;i++){
int depth = i+1;
System.out.println(depth+":");
for (int j=0;j<result[i].length;j++){
System.out.print(result[i][j]);
}
}
}
public static int [][] printTreeByDepth(TreeNode root) {
//遍历二叉树求得二叉树的高度,用于初始化存放结果的数组
int treeDepth = getTreeDepth(root);
int [][]result = new int[treeDepth][5];
Queue<TreeNode> queue = new LinkedList<>();
TreeNode last = root;
TreeNode nextLast = root;
int depth = 0;
int i = 0; //表示遍历到当前层的第几个节点
queue.offer(root);
while(!queue.isEmpty()){
TreeNode node = queue.poll();
result[depth][i] = node.val;
i++;
if (null != node.left){
queue.offer(node.left);
nextLast = node.left;
}
if (null != node.right){
queue.offer(node.right);
nextLast = node.right;
}
if (last == node){
depth++;
i=0;
last = nextLast;
}
}
return result;
}
public static int getTreeDepth(TreeNode root){
int depth = 0;
if (null == root){
return depth;
}else {
return 1 + Math.max(getTreeDepth(root.left),getTreeDepth(root.right));
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。