二叉树 - DFS与BFS

​ 深度优先遍历 (DFS Depth First Search) 就是一个节点不到头(叶子节点为空) 不回头

​ 广度有点遍历(BFS Breadth First Search) 就是一层一层输出 , 输出到最下层的叶子节点, 为空的时候结束

​ 其中深度遍历就是我们所说的 先序遍历 中序遍历 后序遍历 , 先中后指的是根节点输出的时机,先就是根左右

数据结构如下, 全文都是

public class TreeNode {
int val;
TreeNode left;
TreeNode right; TreeNode(int x) {
val = x;
}

输出要求

List<Integer> search(TreeNode root) {
// do 需要返回一个数组
}

测试数据

TreeNode root = new TreeNode(1);
TreeNode left = new TreeNode(2);
TreeNode right = new TreeNode(3);
root.left = left;
root.right = right;
left.left = new TreeNode(4);
left.right = new TreeNode(5);
right.left = new TreeNode(6);

1. DFS

1. 递归实现

​ 递归实现代码相当之简单 , 所以很容易写, 就算不会也能记忆下来

1. 先序遍历

private List<Integer> preOrder(TreeNode root) {
if (null == root) return Collections.emptyList();
List<Integer> list = new ArrayList<>();
recursion(list, root);
return list;
} // 递归
private void recursion(List<Integer> list, TreeNode root) {
if (null == root) return;
// 根
list.add(root.val);
// 左
recursion(list, root.left);
// 右
recursion(list, root.right);
}

2. 中序遍历

private List<Integer> midOrder(TreeNode root) {
if (null == root) return Collections.emptyList();
List<Integer> list = new ArrayList<>();
recursion(list, root);
return list;
} private void recursion(List<Integer> list, TreeNode root) {
if (null == root) return;
recursion(list, root.left);
// 调换到中间
list.add(root.val);
recursion(list, root.right);
}

3. 后序遍历

private List<Integer> aftOrder(TreeNode root) {
if (null == root) return Collections.emptyList();
List<Integer> list = new ArrayList<>();
recursion(list, root);
return list;
} private void recursion(List<Integer> list, TreeNode root) {
if (null == root) return;
recursion(list, root.left);
recursion(list, root.right);
// 调换到最后
list.add(root.val);
}

2. 递归执行流程

三种流程基本都差不多

​ 好多人对于递归并不了解, 执行流程 , 我们知道方法的出栈需要一个return, 所以递归就是在找这个 , 就拿我们上面说的那个先序遍历为例子吧 .

3. 非递归实现(很重要)

​ 递归的坏处就是 , 出入栈消耗大量的内存, 每一次方法的调用都会保存大量的变量, 多以对于遍历来说并不好 ,

​ 非递归遍历的实现 , 基于栈的实现, 对于遍历节点保存在栈中, 出入栈 , 主要利用栈的后进先出的特性 , 很好的保证了, 后进的优先遍历 .

1. 先序遍历

非递归实现先序遍历

private List<Integer> preOrderUnRecursion(TreeNode root) {
if (null == root) return Collections.emptyList();
List<Integer> list = new ArrayList<>();
// 栈
LinkedList<TreeNode> stack = new LinkedList<TreeNode>(); // 压栈
stack.push(root);
while (stack.size() > 0) {
// 出栈
TreeNode node = stack.pop(); TreeNode right = node.right;
if (null != right) {
stack.push(right);
} TreeNode left = node.left; if (null != left) {
stack.push(left);
} list.add(node.val);
}
return list;
}

2. 中序遍历

​ 这个实现就比较麻烦了 , 因为先序遍历, 根节点有先天的优势可以先出去 ,所以很

private List<Integer> midOrderUnRecursion(TreeNode root) {
if (null == root) return Collections.emptyList();
List<Integer> list = new ArrayList<>();
// 栈
LinkedList<TreeNode> stack = new LinkedList<TreeNode>(); // 压栈
stack.push(root); while (stack.size() > 0) {
// 出栈
TreeNode node = stack.pop(); TreeNode right = node.right;
TreeNode left = node.left; if (null != right) {
node.right = null;
stack.push(right);
} // 重复入栈 , 是因为根节点不是最先出来的
if (null != right || null != left) {
stack.push(node);
} if (null != left) {
node.left = null;
stack.push(left);
} if (null == left && null == right) {
list.add(node.val);
}
}
return list;
}

3. 后序遍历

private List<Integer> aftFirstSearchUnRecursion(TreeNode root) {
if (null == root) return Collections.emptyList();
List<Integer> list = new ArrayList<>();
// 栈
LinkedList<TreeNode> stack = new LinkedList<TreeNode>(); // 压栈
stack.push(root); while (stack.size() > 0) {
// 出栈
TreeNode node = stack.pop(); TreeNode right = node.right;
TreeNode left = node.left; if (null != right || null != left) {
stack.push(node);
} if (null != right) {
node.right = null;
stack.push(right);
} if (null != left) {
node.left = null;
stack.push(left);
} if (null == left && null == right) {
list.add(node.val);
}
}
return list;
}

4.非递归实现流程图

1. 先序遍历

2. 中序遍历和后序遍历一样

流程从左往右, 从上往下看 .

2. BFS

​ 广度优先遍历就是一层 一层遍历 , 同一层, 从左到右输出,

​ 基于队列实现的 , FIFO特性 , offer 和 poll , 操作

代码实现

private List<Integer> breadthFirstSearch(TreeNode root) {
if (null == root) return Collections.emptyList();
ArrayList<Integer> list = new ArrayList<>();
LinkedList<TreeNode> queue = new LinkedList<>(); queue.offer(root); while (queue.peek() != null) { TreeNode poll = queue.poll(); TreeNode left = poll.left;
if (null != left) {
queue.offer(left);
} TreeNode right = poll.right;
if (null != right) {
queue.offer(right);
} list.add(poll.val);
}

基本流程图

3. 求树的深度

​ 利用树的先序遍历递归进行求树的深度

private int countDepth(TreeNode root) {
if (null == root) return 0;
int left = countDepth(root.left);
int right = countDepth(root.right);
return left >= right ? left + 1 : right + 1;
}

4. 求数的节点个数

​ 也是递归遍历

private int countNode(TreeNode root) {
if (null == root) return 0;
return countNode(root.left) + countNode(root.right)+1;
}

二叉树 - DFS与BFS的更多相关文章

  1. UVA 548.Tree-fgets()函数读入字符串+二叉树(中序+后序遍历还原二叉树)+DFS or BFS(二叉树路径最小值并且相同路径值叶子节点权值最小)

    Tree UVA - 548 题意就是多次读入两个序列,第一个是中序遍历的,第二个是后序遍历的.还原二叉树,然后从根节点走到叶子节点,找路径权值和最小的,如果有相同权值的就找叶子节点权值最小的. 最后 ...

  2. Clone Graph leetcode java(DFS and BFS 基础)

    题目: Clone an undirected graph. Each node in the graph contains a label and a list of its neighbors. ...

  3. 数据结构(12) -- 图的邻接矩阵的DFS和BFS

    //////////////////////////////////////////////////////// //图的邻接矩阵的DFS和BFS ////////////////////////// ...

  4. 数据结构(11) -- 邻接表存储图的DFS和BFS

    /////////////////////////////////////////////////////////////// //图的邻接表表示法以及DFS和BFS //////////////// ...

  5. 在DFS和BFS中一般情况可以不用vis[][]数组标记

    开始学dfs 与bfs 时一直喜欢用vis[][]来标记有没有访问过, 现在我觉得没有必要用vis[][]标记了 看代码 用'#'表示墙,'.'表示道路 if(所有情况都满足){ map[i][j]= ...

  6. 图论中DFS与BFS的区别、用法、详解…

    DFS与BFS的区别.用法.详解? 写在最前的三点: 1.所谓图的遍历就是按照某种次序访问图的每一顶点一次仅且一次. 2.实现bfs和dfs都需要解决的一个问题就是如何存储图.一般有两种方法:邻接矩阵 ...

  7. 图论中DFS与BFS的区别、用法、详解?

    DFS与BFS的区别.用法.详解? 写在最前的三点: 1.所谓图的遍历就是按照某种次序访问图的每一顶点一次仅且一次. 2.实现bfs和dfs都需要解决的一个问题就是如何存储图.一般有两种方法:邻接矩阵 ...

  8. 数据结构基础(21) --DFS与BFS

    DFS 从图中某个顶点V0 出发,访问此顶点,然后依次从V0的各个未被访问的邻接点出发深度优先搜索遍历图,直至图中所有和V0有路径相通的顶点都被访问到(使用堆栈). //使用邻接矩阵存储的无向图的深度 ...

  9. dfs和bfs的区别

    详见转载博客:https://www.cnblogs.com/wzl19981116/p/9397203.html 1.dfs(深度优先搜索)是两个搜索中先理解并使用的,其实就是暴力把所有的路径都搜索 ...

随机推荐

  1. 文本输入框UITextField和UITextView

    本文概要 1.简介 2.介绍TextField控件 3.介绍TextView控件 4.键盘的打开和关闭 5.关闭和大开键盘的通知 6.键盘的种类 详情 1.简介 与Label一样,TextField和 ...

  2. PAT T1011 Cut Rectangles

    大模拟题,按要求建立多边形,先定位斜边的位置,再分类讨论~ #include<bits/stdc++.h> using namespace std; ; struct node { dou ...

  3. 【转】spring IOC和AOP的理解

    spring 的优点?1.降低了组件之间的耦合性 ,实现了软件各层之间的解耦 2.可以使用容易提供的众多服务,如事务管理,消息服务等 3.容器提供单例模式支持 4.容器提供了AOP技术,利用它很容易实 ...

  4. 【转】CentOS6开启BBR加速

    1.查看机器内核 BBR 算法需要 Linux 4.9 及以上的内核支持,所以想要使用该方式的需要先升级内核版本. 在 Cent OS 7 上的 Linux 内核是 3.10, 使用 uname -r ...

  5. Java基础 -2.5

    布尔数据boolean类型 布尔类型的取值范围只有两个数据:true false. public class ddd { public static void main(String[] args) ...

  6. 腾讯玄武实验室向(CNVD)提交了一个重大漏洞“BucketShock”

    导读 11 月 21 日,在小米 IoT 安全峰会上,腾讯安全玄武实验室负责人于旸(花名:TK 教主)在演讲中透露,腾讯玄武实验室最近向国家信息安全漏洞共享平台(CNVD)提交了一个重大漏洞“Buck ...

  7. Linux命令:netstat命令

    netstat功能:显示网络连接情况 netstat功能选项 -t:tcp协议的连接 -u:udp协议的链接 -l:监听状态的连接 -a:所有状态的连接 -p:连接相关的进程 -n:数字格式显示 -r ...

  8. 【PAT甲级】1033 To Fill or Not to Fill (25 分)(贪心,思维可以做出简单解)

    题意: 输入四个正数C,DIS,D,N(C<=100,DIS<=50000,D<=20,N<=500),分别代表油箱容积,杭州到目标城市的距离,每升汽油可以行驶的路程,加油站数 ...

  9. SpringMVC配置没有任何问题根据请求却怎么都找不到映射(tomcat所导致的问题)

    本人在做SpringMVC练习的时候,配置文件反复检查了不下十几遍,没有任何问题,然后就招了个之前的项目的源码复制进去,原来的项目没有任何问题,这个项目却怎么都不能跳转路径,然后有找了一个Spring ...

  10. SpringBoot 集成Spring JDBC

    (1)在pom.xml中添加依赖 <!--spring-jdbc的依赖--> <dependency> <groupId>org.springframework.b ...