六大搜索算法

题目描述

使用搜索算法实现罗马尼亚问题的求解
在这里插入图片描述
1:创建搜索树;
2:实现搜索树的宽度优先搜索,深度优先搜索,一致代价搜索,迭代加深的深度优先搜索算法;
3:实现贪婪最佳优先搜索和A*搜索
4:使用编写的搜索算法代码求解罗马尼亚问题;
5:记录各种算法的时间复杂度并绘制直方图

图信息存储

在这里插入图片描述

树的构建以及图的实现代码

搜索树中的树结点定义:

在搜索树中,每一个树结点应该记录的信息包括:
该树结点的代价估计值h(启发式)
该树结点的深度depth(主要用于迭代加深的深度优先搜索算法)
用于取出父节点与子节点的路径值adjEdges
保存该树结点的父亲结点(指针)
保存该树结点的所有孩子结点child
指向父节点preNode
到开始结点的路径距离dist

建边的类:
在这里插入图片描述
结点类:
在这里插入图片描述

无信息搜索策略
package 实验一;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public final class FileUtil
{
     //spec 允许解析的最大行数, spec==null时,解析所有行
    public static String read(final String filePath, final Integer spec)
    {
        File file = new File(filePath);
        // 当文件不存在或者不可读时
        if ((!isFileExists(file)) || (!file.canRead()))
        {
            System.out.println("file [" + filePath + "] is not exist or cannot read!!!");
            return null;
        }

        BufferedReader br = null;
        FileReader fb = null;
        StringBuffer sb = new StringBuffer();
        try
        {
            fb = new FileReader(file);
            br = new BufferedReader(fb);

            String str = null;
            int index = 0;
            while (((spec == null) || index++ < spec) && (str = br.readLine()) != null)
            {
                sb.append(str + "\n");
            }
        }
  
        catch (IOException e)
        {
            e.printStackTrace();
        }
        finally
        {
            closeQuietly(br);
            closeQuietly(fb);
        }

        return sb.toString();
    }

    public static int write(final String filePath, final String content, final boolean append)
    {
        File file = new File(filePath);
        if (content == null)
        {
            System.out.println("file [" + filePath + "] invalid!!!");
            return 0;
        }

        // 当文件存在但不可写时
        if (isFileExists(file) && (!file.canRead()))
        {
            return 0;
        }

        FileWriter fw = null;
        BufferedWriter bw = null;
        try
        {
            if (!isFileExists(file))
            {
                file.createNewFile();
            }

            fw = new FileWriter(file, append);
            bw = new BufferedWriter(fw);

            bw.write(content);
        }
        catch (IOException e)
        {
            e.printStackTrace();
            return 0;
        }
        finally
        {
            closeQuietly(bw);
            closeQuietly(fw);
        }

        return 1;
    }

    private static void closeQuietly(Closeable closeable)
    {
        try
        {
            if (closeable != null)
            {
                closeable.close();
            }
        }
        catch (IOException e)
        {
        }
    }

    private static boolean isFileExists(final File file)
    {
        if (file.exists() && file.isFile())
        {
            return true;
        }

        return false;
    }
}
宽度优先搜索算法BFS

算法原理: 利用队列先进先出的性质来一层层的遍历。从根节点开始一层层拓展它的子节点。拓展层层加深的方式进行搜索。
算法时间空间复杂度分析:时间复杂度:O(b^d ),空间复杂度:O(b^d )

算法步骤:
1)将开始结点压入队列中;
2)取出队列结点当前拓展结点,设置为已访问;
3)判断当前结点是否为目标结点,若是则输出路径搜索结束,否则进行下一步;
4)访问当前结点的所有相邻子节点;
5)判断该该子节点是否被访问过,若已经访问过则回到2),若还未访问过则继续下一步;
6)对于每一个子节点,获取其相关信息值并进行路径更新,将其子节点的父亲结点指向当前结点;
若队列为空还未找到目标结点,返回搜索失败;

