A*(Astar)搜索算法的实现(C语言)

A*(A-Star)算法是一种在静态路网中求解最短路径的高效方法。本文介绍了算法的起源、详细描述,包括等式表示和伪代码,并重点讨论了算法实现的关键点,如维护open表(使用大根堆)和估算函数的选择,如欧氏距离、曼哈顿距离和切比雪夫距离。此外,还展示了A*算法在最短路径寻优和8数码问题中的具体应用。
摘要由CSDN通过智能技术生成

     A*(A-Star)算法是一种静态路网中求解最短路最有效的方法,是启发搜索中的一种。

1.起源

名字创意来源于第一届百度之星比赛决赛中有题目是一道经典的8数码题目,解这道题,冠军ACRush使用了A*算法(Astar)。Astar又包含了“百度之星”的含义。

2.算法的描述

2.1 该算法可以用如下等式表示:

f(n) = g(n) + h(n)
其中
f(n) 是从初始点经由节点n到目标点的移动耗费。
        g(n) 是在状态空间中从起点到n节点的实际耗费。
        h(n) 从网格上那个方格移动到终点的预估移动耗费。这经常被称为启发式的,这样叫的原因是因为它只是个猜测。我们没办法事先知道路径的长度,因为路上可能存在各种障碍(墙,水,等等)。

2.2 该算法的伪代码描述如下:

创建两个表,OPEN表保存所有已生成而未考察的节点,CLOSED表中记录已访问过的节点; 
算起点的估价值;
将起点放入OPEN表;
while(OPEN!=NULL) 
{ 
	从OPEN表中取估价值f最小的节点n; 
	if(n节点==目标节点)
	{ 
		break; 
	}
	 
	for(当前节点n 的每个子节点X) 
	{
		算X的估价值; 
		if(X in OPEN)
		{ 
			if( X的估价值小于OPEN表的估价值 )
			{ 
				把n设置为X的父亲; 
				更新OPEN表中的估价值; /*取最小路径的估价值*/
			}
		}
	
		if(X in CLOSE)
		{
			continue;
		}
	
		if(X not in both)
		{
			把n设置为X的父亲;
			求X的估价值; 
			并将X插入OPEN表中; 
		}
	}/* end for */

	将n节点插入CLOSE表中; 
	按照估价值将OPEN表中的节点排序; /*实际上是比较OPEN表内节点f的大小,从最小路径的节点向下进行。*/
}/* end while(OPEN!=NULL) */

保存路径,即 从终点开始,每个节点沿着父节点移动直至起点,这就是你的路径;

 

3.算法实现的几个关键点

3.1 维护open表

算法中从open表中需要选择估算值最小的节点进行,相当于open表是一个有序序列。对于open表的实现可以用完全排序链表。但是对于节点数量大的网络中有一个更优的选择,那就是二叉堆。
二叉堆是一种特殊的堆,二叉堆是完全二元树或者是近似完全二元树。二叉堆有两种:最大堆和最小堆。最大堆:父结点的键值总是大于或等于任何一个子节点的键值;最小堆:父结点的键值总是小于或等于任何一个子节点的键值。 在这里用到是最小二叉堆。二叉堆的介绍也可以参考:  Using Binary Heaps in A* Pathfinding
二叉堆实现代码如下:
bheap.h
/*
*	author:	Atom
* date:		2012/12/02
* file:		bheap.h
*/
#ifndef _BHEAP_H
#define _BHEAP_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define DEF_SIZE			16				/* 默认heap大小 */
#define INC_RATE			1.5				/* heap自动增长速度 */

enum Bheap_type
{
	BHEAP_TYPE_BIG,								/* 大根二叉堆 */
	BHEAP_TYPE_SMALL							/* 小根二叉堆 */
};

struct Bheap_node
{
	void* value;
};

struct Bheap
{
	struct Bheap_node**	head;
	size_t							size;				/* 当前元素个数 */
	size_t							max_size;		/* 堆容量 */
	enum Bheap_type			Btype;			/* 堆类型 */
};

/*		condition		result
*			n1 > n2				1
*			n1 == n2			0
*			n1 < n2				-1
*/
typedef int (*Bheap_compare_t)(struct Bheap_node* n1, struct Bheap_node* n2);

/*		condition		result
*			n1 == n2			1
*			n1 != n2			0
*/
typedef int (*Bheap_equal_t)(struct Bheap_node* n1, struct Bheap_node* n2);

/* free 节点,包括bn->value */
typedef void (*Bheap_free_node_t)(struct Bheap_node* bn);

/*根据 Bheap_type 创建二叉堆,如果未指定堆大小或指定的堆大小 小于等于 1,则初始化堆容量为16*/
static struct Bheap* Bheap_create(size_t size, enum Bheap_type Btype)
{
	struct Bheap* heap = NULL;

	if (NULL == (heap = (struct Bheap*)malloc(sizeof(struct Bheap))))
	{
		fprintf(stderr, "Bheap malloc error!\n");
		return (NULL);
	}
	memset(heap, 0x00, sizeof(struct Bheap));
		
