顶点
class Vertex
{
public char label;
public boolean wasVisited;
public Vertex(char lab)
{
label=lab;
wasVisited=false;
}
}
顶点对象放在数组中然后用下标指示用数组vertexList存储顶点对象。顶点也可以放在链表或其他数据结构中。
图搜索
1深度优先搜索
*规则1 如果可能,访问一个 邻接的未访问顶点标记他并把它放入栈中
*规则2 当不能执行规则1时,如果栈不为空,就从栈中弹出一个节点
*规则3 如果不能执行1,2则完成了整个搜索过程
public void dfs()
{
vertexList[0].wasVisited=true;//将vertexList中的第一个节点标记已访问
visited(vertexList[0]);//访问节点
Stack<Integer> stack=new Stack<>();
while(!stack.isEmpty())// *规则3 如果不能执行1,2则完成了整个搜索过程
{
int v = getUnvisitedVertex(stack.peek());
if(v==-1)
{
stack.pop();// *规则2 当不能执行规则1时,如果栈不为空,就从栈中弹出一个节点
}
else// *规则1 如果可能,访问一个 邻接的未访问顶点标记他并把它放入栈中
{
vertexList[v].wasVisited=true;//将vertexList中的第v个节点标记已访问
visited(vertexList[v]);
stack.push(v);
}
}
for(int j=0;j<vertexList.length;j++)//结束遍历后对还原节点访问标志
{
vertexList[j].wasVisited=false;
}
}
2 广度优先搜索
*规则1 访问下一个未访问的邻接点(如果存在),这个顶点必须是当前顶点的邻接点,并标记他,并把它插入到队列中
*规则2 如果因为未访问顶点而不能执行规则1.那么从队头取一个顶点?(如果存在),并使其成为当前顶点。
*规则3 如果因为队列为空而不能执行规则2,则搜索结束
public void bfs()
{
vertexList[0].wasVisited=true;
visited(vertexList[0]);
int v2;
LinkedList<Integer> queue=new LinkedList<>();
queue.offer(0);
while(!queue.isEmpty())// *规则3 如果因为队列为空而不能执行规则2,则搜索结束
{
int v = queue.poll();//规则2 如果因为未访问顶点而不能执行规则1.那么从队头取一个顶点?(如果存在),并使其成为当前顶点。
while((v2=getUnvisited)!=-1)// *规则1 访问下一个未访问的邻接点(如果存在),这个顶点必须是当前顶点的邻接点,并标记他,并把它插入到队列中
{
vertexList[v2].wasVisited=true;
visit(vertexList[v2]);
queue.offer(v2);
}
}
for(int j=0;j<vertexList.length;j++)//结束遍历后对还原节点访问标志
{
vertexList[j].wasVisited=false;
}
}
(以上是数据结构与算法Java版中的部分代码)
通过一道递归题帮助理解图搜索
leetcode 78
Note:
Elements in a subset must be in non-descending order.
The solution set must not contain duplicate subsets.
For example,
If nums = [1,2,3], a solution is:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
思路分析:题意就是求一个数组集合的所有子集
public static boolean[] v=new boolean[100];//记录该位置的元素是否被选取
public static List<List<Integer>> res=new ArrayList<>();//存储结果
public List<List<Integer>> subsets(int[] nums)
{
robot(0,nums);
return res;
}
private void robot(int idx, int[] nums) {
if(idx>=nums.length)
{
List<Integer> r= new ArrayList<Integer>();
for(int i=0;i<nums.length;i++)
{
if(v[i])
{
r.add(nums[i]);
}
}
}
//有两种决策选取idx元素则v[idx]为true否则为false
v[idx]=true;
robot(idx+1,nums);//选取
v[idx]=false;
robot(idx+1,nums);//不选
}
深度优先应用(栈 递归)
Given an integer n, return all distinct solutions to the n-queens puzzle.
Each solution contains a distinct board configuration of the n-queens' placement, where 'Q'
and '.'
both indicate a queen and an empty space respectively.
For example,
There exist two distinct solutions to the 4-queens puzzle:
[ [".Q..", // Solution 1 "...Q", "Q...", "..Q."], ["..Q.", // Solution 2 "Q...", "...Q", ".Q.."] ]
nxn国际象棋上摆摆n个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行、同一列或同一斜线上,问有多少种摆法。
思路:从0-n列依次摆 在第0列摆皇后可以有0-n行的位置可以选择摆一个皇后后问题就变成从(1-n)列摆皇后用path记录皇后摆的位置
假如皇后摆在第i行位置则path[0]=i,zheng记录有左下到右上可以找出规律 此时 不可用摆的位置为0+i zheng[0+i]=false 即如果列记为idx则
zheng[idx+i]=false 即如果以后皇后的位置如果满足index+i就不能摆同理fan记录有左上到右下规律 idx-i相等就不能摆 因为数组索引不能为负i所以用x-i+n作为索引记录
public static List<List<String>> ress=new ArrayList<>();//记录结果
public static boolean[] hang = new boolean[100];//记录行是否可以摆皇后
public static int[] path = new int[100];//记录皇后摆放的列
public static boolean zheng[] = new boolean[100];//记录左下到右上方向上是否可以摆皇后
public static boolean fan[] = new boolean[100];//记录左上到右下方向是否可以摆皇后
public void dfs(int idx,int n)
{
if(idx>=n)//如果搜索到头就按题目要求输出结果
{
List<String> chess = new ArrayList<String>();
for(int i=0;i<n;i++)
{
String temp="";
for(int j=0;j<n;j++)
{
if(j==path[i])
{
temp+="q";
}
else
{
temp+=".";
}
}
}
ress.add(chess);
}
for(int i=0;i<n;i++)//该皇后初始摆放行位置可以从0到n-1;
{
if(!hang[i]&&!zheng[idx+i]&&!fan[idx-i+n-1]&&!fan[idx-i+n-1])//判断该位置能否摆皇后
{
//能摆
path[idx]=i;//记录对应列皇后摆放的行
hang[i]=true;//之后该行不能摆皇后
zheng[idx+i]=true;//对应斜线不能摆皇后
fan[idx-i+n-1]=true;//对应斜线不能摆皇后
dfs(idx+1,n);//深度搜索
hang[i]=false;//这个位置摆完后还原现场
zheng[idx+i]=false;
fan[idx-i+n-1]=false;
}
}
参考资料:https://www.bilibili.com/video/av19345520/
数据结构与算法(Java版)