package 实验一;
import java.util.LinkedList;
import java.util.Queue;
public class BFS extends BuildGraph {
	public void ShortestPath(){
		ShortestPath(start,end);
	}
	public void ShortestPath(Vertex startNode,Vertex endNode){
		//初始化
		 Queue<Vertex> queue = new LinkedList<>();
		 //startNode.dist=0;
		 queue.offer(startNode);//将源点dist设置为0并入队列
		  while(!queue.isEmpty()){
		     Vertex v = queue.poll();
		     explored.put(v.vertexLabel, 1);
			 if(v.vertexLabel==endNode.vertexLabel){
				 System.out.println("BFS Route:");
				 showPath(v,startNode);
				 return;
			 }
			 for(int i=0;i<v.child.size();i++){//遍历子节点
				 Vertex current=v.child.get(i).endVertex;
				 //System.out.println(explored.get(current.vertexLabel));
				 if(explored.get(current.vertexLabel)==0){
					 current.dist=v.dist+v.adjEdges.get(v.child.get(i));//更新路径值
					 queue.offer(current);
					 current.preNode=v;
				 }
			 }			
		}
		System.out.println("BFS Route:"+" Failure!");
		return;

	}
	
}  
深度优先搜索算法DFS

算法原理: 利用栈后进先出的性质来进行递归加深加回溯的遍历搜索。深度优先搜索每次都直接递进进行搜搜知道搜索到叶子结点才进行回溯搜索。
算法时间空间复杂度分析:时间复杂度:O(b^m )空间复杂度:O(bm)

算法步骤:
1)将开始结点压入栈中;
取出算法时间空间复杂度分析:时间复杂度:O(b^m )空间复杂度:O(bm)
2)队列结点当前拓展结点,设置为已访问;
3)判断当前结点是否为目标结点,若是则输出路径搜索结束,否则进行下一步;
4)访问当前结点的所有相邻子节点;
5)判断该该子节点是否被访问过,若已经访问过则回到2),若还未访问过则继续下一步6);
6)对于每一个子节点,获取其相关信息值并进行路径更新,将其子节点的父亲结点指向当前结点,返回2);
7)若栈为空还未找到目标结点,返回搜索失败;

package 实验一;
import java.util.Stack;
public class DFS extends BuildGraph{
	public void ShortestPath(){
		ShortestPath(start,end);
	}
	public void ShortestPath(Vertex startNode,Vertex endNode){
		//初始化
		 Stack<Vertex> stack= new Stack<>();
		 //startNode.dist=0;
		 stack.push(startNode);
		  while(!stack.isEmpty()){
		     Vertex v = stack.pop();
		     explored.put(v.vertexLabel, 1);
			 if(v.vertexLabel==endNode.vertexLabel){
				 System.out.println("DFS Route:");
				 showPath(v,startNode);
				 return;
			 }
			 for(int i=0;i<v.child.size();i++){
				 Vertex current=v.child.get(i).endVertex;
				 //System.out.println(explored.get(current.vertexLabel));
				 if(explored.get(current.vertexLabel)==0){
					 current.dist=v.dist+v.adjEdges.get(v.child.get(i));
					 stack.push(current);
					 current.preNode=v;
				 }
			 }			
		}
		System.out.println("DFS Route:"+" Failure!");
		return;

	}
}

一致代价搜索算法UCS_BFS

算法原理: 利用优先队列(优先级属性为每一步的路径代价)后进先出的性质来一层层的遍历。一致代价搜索每次都选择下一步路径代价最小的值进行贪心的拓展。这可以通过将边缘结点集组织成按单步代价值排序的优先队列来实现。
算法时间空间复杂度分析:时间复杂度:O(b^(1+[C*/ε] ) ) 空间复杂度:O(b^(1+[C*/ε] ) )

算法步骤:
1)将开始结点压入优先队列中;
2)取出队列结点当前拓展结点,设置为已访问;
3)判断当前结点是否为目标结点,若是则输出路径搜索结束,否则进行下一步;
4)访问当前结点的所有相邻子节点;
5)判断该该子节点是否被访问过,若已经访问过则回到2),若还未访问过则继续下一步6);
6)对于每一个子节点,获取其相关信息值并进行路径更新,将其子节点的父亲结点指向当前结点,返回2);
7)若优先队列为空还未找到目标结点,返回搜索失败;

