图的顺序存储及其深度优先遍历和广度优先遍历

图的基本概念


        在线性表中,数据元素之间是被串起来的,仅有线性关系,每个数据元素只有一个直接前驱和一个直接后继。在树形结构中,数据元素之间有着明显的层次关系,并且每一层上的数据元素可能和下一层中多个元素相关,但只能和上一层中一个元素相关。图是一种较线性表和树更加复杂的数据结构。在图形结构中,结点之间的关系可以是任意的,图中任意两个数据元素之间都可能相关。

图的定义


        图(Graph)是由顶点的有穷非空集合V ( G ) 和顶点之间边的集合E ( G )组成,通常表示为: G = ( V , E ) 其中,G表示图,V 是图G 中顶点的集合,E 是图G 中边的集合。

注意:线性表可以是空表,树可以是空树,但图不可以是空图。就是说,图中不能一个顶点也没有,图的顶点集V一定非空,但边集E可以为空,此时图中只有顶点而没有边。

图的顺序存储 

邻接矩阵

        图的邻接矩阵存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(称为邻接矩阵)存储图中的边或弧的信息。

 下图是一个无向图和它的邻接矩阵:

下图是有向图和它的邻接矩阵:
 

 对于带权图而言,若顶点之间有边相连,则邻接矩阵中对应项存放着该边对应的权值

下图是有向网图和它的邻接矩阵:

 通过上面对无向图、有向图和网的邻接矩阵比较,可以定义出图顺序存储的结构类型

#define N 1024//最大顶点存储数量

typedef char g_data_t;

typedef struct sqg{
    g_data_t v_buf[N];//存放顶点的一维数组
    int e_buf[N][N];//存放边的二维数组
    int v_number;//顶点的数量
    int e_number;//边的数量
    int flag[N];//访问标志位
}sg_node, *sg_pnode;

注意:无向图和网的存储邻接矩阵是对称矩阵

下面以一个实例来讲解图的顺序存储实现原理:

 

 如上图所示,其邻接矩阵可以表示为:

图的初始化

sg_pnode create_g()
{
    //创建空间
    sg_pnode G = (sg_pnode)malloc(sizeof(sg_node));
    if(NULL == G)
    {
        printf("g is NULL\n");
        return NULL;
    }
    //给顶点赋值
    printf("please input V number->");
    scanf("%d", &(G->v_number));
    getchar();
    
    int s;
    for(s=0;s<G->v_number;s++)
	G->flag[s]=0;

    printf("please input V data->");
    int i,j;
    for(i = 0; i < G->v_number; i++)
    {
        scanf("%c", &(G->v_buf[i]));
    }
    getchar();

    //给边赋值
    printf("please input E number->");
    scanf("%d", &(G->e_number));
    getchar();
    /*
    for(i = 0; i < G->v_number; i++)
        for(j = 0; j < G->v_number; j++)
        {
            G->e_buf[i][j] = 0
        }
    */
    memset(G->e_buf,0,sizeof(G->e_buf));
    //for(i=0;i<N;i++)
//	G->e_buf[i][i]=1;

    for(i = 0; i < G->e_number; i++)
    {
        printf("please input e data->");
        int p, q,x;
        scanf("%d%d%d", &p, &q,&x);//x代表权值,实现网的结构
        G->e_buf[p][q] = x;//若不表示网,直接赋值为1就行,代表两个顶点连接
        G->e_buf[q][p] = x;//无向图才有反向,有向图没有
    }
    return G;
}

        这里初始化的是网这个结构,和无向图的区别在于:对于有关系的两个顶点,若是图,其邻接矩阵中用1来表示,而如果是网,邻接矩阵中存储的就是实际的权值。

打印邻接矩阵 

int show_g(sg_pnode G)
{
    //printf("V data is\n");
	printf("the relationship of the Graph:\n");
	printf("  ");
    int i,j;
    for(i = 0; i < G->v_number; i++)
    {
        printf("%2c ", G->v_buf[i]);
    }
    printf("\n");

    //printf("E data is\n");
    for(i = 0; i < G->v_number; i++)
    {
	printf("%c:",G->v_buf[i]);
        for(j = 0; j < G->v_number; j++)
        {
            printf("%2d ", G->e_buf[i][j]);
        }
        printf("\n");
    }

    return 0;
}

图的广度优先遍历:BFS

图的广度优先遍历需要借助队列来实现,其算法步骤为:

1、首先创建一个队列,随机选取一个顶点入队

2、进入循环,循环结束条件为队列为空

3、出队,若该元素未被访问,则访问该元素,并将其访问标志位置为1表示已访问

4、查找与当前出队元素有关系且未被访问的元素,若有,则入队该元素,

5、重复2至4步,直至遍历完成

注意:遍历完成后需要将所有元素访问标志位恢复为0.

//广度遍历
void BFS(sg_pnode G)
{
	qnode Q=queue_init();
	push_queue(Q,0);
	while(!empty_queue(Q))
	{	//puts("!!!");
		int data=pop_queue(Q);
		if(G->flag[data]==0)
			{
				printf("%c ",G->v_buf[data]);
				G->flag[data]=1;
			}	
		int i;
		for(i=0;i<G->v_number;i++)
			if(G->e_buf[data][i]>0&&G->flag[i]==0)
				push_queue(Q,i);
	}
	memset(G->flag,0,sizeof(G->flag));
	puts("");	
}

图的深度优先遍历 :DFS

图的深度优先遍历需要借助栈来实现,其算法步骤为:

1、首先创建一个栈,随机选取一个顶点入栈

2、进入循环,循环结束条件为栈为空

3、访问栈顶元素,若该元素未被访问,则访问该元素,并将其访问标志位置为1表示已访问

4、查找与当前栈顶元素有关系且未被访问的元素,若有,则入栈该元素;若没有,则将栈顶元素出栈

5、重复2至4步,直至遍历完成

注意:遍历完成后需要将所有元素访问标志位恢复为0.

//深度遍历
void DFS(sg_pnode G)
{
	p_node S=stack_init();
	push_stack(S,0);
	while(!empty_stack(S))
	{
		int data=top(S);
		if(G->flag[data]==0)
			{
				printf("%c ",G->v_buf[data]);
				G->flag[data]=1;
			}
		int i,flag=0;
		for(i=0;i<G->v_number;i++)
			if(G->e_buf[data][i]>0&&G->flag[i]==0)
				{
					push_stack(S,i);
					flag=1;
				}
		if(flag==0)
			pop_stack(S);
	}	
	memset(G->flag,0,sizeof(G->flag));
	puts("");
}

遍历结果

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值