对A*算法的路径进行优化

3 篇文章 0 订阅
3 篇文章 0 订阅


如果你没有看过上一个文章的代码,请到这个传送门:A*算法的实现

注:优化最终路径,必然会对算法耗时造成一定的影响。


针对上一篇文章,我提到的设想,对路径进行分段处理,每一小段再进行一次A*,那么我们需要新增一个SearchEx接口,并对原本的Search接口进行修改。

Search新增一个参数,用来代替原本的BREAK_GAP常量宏,在Search中,清理内存时,将地图数据恢复。

修改后的源代码如下:


bool CAStar::Search(int X, int Y, std::list<POINT> &lResult, double dbGapBreak)
{
	if(X < 0 || Y < 0
		|| X > m_dwMapWidth || Y > m_dwMapWidth ||
		m_dwDestinationX < 0 || m_dwDestinationX < 0 ||
		m_dwDestinationX > m_dwMapWidth || m_dwDestinationY > m_dwMapHeight)
	{
		//_outf("坐标或地图参数错误!");
		return false;
	}
	
	LPAPOINT p = new APOINT;
	p->x = X;
	p->y = Y;
	p->parent = NULL;
	p->dbGap = _p2g(X, Y, m_dwDestinationX, m_dwDestinationY);
	m_lOpen.push_front(p);//起始节点加入到开启列表
	m_lSafe.push_back(p);//加入到公共容器,任何新分配的节点,都要加入到这里,便于算法执行完后清理
	
	std::list<LPAPOINT>::iterator it;
	DWORD dwTime = clock();
	while(!m_lOpen.empty())
	{
		//这里就是反复遍历开启列表选择距离最小的节点
		it = GetMingapNode();
		if((*it)->dbGap <= dbGapBreak)
			break;
		p = *it;
		GenerateSuccessors(it);
	}
	
	if(!m_lOpen.empty())
	{
		//如果列表不为空,从最后一个节点开始拷贝路径到返回值中
		//_outf("最终寻路到:%X, %X", p->x, p->y);
		POINT point;
		while(p)
		{
			point.x = p->x;
			point.y = p->y;
			lResult.push_front(point);
			p = p->parent;
		}
	}
	
	for(it = m_lSafe.begin(); it != m_lSafe.end(); ++it)
	{
		//清理内存
		if(*it != NULL)
		{
			m_pMap[(*it)->y][(*it)->x] = 1;//会被添加到m_lSafe的节点,一定是最初为1的节点,所以可以在这里恢复地图数据
			delete (*it);
			*it = NULL;
		}
	}
	
	m_lSafe.clear();//清空容器
	
	//_outf("耗时:%d 毫秒", clock() - dwTime);
	
	if(m_lOpen.empty())
	{
		//_outf("寻路失败");
		return false;
	}
	
	m_lOpen.clear();//清空开启列表
	//_outf("寻路成功,节点数:%d", lResult.size());
	return true;
}

新增的SearchEx源代码如下:

nBeginSift 参数为循环初始值,nEndSift为循环结束值,其实就是一个for循环的起始值与结束值。

这个循环的引用计数,最终会被 乘于 10 来作为距离分段选择路径进行路线优化

nBeginSift 与 nEndSift的间距越大,并不表示最终路径就越好,最终优化出来的路径,还是会和地形有关。

其实最好路径优化算法是按照角度的变化来选择路径优化,但是预计开销会比较大,有了这个优化方式作为基础,你可以自己去写根据角度变化来优化的算法。

bool CAStar::SearchEx(int X, int Y, std::list<POINT> &lResult, double dbGapBreak, int nBeginSift, int nEndSift)
{
	DWORD dwTime = clock();
	if(!Search(X, Y, lResult, dbGapBreak))
		return false;
	std::list<POINT>::iterator it = lResult.begin();
	std::list<POINT>::iterator it2 = it;
	
	std::list<POINT> l2;
	for(int i = nBeginSift; i < nEndSift; i++)
	{
		it = lResult.begin();
		it2 = it;
		for(;it != lResult.end(); ++it)
		{
			if(_p2g(it2->x, it2->y, it->x, it->y) > (double)(i * 10))
			{
				SetDestinationPos(it->x, it->y);
				l2.clear();
				if(Search(it2->x, it2->y, l2, 0.0))
				{
					it = lResult.erase(it2, it);
					lResult.insert(it, (l2.begin()), (l2.end()));
				}
				it2 = it;
			}
		}
	}
	
	_outf("耗时:%d 毫秒", clock() - dwTime);
	return true;
}



以下为 nBeginSift = 6      nEndSift = 15 的优化结果。

测试时间结果:

[3368] 耗时:47 毫秒



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值