package 实验一;

import java.util.PriorityQueue;

public class UCS_BFS extends BuildGraph{
	public void ShortestPath(){
		ShortestPath(start,end);
	}
	public void ShortestPath(Vertex startNode,Vertex endNode){
		//初始化
		 PriorityQueue<Vertex> priorityQueue=new PriorityQueue<>();
		 priorityQueue.add(startNode);
		  while(!priorityQueue.isEmpty()){
		     Vertex v = priorityQueue.remove();
		     explored.put(v.vertexLabel, 1);
			 if(v.vertexLabel==endNode.vertexLabel){
				 System.out.println("UCS_BFS Route:");
				 showPath(v,startNode);
				 return;
			 }
			 for(int i=0;i<v.child.size();i++){
				 Vertex current=v.child.get(i).endVertex;
				 //System.out.println(explored.get(current.vertexLabel));
				 if(explored.get(current.vertexLabel)==0){
					 current.dist=v.dist+v.adjEdges.get(v.child.get(i));
					 priorityQueue.add(current);
					 current.preNode=v;
				 }
			 }			
		}
		System.out.println("UCS_BFS Route:"+" Failure!");
		return;

	}
}

迭代加深搜索算法ID_BFS

算法原理: 利用栈后进先出的性质来进行递归迭代加深(加深的深度有限制不再直接一定要搜索到叶节点才能返回)加回溯的遍历搜索。迭代加深的深度优先搜索是一种常用策略,它经常和深度优先搜索结合使用来确定最好的深度界限。
算法时间空间复杂度分析:时间复杂度:O(b^d )

算法步骤:
1)将开始结点压入栈中;
2)取出队列结点当前拓展结点,设置为已访问;
3)判断当前结点是否为目标结点,若是则输出路径搜索结束,否则进行下一步;
4)判断当前结点的深度是已经超过设置的深度限制D,若超过返回2),否则继续下一步5)
5)访问当前结点的所有相邻子节点;
6)判断该该子节点是否被访问过,若已经访问过则回到2),若还未访问过则继续下一步7);
7)对于每一个子节点,获取其相关信息值并进行路径更新,将其子节点的父亲结点指向当前结点,返回2);
8)若优先队列为空还未找到目标结点,返回搜索失败;

package 实验一;

import java.util.Stack;
public class ID_DFS extends BuildGraph{
	public void ShortestPath(int D){
		ShortestPath(start,end,D);
	}
	public void ShortestPath(Vertex startNode,Vertex endNode ,int D){
		//初始化
		 Stack<Vertex> stack= new Stack<>();
		 //startNode.dist=0;
		 stack.push(startNode);//将源点dist设置为0并入队列
		  while(!stack.isEmpty()){
		     Vertex v = stack.pop();
		     if(v.depth>D) continue;//检查一下
		     explored.put(v.vertexLabel, 1);
			 if(v.vertexLabel==endNode.vertexLabel){
				 System.out.println("ID_DFS Route:"+"("+D+")");
				 showPath(v,startNode);
				 return;
			 }
			 for(int i=0;i<v.child.size();i++){
				 Vertex current=v.child.get(i).endVertex;
				 //System.out.println(explored.get(current.vertexLabel));
				 if(explored.get(current.vertexLabel)==0){
					 current.dist=v.dist+v.adjEdges.get(v.child.get(i));
					 current.depth=v.depth+1;
					 stack.push(current);
					 current.preNode=v;
				 }
			 }			
		}
		System.out.println("ID_DFS Route:"+"("+D+")"+" Failure!");
		return;

	}
}

贪婪最佳优先搜索算法Greedy_BFS

