算法实现系列第四章.启发式搜索_A*搜索

本文探讨了启发式搜索和A*搜索的概念,通过实例代码展示了如何实现这两种算法,重点解释了它们的区别及应用场景。

..很郁闷启发式搜索和A*搜索.自己对照文档写了下..发现和之前学的有出入...算了先写这个吧..等我回去翻翻笔记...如果有问题再来补充..明白的同学可以直接拍砖...

 

下面我们对这个图进行..最短路径的查

 

package algorithm;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

/**
 * A* 搜索见得的java例子,也是启发式搜索.和我映像里有点出入...
 * 
 * @author ansj
 * 
 */
public class HeuristicSearching {
	public static void main(String[] args) {
		// 设置节点
		Node v1 = new Node("v1", 0);
		Node v2 = new Node("v2");
		Node v3 = new Node("v3");
		Node v4 = new Node("v4");
		Node v5 = new Node("v5");
		Node v6 = new Node("v6");

		// 设置关联关系
		v1.hm.put(v2, 40);
		v1.hm.put(v3, 30);
		v1.hm.put(v4, 20);
		v1.hm.put(v5, 10);

		v2.hm.put(v6, 10);

		v3.hm.put(v2, 2);
		v3.hm.put(v6, 15);

		v4.hm.put(v2, 15);
		v4.hm.put(v3, 6);

		v5.hm.put(v4, 15);

		openNode(v1);

		System.out.println(v1);
		System.out.println(v2);
		System.out.println(v3);
		System.out.println(v4);
		System.out.println(v5);
		System.out.println(v6);

	}

	private static List<Node> open = new ArrayList<Node>();

	private static void openNode(Node from) {
		// TODO Auto-generated method stub

		Node temp = null;
		Integer pathWeight = null;
		if (from == null) {
			return;
		}
		for (Entry<Node, Integer> entry : from.hm.entrySet()) {
			temp = entry.getKey();
			// 如果此节点已经关闭.则忽略
			if (temp.close) {
				continue;
			}
			pathWeight = entry.getValue();
			if (temp.min > from.min + pathWeight) {
				temp.min = pathWeight + from.min;
			}
			open.add(temp);
		}
		// 每次关闭掉路径最短的节点
		Node nodeMin = findAndRemoveMinNode();
		if(nodeMin!=null){
			openNode(nodeMin);
		}

	}

	private static Node findAndRemoveMinNode() {
		// TODO Auto-generated method stub
		Node node = null;
		for (int i = 0; i < open.size(); i++) {
			if (node == null) {
				node = open.get(i);
			} else if (open.get(i).min < node.min) {
				node = open.get(i);
			}
		}
		open.remove(node) ;
		return node;
	}

	// 节点对象
	private static class Node {
		// 节点名称
		private String name;
		private boolean close = false;
		// 最短的路径
		private int min = Integer.MAX_VALUE;
		// 可以到达的节点及其长度
		private HashMap<Node, Integer> hm = new HashMap<Node, Integer>();

		private Node(String name) {
			this.name = name;
		}

		private Node(String name, Integer pathWeight) {
			this.name = name;
			this.min = pathWeight;
		}

		public String toString() {
			return this.name + ":" + this.min;
		}
	}
}
 

 

 


 

 

 

 