	if (size > 1)
	{
		heap->head = (struct Bheap_node**)malloc(sizeof(struct Bheap_node*) * (size + 1));
		if (NULL == heap->head)
		{
			fprintf(stderr, "Bheap.head malloc error!\n");
			return (NULL);
		}
		heap->max_size = size;
	}
	else
	{
		heap->head = (struct Bheap_node**)malloc(sizeof(struct Bheap_node*) * ((DEF_SIZE) + 1));
		if (NULL == heap->head)
		{
			fprintf(stderr, "Bheap.head malloc error!\n");
			return (NULL);
		}
		heap->max_size = DEF_SIZE;
	}
	
	heap->Btype = Btype;
	
	return (heap);
}

/* 初始化二叉堆 */
static void Bheap_init(struct Bheap* heap)
{
	if (NULL == heap)
		return;
	
	memset(heap->head, 0x00, (sizeof(struct Bheap_node*) * (heap->size + 1)));
	
	heap->size = 0;
}

/* 增长二叉堆容量 */
static size_t __inc_Bheap_size(struct Bheap* heap)
{
	if (NULL == heap)
		return (-1);

	heap->max_size = (size_t)((INC_RATE) * heap->max_size);
	
	heap->head = (struct Bheap_node**)realloc(heap->head, sizeof(struct Bheap_node*) * (heap->max_size + 1));
	
	if (NULL == heap->head)
		return (-1);

	return (0);
}

/* 交换节点内容 */
static void __swap_Bheap_node(struct Bheap_node** n1, struct Bheap_node** n2)
{
	struct Bheap_node* temp;
	
	if (*n1 == *n2)
		return;

	temp = *n1;
	*n1 = *n2;
	*n2 = temp;
}

/* 入堆操作 */
static int Bheap_push(struct Bheap* heap, struct Bheap_node* node, Bheap_compare_t comp)
{
	int n = 0, c;
	if ((NULL == heap) || (NULL == node) || (NULL == comp))
		return	(-1);
	
	if ((heap->size == heap->max_size) && (-1 == __inc_Bheap_size(heap)))
	{
		fprintf(stderr, "increase heap size error!\n");
		return (-1);
	}
	heap->size++;
	n = heap->size;
	heap->head[heap->size] = node;
	
	/* 冗余代码,减少循环中的判断 */
	if (BHEAP_TYPE_SMALL == heap->Btype)
	{
		/* 小根堆 */
		for ( ; ; )
		{
			if (1 == n)
				break;
			c = n;
			n = n>>1;
			if (1 == comp(heap->head[n], heap->head[c]))
				__swap_Bheap_node(&(heap->head[n]), &(heap->head[c]));
			else
				break;
		}
	}
	else
	{
		/* 大根堆 */
		for ( ; ; )
		{
			if (1 == n)
				break;
			c = n;
			n = n>>1;
			if (-1 == comp(heap->head[n], heap->head[c]))
				__swap_Bheap_node(&(heap->head[n]), &(heap->head[c]));
			else
				break;
		}
	}
	
	return (0);
}

/* 移除节点 */
static struct Bheap_node* Bheap_remove(struct Bheap* heap, size_t idx, Bheap_compare_t comp)
{
	int n = 0, c;
	if ((NULL == heap) || (idx < 1) || (idx > heap->size) || (NULL == comp))
		return (NULL);
		__swap_Bheap_node(&(heap->head[idx]), &(heap->head[heap->size]));
	
	n = idx;	
	heap->size--;
	
	/* 冗余代码,减少循环中的判断 */
	if (BHEAP_TYPE_SMALL == heap->Btype)
	{
		/* 小根堆 */
		for ( ; ; )
		{
			c = n;
			n = n<<1;
			if (n > heap->size)
				break;
			
			if ((n + 1) > heap->size)
			{
				if (1 == comp(heap->head[c], heap->head[n]))
					__swap_Bheap_node(&(heap->head[c]), &(heap->head[n]));
				else
					break;
			}
			else
			{
				if (1 == comp(heap->head[n], heap->head[n + 1]))
				{
					if (1 == comp(heap->head[c], heap->head[n + 1]))
					{
						__swap_Bheap_node(&(heap->head[c]), &(heap->head[n + 1]));
						n += 1;
					}
					else
						break;
				}
				else 
				{
					if (1 == comp(heap->head[c], heap->head[n]))
						__swap_Bheap_node(&(heap->head[c]), &(heap->head[n]));
					else
						break;
				}
			}
		}/* end for */
	}
	else
	{
		/* 大根堆 */
		for ( ; ; )
		{
			c = n;
			n = n<<1;
			if (n > heap->size)
				break;
			
			if ((n + 1) > heap->size)
			{
				if (-1 == comp(heap->head[c], heap->head[n]))
					__swap_Bheap_node(&(heap->head[c]), &(heap->head[n]));
				else
					break;
			}
			else
			{
				if (-1 == comp(heap->head[n], heap->head[n + 1]))
				{
					if (-1 == comp(heap->head[c], heap->head[n + 1]))
					{
						__swap_Bheap_node(&(heap->head[c]), &(heap->head[n + 1]));
						n += 1;
					}
					else
						break;
				}
				else 
				{
					if (-1 == comp(heap->head[c], heap->head[n]))
						__swap_Bheap_node(&(heap->head[c]), &(heap->head[n]));
					else
						break;
				}
			}
		}/* end for */
	}
	
	return (heap->head[heap->size + 1]);
}

/* 出堆操作 */
static struct Bheap_node* Bheap_pop(st
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值