数据结构——邻接表(图)

        在讲邻接表之前,我觉得有必要介绍一下图的遍历操作:

深度优先遍历:对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次

广度优先遍历:系统地展开并遍历图中的所有节点,而且每个节点只能访问一次,与队列配合进行

关于邻接表这种存储结构,在数据结构里非常特殊,因为它是由顺序+链式存储,非单一的顺序存储或链式存储,所以相对来说也比较复杂;具象化一下描述:比如食堂打饭,每个窗口就是一个顶点,每个窗口前面排着的人就是要到这个窗口打饭的人,即表示人和窗口的关系,但是各个窗口前的人互不干涉,因此彼此之间不能直接访问;又比如你去坐高铁,你必须找到对应的站台号下去,否则下去之后发现站台不对,跟你要去的站台隔着几条铁轨,还不能直接过去,必须回到上面的大走廊再继续找。废话有点多了,下面来定义结构体以及相关操作:

//边
typedef struct Edge
{
	int index;//顶点下标
	struct Edge *next;//指向下一条边的地址
}Edge;

创建到 index 顶点的边

//创建到index顶点的边
Edge *create_edge(int index)
{
	Edge *edge=malloc(sizeof(Edge));
	edge->index=index;
	edge->next=NULL;
	return edge;
}

顶点

//顶点
typedef struct Vertex
{
	char vertex;//顶点数据
	Edge *first;//指向第一条边的指针
}Vertex;

//图
typedef struct graph
{
	Vertex *v;//顶点数组
	int cnt;//顶点数量
}Graph;

创建图

//创建图
Graph *create_graph(const char *str)
{
	//申请图所需要的内存
	Graph *graph=malloc(sizeof(Graph));
	//计算顶点的数量
	graph->cnt=strlen(str);
	//申请存储顶点所需内存
	graph->v=malloc(sizeof(Vertex)*graph->cnt);
	//初始化顶点
	for(int i=0;i<graph->cnt;i++)
	{
		graph->v[i].vertex=str[i];
		graph->v[i].first=NULL;
	}
	return graph;
}

添加边

//添加边
bool add_graph(Graph *graph,char v1,char v2)
{
	for(int i=0;i<graph->cnt;i++)
	{
		if(v1==graph->v[i].vertex)
		{
			for(int j=0;j<graph->cnt;j++)
			{
				if(v2==graph->v[j].vertex)
				{
					Edge *edge=create_edge(j);
					edge->next=graph->v[i].first;
					graph->v[i].first=edge;
					return true;
				}
			}
		}
	}
	return false;
}

入度

//入度
int id_graph(Graph *graph,char v)
{
	int x=-1,num=0;
	for(int i=0;i<graph->cnt;i++)
	{
		if(v==graph->v[i].vertex)
		{
			x=i;
			break;
		}
	}
	if(x==-1) return -1;
	for(int i=0;i<graph->cnt;i++)
	{
		for(Edge *edge=graph->v[i].first;edge;edge=edge->next)
		{
			if(edge->index==x)
				num++;
		}
	}
	return num;
}

出度

//出度
int od_graph(Graph *graph,char v)
{
	int num=0;
	for(int i=0;i<graph->cnt;i++)
	{
		if(v==graph->v[i].vertex)
		{
			for(Edge *edge=graph->v[i].first;edge;edge=edge->next)
			{
				num++;	
			}
			return num;
		}
	}
	return -1;
}

显示图

//显示图
void show_graph(Graph *graph)
{
	for(int i=0;i<graph->cnt;i++)
	{
		printf("index:%d v:%c ",i,graph->v[i].vertex);
		for(Edge *edge=graph->v[i].first;edge;edge=edge->next)
		{
			printf("e:%d ",edge->index);	
		}
		printf("\n");
	}
}

深度优先遍历

//深度优先遍历
bool visit[7];
void _dfs_graph(Graph *graph,int i)
{
	visit[i]=true;
	printf("%c ",graph->v[i].vertex);
	for(Edge *e=graph->v[i].first;e;e=e->next)
	{
		if(!visit[e->index])
			_dfs_graph(graph,e->index);
	}
}
void dfs_graph(Graph *graph)
{
	_dfs_graph(graph,0);
}

广度优先遍历

//广度优先遍历
void bfs_graph(Graph *graph)
{
	bool visited[graph->cnt];
	ListQueue *queue=create_queue();
	for(int i=0;i<graph->cnt;i++)
	{
		if(!visited[i])
		{
			visited[i]=true;
			in_queue(queue,i);
		}
		while(queue->cnt)
		{
			int current=0;
			head_queue(queue,&current);
			printf("%c ",graph->v[current].vertex);
			out_queue(queue);

			for(Edge *e=graph->v[current].first;e;e=e->next)
			{
				if(!visited[e->index])
				{
					visited[e->index]=true;
					in_queue(queue,e->index);
				}
			}
		}
	}
	destroy_queue(queue);
}

浅浅的测试一下:

int main(int argc,const char* argv[])
{
	char *str="ABCDEFG";
	Graph *graph=create_graph(str);
	add_graph(graph,'A','B');
	add_graph(graph,'A','D');
	add_graph(graph,'B','D');
	add_graph(graph,'B','E');
	add_graph(graph,'C','D');
	add_graph(graph,'C','F');
	add_graph(graph,'D','C');
	add_graph(graph,'D','G');
	add_graph(graph,'E','G');
	add_graph(graph,'F','G');
	add_graph(graph,'G','F');
	show_graph(graph);
	printf("id=%d\n",id_graph(graph,'D'));
	printf("od=%d\n",od_graph(graph,'E'));
	dfs_graph(graph);
	printf("\n");
	bfs_graph(graph);
		
	return 0;
}

over

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值