<think> 我们正在讨论Scrapy框架中的扩展中间件。根据之前的对话,用户已经了解Scrapy有四种核心中间件类型:爬虫中间件、下载器中间件、扩展中间件(Extensions)和项目管道(Item Pipelines)。现在用户特别询问关于自定义扩展中间件的方法和示例。 扩展中间件(Extensions)是通过Scrapy的信号系统(signals)来工作的,它们可以在Scrapy运行的各个阶段插入自定义逻辑。创建自定义扩展需要以下步骤: 1. **定义扩展类**:创建一个类,并实现必要的方法。 2. **连接到信号**:在类中连接到Scrapy的各种信号(例如`spider_opened`, `spider_closed`等)。 3. **注册扩展**:在Scrapy的配置文件中启用扩展。 下面是一个自定义扩展的示例,该扩展在爬虫启动和关闭时打印日志,并在爬虫运行期间定期打印统计信息(模拟定时监控功能): ```python import logging from scrapy import signals from scrapy.exceptions import NotConfigured logger = logging.getLogger(__name__) class MyExtension: """自定义扩展,用于监控爬虫运行状态""" def __init__(self, stats, interval=60.0): # 初始化统计信息和间隔时间 self.stats = stats self.interval = interval # 定时任务句柄 self.task = None @classmethod def from_crawler(cls, crawler): # 获取配置中的间隔时间,如果没有配置则使用默认值60秒 interval = crawler.settings.getfloat('MYEXT_INTERVAL', 60.0) # 如果扩展未启用,则抛出异常 if not crawler.settings.getbool('MYEXT_ENABLED', True): raise NotConfigured # 创建扩展实例 ext = cls(crawler.stats, interval) # 连接信号 crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened) crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed) return ext def spider_opened(self, spider): """爬虫启动时执行""" logger.info(f"Spider opened: {spider.name}") # 启动定时任务 from twisted.internet import task self.task = task.LoopingCall(self.log_stats, spider) self.task.start(self.interval) def log_stats(self, spider): """定时记录统计信息""" stats = self.stats.get_stats() logger.info(f"Spider {spider.name} stats: {stats}") def spider_closed(self, spider): """爬虫关闭时执行""" logger.info(f"Spider closed: {spider.name}") # 停止定时任务 if self.task and self.task.running: self.task.stop() ``` 在项目的`settings.py`中启用该扩展: ```python EXTENSIONS = { 'myproject.extensions.MyExtension': 500, # 优先级设为500 } MYEXT_ENABLED = True # 默认已启用,此项可省略 MYEXT_INTERVAL = 30.0 # 设置间隔时间为30秒 ``` 这个扩展做了以下事情: - 在爬虫启动时开始一个定时任务,每隔一段时间(通过`MYEXT_INTERVAL`设置)打印一次统计信息。 - 在爬虫关闭时停止定时任务。 注意: - 扩展类必须实现`from_crawler`类方法,用于创建扩展实例并连接信号。 - 使用`crawler.signals.connect`来连接信号处理函数。 - 扩展的执行顺序由`EXTENSIONS`设置中的优先级数值决定(数值越小越先执行)。 通过这种方式,我们可以轻松地扩展Scrapy的功能,例如实现监控、报警、资源清理等。 §§相关问题§§ 1. Scrapy扩展中间件如何接入外部监控系统(如Prometheus)? 2. 如何在Scrapy扩展中处理异常并发送警报? 3. Scrapy的信号系统支持哪些关键生命周期事件? </think> ### Scrapy自定义扩展中间件方法与示例 在Scrapy框架中,自定义扩展中间件(Extensions)是通过订阅**事件系统(signals)**实现的全局功能增强组件。它不属于请求/响应流水线,但能访问Scrapy核心对象(如crawler、stats),常用于监控、通知等场景。 #### 创建方法 1. **定义扩展类** 需实现`from_crawler`类方法和事件处理方法: ```python from scrapy import signals class MyExtension: def __init__(self, crawler): self.crawler = crawler @classmethod def from_crawler(cls, crawler): ext = cls(crawler) # 订阅事件 crawler.signals.connect(ext.spider_opened, signal=signals.spider_opened) crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed) return ext def spider_opened(self, spider): print(f"爬虫启动: {spider.name}") def spider_closed(self, spider, reason): print(f"爬虫关闭: {spider.name}, 原因: {reason}") ``` 2. **注册扩展** 在`settings.py`中激活: ```python EXTENSIONS = { 'myproject.extensions.MyExtension': 500, # 数值表示优先级 } ``` #### 实用示例 **定时性能监控扩展** 每60秒记录爬虫状态: ```python from twisted.internet import task class StatsMonitorExtension: def __init__(self, crawler): self.stats = crawler.stats self.interval = 60 # 秒 self.task = None @classmethod def from_crawler(cls, crawler): ext = cls(crawler) crawler.signals.connect(ext.spider_opened, signals.spider_opened) crawler.signals.connect(ext.spider_closed, signals.spider_closed) return ext def spider_opened(self, spider): self.task = task.LoopingCall(self.log_stats, spider) self.task.start(self.interval) def log_stats(self, spider): stats_data = { "pages": self.stats.get_value('response_received_count', 0), "items": self.stats.get_value('item_scraped_count', 0), "errors": self.stats.get_value('log_count/ERROR', 0) } print(f"[监控] {spider.name}状态: {stats_data}") def spider_closed(self, spider, reason): if self.task and self.task.running: self.task.stop() ``` #### 关键特性 1. **事件订阅机制**: - `engine_started`/`engine_stopped`:引擎启停 - `spider_opened`/`spider_closed`:爬虫启停 - `item_scraped`:数据项抓取成功 - `item_dropped`:数据项被丢弃[^3] 2. **核心对象访问**: ```python def from_crawler(cls, crawler): # 获取配置 interval = crawler.settings.getfloat('STATS_INTERVAL', 60) # 访问统计收集器 stats = crawler.stats # 访问爬虫配置 spider_settings = crawler.spider.settings ``` 3. **执行优先级控制** 通过`EXTENSIONS`字典的值调整顺序(值越小优先级越高)[^1] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值