学习笔记:数据结构与算法(十五):图的存储结构和遍历

邻接表(无向图)

考虑将数组和链表结合在一起来存储,这种图结构称为邻接表。
处理方法:

  1. 顶点用一个一维数组存储,当然也可以用单链表,但是数组更容易地读取顶点信息。
  2. 图中每个顶点Vi的所有邻接点构成一个线性表,由于邻接点的个数不确定,所以选择用单链表存储。
    在这里插入图片描述
    右侧单链表的数字代表数组中的位置,如果没有了就用空指针结束。

邻接表(有向图)

在有向图中,结构也是类似的,如下图所示
在这里插入图片描述
注意:要么表示出度要么表示入度。

邻接表(网)

对于带权值的网图,在边表结点定义中再增加一个数据域来存储权值。
在这里插入图片描述

十字链表

重新定义顶点表结点结构
在这里插入图片描述
边表结点结构
在这里插入图片描述
在这里插入图片描述
看V1这个结点,出度是1->0和1->2,所以在后面蓝色指出来了,入度是2->1,用红色的表示。

好处:把邻接表和逆邻接表整合在一起,容易找到为尾的弧,也容易找到头的弧。
缺点:结构复杂

邻接多重表

在这里插入图片描述
为了避免这种麻烦,可以对边表结构改装,重新定义,关注重点改为边而不是顶点
在这里插入图片描述
在这里插入图片描述
填充之后变为
在这里插入图片描述

边集数组

两个一维数组构成,一个存储顶点的信息,另一个存储边的信息,边数组每个数据元素由一条边的起点下标,终点下标和权组成。
在这里插入图片描述

图的遍历

深度优先遍历

也称为深度优先搜索,简称为DFS。
在这里插入图片描述

骑士周游问题

国际象棋棋盘为8*8的方格棋盘,将“马”放在任意指定的方格中,按照走棋规则进行移动,要求每个方格只能进入一次,最终使得马走遍64个方格。
在这里插入图片描述
回溯法:一条路走到黑,碰到走过的结点就放弃再退回,和递归可以搭配使用
哈密尔顿路径:经过图G中每个顶点且只经过一次的一条轨迹。如果这个轨迹是一条闭合的路径,那么这条路径称为哈密尔顿回路。

#include <stdio.h>
#include <time.h>

#define X 8
#define Y 8
int chess[X][Y];
//找到基于xy位置的下一个可走的位置
int nextxy(int *x,int *y, int count)
{
	switch(count)
	case 0:
		if(*x + 2 <= X -1 && *y - 1 >= 0 && chess[*x + 2][*y - 1] == 0)
		{
			*x += 2;
			*y -= 1;
			return 1;
		}
		break;
	case 1:
		if(*x + 2 <= X -1 && *y + 1 <=Y - 1 && chess[*x + 2][*y + 1] == 0)
		{
			*x += 2;
			*y += 1;
			return 1;
		}
		break;
	case 2:
		if(*x + 1 <= X -1 && *y -2>=0 && chess[*x + 1][*y-2] == 0)
		{
			*x += 1;
			*y -= 2;
			return 1;
		}
		break;
	case 3:
		if(*x + 1 <=X-1 && *y +2<=Y-1 && chess[*x + 1][*y + 2] == 0)
		{
			*x += 1;
			*y += 2;
			return 1;
		}
		break;
	case 4:
		if(*x -2>=0 && *y - 1 >=0 && chess[*x -2][*y-1] == 0)
		{
			*x -= 2;
			*y -= 1;
			return 1;
		}
		break;
	case 5:
		if(*x -2 <= X -1 && *y + 1 <=Y - 1 && chess[*x -2][*y + 1] == 0)
		{
			*x -= 2;
			*y += 1;
			return 1;
		}
		break;
	case 6:
		if(*x -1 >=0  && *y -2>=0 && chess[*x-1][*y-2] == 0)
		{
			*x -= 1;
			*y -= 2;
			return 1;
		}
		break;
	case 7:
		if(*x-1 >=0 && *y + 2 <=Y - 1 && chess[*x -1][*y + 2] == 0)
		{
			*x -= 1;
			*y += 2;
			return 1;
		}
		break;
	default:
		break;
	}
	return 0;
}

void print()
{
	int i,j;
	for(i=0;i<X;i++)
	{
		for(j=0;j<Y;j++)
		{
			printf("%2d\t",chess[i][j]);					
		}
		printf("\n");	
	}
	printf("\n");
}
 //深度优先遍历棋盘,xy为位置坐标,tag是标记变量,走一步加一
int TravelChessBoard(int x,int y, int tag)
{
	int x1 =x,y1=y,flag = 0,count = 0;
	chess[x][y] = tag;
	if(X*Y == tag)
	{
		//打印棋盘
		print();
		return 1}
	//找下一个马的坐标,如果找到flag为1,否则为0
	flag = nextxy(&x1,&y1,count);
	while( 0 ==flag && count <7)
	{
		count++;
		flag = nextxy(&x1,&y1,count);
	}
	while(flag)
	{
		if(TravelChessBoard(x1,y1,tag+1))
		{
			return 1;
		}
		//继续找到下一步可走的坐标
		x1 =x;
		y1 = y;
		count ++;
		flag = nextxy(&x1,&y1,count);
		while( 0 ==flag && count <7)
		{
			count++;
			flag = nextxy(&x1,&y1,count);
		}
	}
	if( 0 == flag)
	{
		chess[x][y] = 0;
	}
	return 0;
	
}

int main()
{
	int i,j;
	clock_t start,finish;
	start = clock();
	for(i=0;i<X;i++)
	{
		for(j=0;j<Y;j++)
			chess[i][j] = 0;
	}
	if(!TravelChessBoard(2,0,1))
	{
		printf("遍历失败!\n");
		
	}
	finish = clock();
	printf("本次计算一共耗时:%f秒\n\n",(double)(finish - start)/CLOCKS_PER_SEC);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值