算法原理: 利用优先队列(优先级属性每一个结点的估计函数值)后进先出的性质来一层层的遍历。有信息搜索策略使用问题本身的定义之外的特定知识,比无信息的搜索策略更有效的进行问题求解。一般考虑的算法称为最佳优先搜索。最佳优先搜索中,结点是基于评价函数值被选择扩展的。
算法时间空间复杂度分析:时间复杂度:O(b^m ),空间复杂度:O(b^m )
算法步骤:
1)将开始结点压入优先队列中;
2)取出队列结点当前拓展结点,设置为已访问;
3)判断当前结点是否为目标结点,若是则输出路径搜索结束,否则进行下一步;
4)访问当前结点的所有相邻子节点;
5)判断该该子节点是否被访问过,若已经访问过则回到2),若还未访问过则继续下一步6);
6)对于每一个子节点,获取其相关信息值并进行路径更新,将其子节点的父亲结点指向当前结点,返回2);
7)对新的队列进行一次优先级排序;
8)若优先队列为空还未找到目标结点,返回搜索失败;

package 实验一;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;

public class Greedy_BFS extends BuildGraph{
	public void ShortestPath(){
		ShortestPath(start,end);
	}
	public Queue<Vertex> SortTest(Queue<Vertex> queue){
		List<Vertex> list=new ArrayList<>();
		while(!queue.isEmpty()){
			list.add(queue.poll());
		}
		Collections.sort(list, new Comparator<Vertex>(){

			@Override
			public int compare(Vertex o1, Vertex o2) {
				// TODO Auto-generated method stub
				return o1.h<o2.h? -1:(o1.h==o2.h? 0:1);
			}
		});
		int i=0;
		while(i<list.size()){
			//System.out.print(list.get(i).h+" ");
			queue.add(list.get(i));
			i++;
		}
		//System.out.println();
		return queue;
	}
	public void ShortestPath(Vertex startNode,Vertex endNode){
		//初始化
		 Queue<Vertex> queue = new LinkedList<>();
		 //startNode.dist=0;
		 queue.offer(startNode);//将源点dist设置为0并入队列
		  while(!queue.isEmpty()){
		     Vertex v = queue.poll();
		     explored.put(v.vertexLabel, 1);
			 if(v.vertexLabel==endNode.vertexLabel){
				 System.out.println("Greedy_BFS Route:");
				 showPath_H(v,startNode);
				 return;
			 }
			 for(int i=0;i<v.child.size();i++){
				 Vertex current=v.child.get(i).endVertex;
				 //System.out.println(explored.get(current.vertexLabel));
				 if(explored.get(current.vertexLabel)==0){
					 current.dist=v.dist+v.adjEdges.get(v.child.get(i));
					 queue.offer(current);
					 current.preNode=v;
				 }
			 }
			 queue=SortTest(queue);
		}
		System.out.println("Greedy_BFS Route:"+" Failure!");
		return;

	}
}

A*搜索算法AStar_BFS

算法原理: 利用优先队列(优先级属性每一个结点的估计函数值+当前的路径消耗值)后进先出的性质来一层层的遍历。最佳优先搜索的最广为人知的形式称为 A* 搜索。它对结点的评估结合了到达此结点已经花费的代价,和从该结点到目标结点所花代价。由于结合了从开始结点到结点 n 的路径代价和从结点 n 到目标结点的最小代价路径的评估值,因此评估函数值等于经过结点 n 的最小代价解的估计代价。
算法时间空间复杂度分析:时间复杂度:O(b^m ),空间复杂度:O(b^m )

算法步骤:
1)将开始结点压入优先队列中;
2)取出队列结点当前拓展结点,设置为已访问;
3)判断当前结点是否为目标结点,若是则输出路径搜索结束,否则进行下一步;
4)访问当前结点的所有相邻子节点;
5)判断该该子节点是否被访问过,若已经访问过则回到2),若还未访问过则继续下一步6);
6)对于每一个子节点,获取其相关信息值并进行路径更新,将其子节点的父亲结点指向当前结点,返回2);
7)对新的队列进行一次优先级排序;
8)若优先队列为空还未找到目标结点,返回搜索失败;

