一:二叉树的深度优先遍历(DFS)
二叉树的递归序、先序、中序和后序
- 递归实现
class Node{
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
}
// 递归实现二叉树的前中后排序 根据递归排序得出
public void preSort1(Node head){
if (head == null){
return;
}
// 第一次遇到输出是先序 即:头左右
System.out.println(head.value + " ");
preSort1(head.left);
preSort1(head.right);
}
public void inSort1(Node head){
if (head == null){
return;
}
inSort1(head.left);
// 第二次遇到输出是中序 即:左头右
System.out.println(head.value + " ");
inSort1(head.right);
}
public void posSort1(Node head){
if (head == null){
return;
}
posSort1(head.left);
posSort1(head.right);
// 第三次遇到输出是后序 即:左右头
System.out.println(head.value + " ");
}
2.非递归实现
// 非递归实现二叉树的前中后排序 使用栈
// 先序 使用栈 先压右再压左 依次弹出
public void preSort2(Node head){
if (head != null){
Stack<Node> stack = new Stack<>();
stack.push(head);
while (!stack.empty()){
head = stack.pop();
System.out.print(head.value+" ");
if (head.right != null){
stack.push(head.right);
}
if (head.left != null){
stack.push(head.left);
}
}
}
}
// 中序 使用栈 先将左侧全部压入栈中 依次弹出
public void inSort2(Node head){
if (head != null){
Stack<Node> stack = new Stack<>();
while (!stack.empty() || head != null){
if (head != null){
stack.push(head);
head = head.left;
}else {
head = stack.pop();
System.out.print(head.value + " ");
head = head.right;
}
}
}
}
// 后序 使用两个栈 一个是先序的但是变成先压左再压右 变成了 头右左 再依次存入第二个栈中变成了 左右头
public void posSort2(Node head){
if (head != null){
Stack<Node> stack1 = new Stack<>();
Stack<Node> stack2 = new Stack<>();
stack1.push(head);
while (!stack1.empty()){
head = stack1.pop();
stack2.push(head);
if (head.left != null){
stack1.push(head.left);
}
if (head.right != null){
stack1.push(head.right);
}
}
while (!stack2.empty()){
System.out.print(stack2.pop().value + " ");
}
}
二:二叉树的广度优先遍历(BFS)(求树的宽度/求每一层的各个节点)
层次排序与此类似只需要自行修改即可
1.采用哈希表的思想(思想:使用Map集合 存入每一个节点 key是节点 value是节点所在的层数 每次循环时 从队列中取出节点 并获取它的所在层数 判断节点所在层数是否和当前层数相同 如果相同 则对当前层数的节点数加1 如果不同则说明已经进入下一层了 这时候就需要进行结算 即对Max(宽度)重新进行赋值 并且使当前节点重新赋值为1(因为目前已经进入下一层的第一个节点了) 并且将层级数加1 后需要将该节点的左右孩子加入到队列中 并且加入前也需要将其存入到Map集合中 层数是当前节点所在层数再加1 以此循环 结束条件为队列为空)
// 二叉树的宽度优先遍历(如:求一棵二叉树的宽度)
// 使用队列的思路 先进先出 (采用了哈希表的思想)
public void width(Node head){
if (head == null){
return;
}
Queue<Node> queue = new LinkedList<>();
HashMap<Node,Integer> map = new HashMap<>();
map.put(head,1);
queue.add(head);
int curLevel = 1;
int curLevelNods = 0;
int max = Integer.MIN_VALUE;
while (!queue.isEmpty()){
Node cur = queue.poll();
int NodeCurLevel = map.get(cur);
if (NodeCurLevel == curLevel){
curLevelNods++;
}else {
max = Math.max(curLevelNods,max);
curLevelNods = 1;
curLevel++;
}
if (cur.left != null){
map.put(cur.left,NodeCurLevel+1);
queue.add(cur.left);
}
if (cur.right != null){
map.put(cur.right,NodeCurLevel+1);
queue.add(cur.right);
}
}
System.out.println(max);
}
2.不采用哈希表的思想(思想:将它们放到队列中 设置当前层结束点 下一层结束点 如果当前节点等于当前层结束点 那么该层就结束了 将当前层结束点和下一层结束点进行置换 下一层结束点再置为空 依次循环 最终结束条件是 当前层结束点为null )
// 只使用队列
public void width2(Node head){
if (head != null){
Node curEnd = head;
Node nextEnd = null;
int max = Integer.MIN_VALUE;
int curLevelNods = 0;
Queue<Node> queue = new LinkedList<>();
queue.offer(head);
while (curEnd != null){
head = queue.poll();
curLevelNods++;
if (head != null && head.left != null) {
queue.offer(head.left);
nextEnd = head.left;
}
if (head != null && head.right != null) {
queue.offer(head.right);
nextEnd = head.right;
}
if (curEnd == head){
max = Math.max(max,curLevelNods);
curEnd = nextEnd;
nextEnd = null;
curLevelNods = 0;
}
}
System.out.println(max);
}
}
3.不采用哈希表 使用for循环(思想:根据当前队列的长度 使用for循环 来找到当前层的下一层的节点 并将它们添加到队列中去 并将当前层的节点再循环中依次弹出 这样循环结束后留下的节点就是下一层的节点了 这样每一层的长度就是每一层的宽度)
public void width3(Node head){
if (head != null){
Queue<Node> queue = new LinkedList<>();
queue.offer(head);
int max = Integer.MIN_VALUE;
while (!queue.isEmpty()){
int n = queue.size();
max = Math.max(max,n);
for (int i = 0; i < n; i++) {
head = queue.poll();
if (head != null){
if (head.left != null){
queue.offer(head.left);
}
if (head.right != null){
queue.offer(head.right);
}
}
}
}
System.out.println(max);
}
}