图的D搜索
图的D-搜索类似于BFS,不同之处在于使用栈代替BFS中的队列,入、出队列的操作改为入、出栈的操作。即当一个顶点的所有邻接点被搜索之后,下一个搜索出发点应该是最近入栈(栈顶)的顶点。
①用邻接表作存储结构,写一个D-搜索算法。
②用D-搜索方法搜索下图,设初始出发点为1,写出顶点的访问次序和相应的生成树,当从某顶点出发搜索它的邻接点时,请按邻接点序号递增搜索,以使答案唯一。
难度系数:★★★★
Talk is cheap. Show me the code.
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
//定义常用值
#define FALSE 0
#define TRUE 1
#define OK 1
#define ERROR -1
#define MAX_VERTEX_NUM 20//最多顶点个数
#define Stack_Size 50//用顺序栈代替队列
#define Infinity 32768//表示无穷大
typedef int StackElementType;//栈类型为整型
typedef struct//定义顺序栈
{
StackElementType elem[Stack_Size];
int top;
}SeqStack;
void InitStack(SeqStack *S)//初始化顺序栈
{
S->top = -1;
}
int Push(SeqStack *S, StackElementType x)//进栈
{
if(S->top==Stack_Size-1)
{
return FALSE;
}
else
{
S->top++;
S->elem[S->top] = x;
return TRUE;
}
}
int Pop(SeqStack *S, StackElementType *x)//出栈
{
if (S->top == -1)
{
return FALSE;
}
else
{
*x = S->elem[S->top];
S->top--;
return TRUE;
}
}
int GetTop_Stack(SeqStack *S, StackElementType *x)//找栈顶元素
{
if (S->top == -1)
{
return FALSE;
}
else
{
*x = S->elem[S->top];
return TRUE;
}
}
int IsStackEmpty(SeqStack *S)//判断栈是否为空
{
if (S->top == -1)
{
return TRUE;
}
else
{
return FALSE;
}
}
//图的邻接表表示法
typedef int OtherInfo;//设置与该弧相关的信息为整型
typedef int VertexData;//设置顶点数据为整型
typedef enum{DG,DN,UDG,UDN} GraphKind;//图的种类
typedef struct ArcNode
{
int adjvex;//该弧指向顶点的位置
struct ArcNode *nextarc;//指向下一条弧的指针
OtherInfo info;//与该弧(边)相关的信息
}ArcNode;
typedef struct VertexNode
{
VertexData data;//顶点数据
ArcNode *firstarc;//指向该顶点第一条弧的指针
}VertexNode;
typedef struct
{
VertexNode vertex[MAX_VERTEX_NUM];
int vexnum, arcnum;//图的顶点数和弧数
GraphKind kind;//图的种类标志
}AdjList;//基于邻接表的图
int LocateVertex(AdjList *G,VertexData x)//定位顶点
{
int i;
for (i = 1; i <= G->vexnum; i++)
{
if (G->vertex[i].data == x)
{
return i;
}
}
//printf("Fail to locate this vertex!\n");//测试是否找到该结点
return ERROR;
}
int FirstAdjVertex(AdjList *G,int v)//求v的第一个邻接点
{
int i, x;
for (i = 1; i <= G->vexnum; i++)
{
if (G->vertex[i].data == v)
{
x = G->vertex[i].firstarc->adjvex;
return x;
}
}
//printf("Fail to find first adjacency vertex!\n");//测试是否找到
return ERROR;
}
int NextAdjVertex(AdjList *G, int v , int w)//求v相对于w的下一个邻接点
{
int i,x,nextadjvertex;
x = LocateVertex(G, v);
ArcNode * p;
p = (ArcNode *)malloc(sizeof(ArcNode));
if (p == NULL)
{
printf("Fail to allocate space!");//分配空间失败
return ERROR;
}
p->adjvex = G->vertex[x].data;
p->nextarc = G->vertex[x].firstarc;
p = p->nextarc;
while (p != NULL)
{
if (p->adjvex == w)
{
if (p->nextarc == NULL)
{
break;
}
ArcNode *q;//q为相对于w的下一个邻接点
q = (ArcNode *)malloc(sizeof(ArcNode));
q->adjvex = p->nextarc->adjvex;
nextadjvertex = q->adjvex;
return nextadjvertex;
}
else
{
p = p->nextarc;
}
}
//printf("Fail to find next adjacency vertex!\n");//测试是否找到
return ERROR;
}
void AdjList_Create(AdjList *G)//建立基于邻接表的无向图
{
printf("请依次输入图的边的个数和顶点的个数:\n");
scanf_s("%d %d", &G->arcnum, &G->vexnum);
int i;
for (i = 1; i <= G->vexnum; i++)//建立表头结点表
{
printf("请输入一个顶点:\n");
scanf_s("%d", &G->vertex[i].data);
G->vertex[i].firstarc = NULL;
printf("\n");
}
int j1,j2,v1,v2;
for (i = 1; i <= G->vexnum; i++)//建立边表
{
int n,k;
printf("请输入某个顶点的边表中的结点个数:\n");//控制每个边表中的结点个数
scanf_s("%d", &n);//每次建立边表中的邻接点的个数
printf("\n");
for (k = 1; k <= n; k++)
{
printf("请输入弧头和弧尾:\n");
scanf_s("%d %d", &v1, &v2);//输入弧头和弧尾
j1 = LocateVertex(G, v1);
j2 = LocateVertex(G, v2);
ArcNode *g,*temp;//g为插入的一个邻接点,temp为临时结点
g = (ArcNode *)malloc(sizeof(ArcNode));
g->nextarc = NULL;
g->info = 0;//0表示没有关于下一条弧的信息
temp = (ArcNode *)malloc(sizeof(ArcNode));
temp->nextarc = NULL;
temp->info = 0;
g->adjvex = G->vertex[j2].data;
if (G->vertex[j1].firstarc == NULL)//插入边表第一个结点
{
G->vertex[j1].firstarc = g;
}
else//插入边表非第一个结点
{
temp = G->vertex[j1].firstarc;
G->vertex[j1].firstarc = g;
g->nextarc = temp;
}
}
}
}
void InSequence(AdjList *G, int v0)//搜索的时候调整顺序保证结果唯一
{
int x;
x = LocateVertex(G, v0);
ArcNode *p;//p,q为调整边表顺序所需的结点
p = (ArcNode *)malloc(sizeof(ArcNode));
ArcNode *q;
q = (ArcNode *)malloc(sizeof(ArcNode));
p->adjvex = G->vertex[x].data;
p->nextarc = G->vertex[x].firstarc;
q = p;
p = p->nextarc;
int a[MAX_VERTEX_NUM], i = 0,m;
for (m = 0; m < MAX_VERTEX_NUM; m++)//初始化排序数组
{
a[m] = Infinity;
}
while (p != NULL)//待排序的边表中的值赋给数组元素
{
a[i] = p->adjvex;
p = p->nextarc;
i++;
}
int j, k,temp;
for (j = 1; j < MAX_VERTEX_NUM; j++)//冒泡法排序(递增顺序)来保证搜索答案唯一
{
for (k = 0; k < MAX_VERTEX_NUM - j; k++)
{
if (a[k] > a[k + 1])
{
temp = a[k];
a[k] = a[k + 1];
a[k + 1] = temp;
}
}
}
i = 0;
q = q->nextarc;
while (q != NULL)//排序后的数组元素的值赋回给边表
{
q->adjvex=a[i];
q = q->nextarc;
i++;
}
}
int visited[MAX_VERTEX_NUM] = { 0 };//设置访问标志visited数组来判断顶点是否被访问过,0为否;1为是.
void D_Search(AdjList G,int v0)//D搜索,出发点为1
{
printf("%d ",v0);
visited[v0] = TRUE;
ArcNode *p;
p = (ArcNode *)malloc(sizeof(ArcNode));
SeqStack s;
InitStack(&s);
Push(&s, v0);
InSequence(&G, v0);//入栈一个元素就调整该边表的顺序(递增)
while (!IsStackEmpty(&s))
{
int v,w;
Pop(&s, &v);
w = FirstAdjVertex(&G, v);//下一个邻接点
while (w != -1)
{
if (!visited[w])
{
printf("%d ", w);
visited[w] = TRUE;
Push(&s, w);
InSequence(&G, w);
}
w = NextAdjVertex(&G, v, w);
}
}
}
int main()
{
AdjList G;
AdjList_Create(&G);
printf("D-搜索结果为:");
D_Search(G, 1);//从1开始D-搜索,递增顺序保证答案唯一
system("pause");
return 0;
}
思路
图的D-搜索是一种类似于BFS的一种搜索算法,只是用栈代替了队列。基本思路就是:建图(基于邻接表)、实现图的D-搜索、输出结果。在这个过程中要有栈和与栈相关的基本操作的算法函数和图及其图相关的基本操作的算法函数。最重要的就是编写图的D-搜索算法函数。基本思想及过程为:
1、先设立一个访问标志数组visited[],其初值为0,访问后置为1。
2、访问某个顶点v0并且将访问标志置为1,然后将v0入栈。
3、只要栈不空,就重复一下步骤:
①栈顶元素v出栈。
②求v的邻接点w,如果w未访问,则访问w并置访问标志为1,然后将w入栈。
测试结果