[算法&数据结构]深度优先搜索(Depth First Search)
深度优先 搜索(DFS, Depth First Search)
从一个顶点v出发,首先将v标记为已遍历的顶点,然后选择一个邻接于v的尚未遍历的顶点u,如果u不存在,本次搜素终止。如果u存在,那么从u又开始一次DFS。如此循环直到不存在这样的顶点。
算法核心代码如下:
void dfs(int step){
// 判断边界是否成立
// 尝试每一种可能
for(int i=0;i<n;i++){
//
// 继续执行下一步
dfs(step + 1)
// 取消已被使用标记
}
}
全排列
下面我们利用一个简单基本案例来学习全排列
A 手中有3张牌,分别是1,2,3 那么请问这三张牌能组成多少位不重复三位数字?
DFS算法分析
首先我们假设有三个桶,桶里面可以存放牌,那么我们来到第一个桶,我们手里有3张牌,按照顺序,我我们可以放入1,然后完成当前操作,标记第一张牌已经被使用,来到第二个桶里面,开始尝试,尝试放入第一张牌,此时1已经被使用了,所以我们尝试2,那么第二个桶也已经被放入数据了,2被标记为使用,接着来到第3个桶,此时,我们尝试放入1,1被使用,无法放入,尝试放入2,2也被使用,尝试放入3,OK,3 放入成功,此时三个桶放入完成,完成一次全排列,即
1,2,3好,回到第3个桶,的时候我们没有其他牌可以放了,1,2已经被使用,3正在桶里呢,我们继续回到2号桶,同时标记3号牌未被使用,回到2号桶,此时2号桶已经尝试了1,2 那么我们继续尝试3号牌,3号牌刚刚被收回,可以放入,此时2号桶放入3号牌,继续第3个桶,同样的依次尝试所有的可能,1号牌不行,2号可以,此时完成了全排列
1,3,2继续,回到3号桶,没有可用的了,回到2号桶,3号牌也被用了,也没有了,继续回到1号桶,此时1号桶放入的是1,那么我们收回,继续放入2号牌,来到2号桶,此时手中有1,3号,我们放入1,来到3号桶,1,2已被使用,我们只能放入3,又完成一次全排列
2,1,3依次类推....
那么我们看下代码,这里提供了C语言版本的和Java语言版本的,原理是一样的
C语言版本
代码
#include <stdio.h>
// 定义扑克牌长度 3
#define PLAY_CARD_SIZE 3
// 定义数组
int numbers[] = {1,2,3};
// 标记数字是否被使用
int status[] = {0, 0, 0};
// 定义位置
int location[] = {0,0,0};
/**
* 声明dfs方法
* @param step 当然位置
*/
void dfs(int step);
int main(){
dfs(0);
return 0;
}
void dfs(int step){
// 判断搜索临界条件
if (step == 3){
for (int i = 0; i < 3; ++i) {
printf("%d,",location[i]);
}
printf("\n");
// 完成此次全排列
return;
}
for (int j = 0; j < 3; ++j) {
if(status[j] == 0){
location[step] = numbers[j];
status[j] = 1;
dfs(step + 1);
status[j] = 0;
}
}
}
输出结果
1,2,3,
1,3,2,
2,1,3,
2,3,1,
3,1,2,
3,2,1,
Java语言版本
代码
import java.util.ArrayList;
import java.util.List;
/**
* 深度优先搜寻算法
*/
public class DFS2 {
// 定义扑克牌的数量
static int PLAY_CARD_SIZE = 3;
// 存放扑克牌的集合
static List<PlayCard> playCards = new ArrayList<>();
// 存放扑克牌的位置
static String[] numbers = new String[PLAY_CARD_SIZE];
// 初始化扑克牌 1,2,3
static {
for (int i = 0; i < PLAY_CARD_SIZE; i++) {
playCards.add(new PlayCard(String.valueOf(i + 1), false));
}
}
// 程序入口
public static void main(String[] args) {
dfs(0);
}
private static void dfs(int startIndex) {
if (startIndex == playCards.size()){
for (int i = 0;i<numbers.length;i++){
System.out.print(numbers[i]+",");
}
System.out.println("");
System.out.println("-------------");
return;
}
for (int i = 0; i < playCards.size(); i++) {
if(!playCards.get(i).used){
playCards.get(i).used = true;
numbers[startIndex] = playCards.get(i).code;
dfs(startIndex + 1);
playCards.get(i).used = false;
}
}
}
// 封装的实体类,为了方便定义为public
static class PlayCard {
public PlayCard(String code, boolean used) {
this.code = code;
this.used = used;
}
// 扑克牌编号 ,即1,2,3
public String code;
// 扑克牌是否已被使用
public boolean used;
}
}
输出结果
1,2,3,
1,3,2,
2,1,3,
2,3,1,
3,1,2,
3,2,1,
等式求解
想起来以前有个题目,计算恒等式,题目是a[0] * 100 + a[1] * 10 + a[2] +a[3] * 100 + a[4] * 10 + a[5] == a[6] * 100 + a[7] * 10 +a[8] 问a的组合有多少种?
Ps:a是0-9组成的,不可重复
下面我们有DFS来实现这个题目,记得在以前,肯定是写九个for循环嵌套,现在我们尝试利用上面的全排列来判断,此时的输出(边界条件)修改为上面的等式,代码不做过多的阐述了。没有了9层循环的样子。。。。
代码
public class DFS3 {
static int PLAY_CARD_SIZE = 9;
static List<Number> playCards = new ArrayList<>();
static int[] a = new int[PLAY_CARD_SIZE];
static {
for (int i = 1; i <= PLAY_CARD_SIZE; i++) {
playCards.add(new Number(i, false));
}
}
public static void main(String[] args) {
dfs(0);
}
private static void dfs(int startIndex) {
if (startIndex == playCards.size()) {
if (checkNumber()) {
for (int i=0;i<PLAY_CARD_SIZE;i++){
System.out.print(a[i]+",");
}
System.out.println();
}
return;
}
for (int i = 0; i < playCards.size(); i++) {
if (!playCards.get(i).used) {
playCards.get(i).used = true;
a[startIndex] = playCards.get(i).code;
dfs(startIndex + 1);
playCards.get(i).used = false;
}
}
}
/**
* 判断搜索边界
*
* @return
*/
private static boolean checkNumber() {
if(a[0] * 100 + a[1] * 10 + a[2] +a[3] * 100 + a[4] * 10 + a[5] == a[6] * 100 + a[7] * 10 +a[8])
return true;
return false;
}
static class Number {
public Number(int code, boolean used) {
this.code = code;
this.used = used;
}
public int code;
public boolean used;
}
}
输出结构
输出结构也是蛮多的,这里摘录几个,可以自己测试下
1,2,4,6,5,9,7,8,3,
...
2,1,4,5,6,9,7,8,3,
...
3,1,4,6,5,8,9,7,2,
...
4,1,5,2,7,8,6,9,3,
...
5,9,6,2,4,1,8,3,7,
...
6,9,5,1,4,2,8,3,7,
...
7,8,4,1,5,2,9,3,6,
总结
DFS 是一个非常有意思的算法,在图解中和BFS也属于非常重要的算法了,多多理解,多多学习
[算法&数据结构]深度优先搜索(Depth First Search)的更多相关文章
- [算法入门]——深度优先搜索(DFS)
深度优先搜索(DFS) 深度优先搜索叫DFS(Depth First Search).OK,那么什么是深度优先搜索呢?_? 样例: 举个例子,你在一个方格网络中,可以简单理解为我们的地图,要从A点到B ...
- 回溯算法 DFS深度优先搜索 (递归与非递归实现)
回溯法是一种选优搜索法(试探法),被称为通用的解题方法,这种方法适用于解一些组合数相当大的问题.通过剪枝(约束+限界)可以大幅减少解决问题的计算量(搜索量). 基本思想 将n元问题P的状态空间E表示成 ...
- 算法总结—深度优先搜索DFS
深度优先搜索(DFS) 往往利用递归函数实现(隐式地使用栈). 深度优先从最开始的状态出发,遍历所有可以到达的状态.由此可以对所有的状态进行操作,或列举出所有的状态. 1.poj2386 Lake C ...
- javascript实现的图数据结构的广度优先 搜索(Breadth-First Search,BFS)和深度优先搜索(Depth-First Search,DFS)
最后一例,搞得快.三天之内走了一次.. 下一步,面象对像的javascript编程. function Dictionary(){ var items = {}; this.has = functio ...
- 【算法】深度优先搜索(dfs)
突然发现机房里有很多人不会暴搜(dfs),所以写一篇他们能听得懂的博客(大概?) PS:万能 yuechi ---- 大法师怎么能不会呢?! 若有错误,请 dalao 指出. 前置 我知道即使很多人都 ...
- [算法专题] 深度优先搜索&回溯剪枝
1. Palindrome Partitioning https://leetcode.com/problems/palindrome-partitioning/ Given a string s, ...
- 【算法】深度优先搜索(DFS)III
1. DFS生成排列 众所周知,1,2…n的排列一共有n!个,因此生成全排列至少需要n!的时间复杂度.如果用循环来生成排列,当n稍大时,内外循环会非常之多.可以用DFS模拟解决,生成0 … n-1的排 ...
- 算法与数据结构基础 - 深度优先搜索(DFS)
DFS基础 深度优先搜索(Depth First Search)是一种搜索思路,相比广度优先搜索(BFS),DFS对每一个分枝路径深入到不能再深入为止,其应用于树/图的遍历.嵌套关系处理.回溯等,可以 ...
- 常用算法2 - 广度优先搜索 & 深度优先搜索 (python实现)
1. 图 定义:图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合. 简单点的说:图由节点和边组成.一 ...
随机推荐
- 我们为什么要搞长沙.NET技术社区(二)
我们为什么要搞长沙.NET技术社区(二) 某种意义上讲,长沙和中国大部分内地城市一样,都是互联网时代的灯下黑.没有真正意义上的互联网公司,例如最近发布的中国互联网企业一百强中没有一家湖南或者长沙的公司 ...
- 让 .NET 更方便的导入导出 Excel
让 .Net 更方便的导入导出Excel Intro 因为前一段时间需要处理一些 excel 数据,主要是导入/导出操作,将 Excel 数据转化为对象再用程序进行处理和分析,没有找到比较满意的库,于 ...
- 将个人博客从GitHub迁移至阿里云服务器过程总结
让我们先回顾下前两篇博客: 程序员如何从0到1搭建自己的技术博客 在个人博客中优雅的使用Gitalk评论插件 通过前两篇博客,我们了解了如何快速的从0到1搭建一个个人博客并使用了Gitalk评论插件, ...
- 动态路由协议(RIP)
虽然静态路由在某些时刻很有用,但是必须手工配置每条路由条目,对于大中型的网络或拓补经常发生变化的清空,配置和维护静态路由的工作量就变得非常繁重,而且不小心还容易出错,因此就需要一种不需要手工配置的路由 ...
- Sharepoint 2013内容查询Web部件自定义显示样式(实战)
分享人:广州华软 星尘 一. 前言 在进行Sharepoint开发时,经常会遇到内容展示个性化需求的问题,当然如果通过自定义开发控件对于内容展示的需求基本都可以很好的解决,但自定义开发也有不好的地方, ...
- Spring Aop源码分析
最近看了SpringAop的源码实现 大概记录一下aop的源码流程 创建一个最简单的一个测试类 package com.zcg.learn.Test; import org.aopalliance. ...
- Linux 用户及权限详解
Linux 用户及权限详解 用户 , 组 ,权限 安全上下文(secure context): 权限: r,w,x 文件: r : 可读,可以使用类似cat 等命令查看文件内容. w : 可写,可以编 ...
- JAVA_OPTS设置
AVA_OPTS ,顾名思义,是用来设置JVM相关运行参数的变量. JVM:JAVA_OPTS="-server -Xms2048m -Xmx2048m -Xss512k" -se ...
- Arduino入门笔记(5):1602液晶实验(实现时钟)
转载请注明:@小五义 http://www.cnblogs.com/xiaowuyi 欢迎加入讨论群 64770604 一.本次实验所需器材 1.Arduino板 https://item.taoba ...
- 零基础java的福音!史上最全最精简的学习路线图!
这是一个java系统学习路线,从零基础到项目框架开发,每一个阶段里面内容都标记的很清楚,如果你现在也在学习java,你可以跟着这个系统学习路线学,学完自己可以独立的完成项目框架开发,二线城市拿个7k+ ...