深度优先搜索和广度优先搜索是树形结构中常用的两种搜索遍历方式,其实更多的是用在图中的,深度优先搜索可以用来判断有向图中是否存在环,广度优先搜索就更有用了,常用的路径搜索算法一般都是建立在广度优先搜索的基础上,如dijkstra(迪杰斯特拉)算法,A*算法等,感觉两者的唯一区别就是A*算法中在计算路径权重时加入了一个估价函数,来改变广搜的方向,让搜索向目的地方伸展,减少无用搜索的数量,所以A*算法做的好不好,完全是由其估价函数决定的(只是个人感觉)。
言归正传,这里暂且先不讨论图的遍历,后续有机会再分析,我们现在先来看一下相对简单的树的深搜和广搜(层次遍历),
深搜就是:一根筋到底式搜索,
广搜就是:从头层层推进的搜索
直接上代码进行分析,前面的文章已经介绍了建树的过程,我们这里就不对建树过程在多做解释,直接看深搜和广搜的代码
/*BST.c*/
/*深度优先遍历使用了栈结构,广度优先遍历使用了队列结构*/
/*深度优先遍历*/
/**/
void DFS(Node* root)
{
Stack stack;
registstack(&stack);
stack.init_size(&stack, 1000);
/*判断是否是空树*/
if (NULL == root)
{
printf(" empty tree!!!\n ");
return;
}
/*保存根节点到栈中*/
Node* tmp = root;
stack.push(&stack, tmp);
/*栈为空时推出循环*/
while (!stack.is_empty(&stack))
{
tmp = stack.top(&stack);
stack.pop(&stack);
printf("%d\t",tmp->val);
/*这里为什么要先将右子树入栈呢?因为先入栈的后出栈
A
/ \
B C
/ \ / \
D E F G
以上面的树为例,A在循环开始之前就已经入栈,
第一次循环:进入循环时,A出栈,输出A的值,然后将C(右子节点)入栈,
再将B(左子节点)入栈,
第二次循环:将B先出栈(后入先出)然后将B的右子节点E入栈,左子节点D入栈,
已经输出值的结点是AB,此时栈内元素依次为CED,
第三次循环:栈内元素是ED,D是后进入,因此先输出D,D没有子节点,
因此本次循环没有新元素入栈,栈内元素为CE
第四次循环:E出栈,E也没有子节点,因此本次循环也没有元素入栈,
栈内元素为C
第五次循环:C出栈,将G和F入栈,栈内元素为GF
第六次循环:将F出栈,F无子节点,因此此次循环没有元素入栈,
栈内元素为G
第七次循环:将G出栈,因为G没有子节点,因此本次循环没有元素入栈,
此时栈为空,因此循环结束
*/
if (tmp->prc)
stack.push( &stack, tmp->prc );
if (tmp->plc)
stack.push( &stack, tmp->plc );
}
}
/*广度优先搜索*/
void BFS(Node* root)
{
Node* tmp = root;
if (tmp == NULL)
{
printf("Tree is empty!!!");
return;
}
Queue queue;/*申请个队列变量 */
registerqueue(&queue);
queue.initqueue(&queue);
queue.push(&queue, tmp);/*将根节点先入队*/
/*队列为空时退出循环*/
while (!queue.is_empty(&queue))
{
/*输出队头元素值*/
tmp = queue.get(&queue)->val;
printf("%d\t",tmp->val);
/*队列的特点是先进先出,因此我们以下例进行分析树的广度优先遍历过程
A
/ \
B C
/ \ / \
D E F G
第一次循环:进入循环时,队列里只有A节点,输出A节点的值,然后将B节点入队,
再将C节点入队,然后将A节点出队
第二次循环:进入循环时,队列内有BC两个元素,因为B是先进入的,先进先出的原则下本次循环输出B,
然后将D和E依次入队,B元素出队,队列元素为CDE
第三次循环:进入循环时,队列内有CDE,队头元素是C,因此输出C,再将C的左右子节点FG入队,
将C出队,此时队内原始依次是DEFG
第四次循环:进入循环时,队内元素是DEFG,先将D输出,因为D没有子节点,因此本次循环没有元素入队,
D出队,队内元素为EFG
第五次循环:E输出,没有元素入队,E出队,
第六次循环:F输出,没有元素入队,F出队,
第七次循环:G输出,没有元素入队,G出队,队列为空,退出循环
*/
if (tmp->plc != NULL)
{
queue.push(&queue, tmp->plc);
}
if (tmp->prc != NULL)
{
queue.push(&queue,tmp->prc);
}
queue.pop(&queue);
}
}
以上就是深度优先和广度优先搜索的具体代码,代码仅供简述原理使用,错误之处,请指正。