二叉树的深度优先遍历(DFS)和广度优先遍历(BFS)多种实现方法

一:二叉树的深度优先遍历(DFS)

二叉树的递归序、先序、中序和后序

  1. 递归实现
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);
}
}
  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
叉树广度优先BFS)可以使用队列来实现,具体步骤如下: 1. 创建一个空队列,并将根节点入队。 2. 当队列不为空时,执行以下操作: - 出队一个节点,将其值存储或打印。 - 将出队节点的左子节点入队(如果存在)。 - 将出队节点的右子节点入队(如果存在)。 3. 重复步骤2,直到队列为空。 下面是一个Python实现的示例代码: ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val self.left = left self.right = right def bfs(root): if not root: return [] result = [] queue = [root] while queue: node = queue.pop(0) result.append(node.val) if node.left: queue.append(node.left) if node.right: queue.append(node.right) return result ``` 对于深度优先DFS),有两种常用的方法:前序遍、中序遍和后序遍。下面以前序遍为例进行解释。 前序遍的顺序是:根节点 -> 左子树 -> 右子树。具体实现步骤如下: 1. 创建一个空列表,用于存储遍结果。 2. 定义一个辅助函数,接收一个节点作为参数: - 若节点为空,返回。 - 将节点的值存储或打印。 - 递归调用辅助函数遍节点的左子树。 - 递归调用辅助函数遍节点的右子树。 3. 调用辅助函数,将根节点作为参数传入。 下面是一个Python实现的示例代码: ```python def dfs(root): if not root: return [] result = [] def helper(node): if not node: return result.append(node.val) helper(node.left) helper(node.right) helper(root) return result ``` 这样,你就可以使用这两个函数来实现叉树广度优先深度优先了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值