package 实验一;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class AStar_BFS extends BuildGraph{
	public void ShortestPath(){
		ShortestPath(start,end);
	}
	public Queue<Vertex> SortTest(Queue<Vertex> queue){
		List<Vertex> list=new ArrayList<>();
		while(!queue.isEmpty()){
			list.add(queue.poll());
		}
		Collections.sort(list, new Comparator<Vertex>(){

			@Override
			public int compare(Vertex o1, Vertex o2) {
				// TODO Auto-generated method stub
				return (o1.dist+o1.h)<(o2.dist+o2.h)? -1:((o1.dist+o1.h)==(o2.dist+o2.h)? 0:1);
			}
		});
		int i=0;
		while(i<list.size()){
			//System.out.println(list.get(i).h);
			queue.add(list.get(i));
			i++;
		}
		return queue;
	}
	public void ShortestPath(Vertex startNode,Vertex endNode){
		//初始化
		 Queue<Vertex> queue = new LinkedList<>();
		 //startNode.dist=0;
		 queue.offer(startNode);//将源点dist设置为0并入队列
		  while(!queue.isEmpty()){
		     Vertex v = queue.poll();
		     explored.put(v.vertexLabel, 1);
			 if(v.vertexLabel==endNode.vertexLabel){
				 System.out.println("AStar_BFS Route:");
				 showPath_A(v,startNode);
				 return;
			 }
			 for(int i=0;i<v.child.size();i++){
				 Vertex current=v.child.get(i).endVertex;
				 //System.out.println(explored.get(current.vertexLabel));
				 if(explored.get(current.vertexLabel)==0){
					 current.dist=v.dist+v.adjEdges.get(v.child.get(i));
					 queue.offer(current);
					 current.preNode=v;
				 }
			 }
			 queue=SortTest(queue);
		}
		System.out.println("AStar_BFS Route:"+" Failure!");
		return;

	}
}

完备性讨论

深度优先搜索:在有限状态空间中,深度优先搜索是完备的,因为它至多扩展所有结点,但在树搜索中,则不完备(因为算法可能会陷入死循环);该算法无法避免冗余路径,因此不是最优的;深度优先搜索只需要存储O(bm)个结点,因此空间复杂度为O(bm);该算法可能搜索树上每个结点,因此时间复杂度为O(b^m)。(其中b为分支因子,m为树的最大深度)

广度优先搜索:首先,广度优先搜索是完备的(如果最浅的目标结点处于一个有限深度d,广度优先搜索在扩展完比它浅的所有结点之后最终一定能找到该目标结点;其次,如果路径代价是基于结点深度的非递减函数,则广度优先搜索是最优的;该方法的时间复杂度为O(bd)(假设解的深度为d);该方法的空间复杂度同样为O(bd)(因为有O(b^d)个结点在边缘结点中。

最佳优先搜索:
完备性:贪婪最佳优先搜索是不完备的(有限状态空间的图索索版本是完备的)。A* 搜索是完备的。
最优性:贪婪最优先佳搜索:每次扩展是局部最优的选择,可能不能达到全局最优,所以 不是最优的。A*搜索:如果h(n)是可采纳的,则树搜索版本是 最优的。如果h(n)是⼀致的,则图搜索版本是 最优的。

时间复杂度:
贪婪最佳优先搜索:与深度优先类似,时间复杂度为O(b^m)。
A* 搜索:O(b^d),其中 d=h*-h, 为到⽬标结点的实际代价。
空间复杂度:
贪婪最佳优先搜索:O(b^m)。
A* 搜索:O(b^d),其中 d=h*-h。

贪婪最佳优先搜索:该方法不能保证找到解,因此是不完备的;该方法不一定能找到最优解,因此不是最优的。
一致代价搜索:该方法在存在零代价行动时可能陷入死循环,因此是不完备的,如果每一步的代价都大于等于某个小的正值常数ε,那么一致搜索是完备的;一致代价搜索按照结点的最优路径扩展结点,因此是最优的。
A树搜索:该方法能保证找到解,因此是完备的;因为h(n)是可采纳的,因此A树搜索是最优的。

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值