基础练习 图的基础应用:存储和遍历(邻接表)

1.题目信息

  1. 论坛上的一个提问,题9和题10均属于图的应用:题9需要通过邻接矩阵存储图顶点和边,题10可以在题9的基础上直接输出 或者 通过邻接表存储图顶点和边然后进行输出
  2. 之前已经通过邻接矩阵进行了解答:题9 题10 使用邻接矩阵存储并进行图的遍历,本次使用邻接表解答题10
    在这里插入图片描述

2. 需要掌握的知识

  1. 图的邻接表存储

3.思路

  1. 题10属于图问题,需要通过邻接表存储数据

  2. 分析图中顶点和边的特点:
    (1)行row的取值范围是[0,6],列column的取值范围是[0,6],凡是符合该取值范围的均是有效点。
    (2)对于顶点(column i, row j)来说,他的上下左右邻接点分别是(i,j-1) , (i,j+1), (i-1,j), (i+1,j)
    依据上述两点进行有效边的判定即可
    在这里插入图片描述

  3. 构建边时,按从大到小的顺序插入:即 下 右 左 上,这样直接打印的数据与题目的要求一致

4. 代码框架(重点)

4.1 采用的数据结构

1.邻接表:图的邻接表构造较邻接矩阵麻烦,涉及的结构体包括 图、图的头结点、头结点的邻接点以及边,且 图、图的头结点、头结点的邻接点 从上向下依赖,一开始可能会晕,需要多练习才能掌握

struct EdgeStructure //边
{
	vertex V1;
	vertex V2;
};
typedef struct EdgeStructure *PtrEdge;

typedef struct AdjNodeStructure *PtrAdjNode; //邻接点
struct AdjNodeStructure
{
	vertex vertexNumber;
	PtrAdjNode Next;
};

struct HeadNode  //头结点
{
	PtrAdjNode AdjNode;
};
typedef struct HeadNode HeadNodeArray[max]; 

struct GraphStructure //图
{
	int VertexNumber; //图的顶点数量
	//int EdgeNumber; //题10不需要体现边的数量信息
	HeadNodeArray HeadNode;//头结点数组
};
typedef struct GraphStructure *ptrGraph;

4.2 程序框架

int main() //程序伪码描述
{
	1.创建空图
	2.加入边
	3.打印
}

4.3 主要分支函数

  1. CreatGraphic( )函数,创建一个空图,用于存储顶点和边数据
ptrGraph Graph; //为了方便,将Graph设定为全局变量
void createNoEdgeGraph(int vertexNumber)
{
	Graph=(ptrGraph)malloc(sizeof(struct GraphStructure));
	Graph->VertexNumber=vertexNumber;
	for(int i=0;i<vertexNumber;i++) //创建空的头结点
		Graph->HeadNode[i].AdjNode=NULL;
	return ;
}
  1. 下右左上判定函数 用于判定指定顶点(column i,row j) 是否具备有效的上下左右顶点,为边的插入打基础。结合 3.思路中的分析实现即可
vertex downJudge(column i,row j)
{
	//vertex Node=j*rowElementNumber + i;
	if( (j+1)>rowMax )
		return Null;
	else return ( (j+1)*rowElementNumber+i );
}

vertex rightJudge(column i,row j)
{
	vertex Node=j*rowElementNumber + i;
	if( (i+1)>columnMax )
		return Null;
	else return (Node+1);
}

vertex leftJudge(column i,row j)
{
	vertex Node=j*rowElementNumber + i;
	if( (i-1)<0 )
		return Null;
	else return (Node-1);
}

vertex upJudge(column i,row j)
{
	//vertex Node=j*rowElementNumber + i;
	if( (j-1)<0 )
		return Null;
	else return ((j-1)*rowElementNumber+i);
}
  1. insertEdge( ) 向图Graph中插入边,虽然是无向图,但由于题10中每个头顶点都是独立插入边的,因此执行一次即可;需要注意,下面的编码中邻接点的构造是倒序的,比如:依次录入头结点0的邻接点 2 3 4,实际输出的是 0-4-3-2-NULL
void insertEdge(PtrEdge Edge)
{
	PtrAdjNode Node;
	Node=(PtrAdjNode)malloc(sizeof(struct AdjNodeStructure));
	Node->Next=Graph->HeadNode[Edge->V1].AdjNode;
	Node->vertexNumber=Edge->V2;
	Graph->HeadNode[Edge->V1].AdjNode=Node;
	/*
	Node=(PtrAdjNode)malloc(sizeof(struct AdjNodeStructure));
	Node->Next=Graph->HeadNode[Edge->V2].AdjNode;
	Node->vertexNumber=Edge->V1;
	Graph->HeadNode[Edge->V2].AdjNode=Node;
	*/
	return;
}
  1. buildGraph( ) :先通过createNoEdgeGraph构建无边图,然后按下右左上的结点顺序插入边
typedef int vertex;
typedef int row;
typedef int column;
#define max 49
#define rowMax 6
#define columnMax 6
#define rowElementNumber 7
#define Null -1

void buildGraph()
{	
	int VertexNumber=max;
	PtrEdge Edge; 
	
	createNoEdgeGraph(VertexNumber);
	
	for(row i=0;i<=rowMax;i++) //两层循环 对应 7行7列的图表
	{
		for(column j=0;j<=columnMax;j++)
		{
			if(downJudge(j,i)!=Null) 
			{
				Edge=(PtrEdge)malloc(sizeof(struct EdgeStructure));
				Edge->V1=i*rowElementNumber+j;
				Edge->V2=downJudge(j,i);
				insertEdge(Edge);
			}
			
			if(rightJudge(j,i)!=Null) 
			{
				Edge=(PtrEdge)malloc(sizeof(struct EdgeStructure));
				Edge->V1=i*rowElementNumber+j;
				Edge->V2=rightJudge(j,i);
				insertEdge(Edge);
			}
			
			if(leftJudge(j,i)!=Null) 
			{
				Edge=(PtrEdge)malloc(sizeof(struct EdgeStructure));
				Edge->V1=i*rowElementNumber+j;
				Edge->V2=leftJudge(j,i);
				insertEdge(Edge);
			}
			
			if(upJudge(j,i)!=Null) 
			{
				Edge=(PtrEdge)malloc(sizeof(struct EdgeStructure));
				Edge->V1=i*rowElementNumber+j;
				Edge->V2=upJudge(j,i);
				insertEdge(Edge);
			}			
	
		}
	}
	
	return;
}

  1. PrintLinkTable( ) :按题目要求打印链表,由于build中已经按照 序号从大到小加入边,因此可以直接打印,这样与题目的要求是相符的
void PrintLinkTable()
{
	PtrAdjNode AdjNode;
	
	for(int i=0;i<Graph->VertexNumber;i++)
	{
		cout<<i;
		AdjNode=Graph->HeadNode[i].AdjNode;
		if(!AdjNode) continue;
		while(AdjNode)
		{
			cout<<" "<<AdjNode->vertexNumber;
			AdjNode=AdjNode->Next;
		}
		cout<<endl;
	}
	
	return;
}

5. 程序运行结果

0 1 7
1 0 2 8
2 1 3 9
3 2 4 10
4 3 5 11
5 4 6 12
6 5 13
7 0 8 14
8 1 7 9 15
9 2 8 10 16
10 3 9 11 17
11 4 10 12 18
12 5 11 13 19
13 6 12 20
14 7 15 21
15 8 14 16 22
16 9 15 17 23
17 10 16 18 24
18 11 17 19 25
19 12 18 20 26
20 13 19 27
21 14 22 28
22 15 21 23 29
23 16 22 24 30
24 17 23 25 31
25 18 24 26 32
26 19 25 27 33
27 20 26 34
28 21 29 35
29 22 28 30 36
30 23 29 31 37
31 24 30 32 38
32 25 31 33 39
33 26 32 34 40
34 27 33 41
35 28 36 42
36 29 35 37 43
37 30 36 38 44
38 31 37 39 45
39 32 38 40 46
40 33 39 41 47
41 34 40 48
42 35 43
43 36 42 44
44 37 43 45
45 38 44 46
46 39 45 47
47 40 46 48
48 41 47

6. 完整代码

#include <cstdlib>
#include <iostream>
using namespace std; 

typedef int vertex;
typedef int row;
typedef int column;
#define max 49
#define rowMax 6
#define columnMax 6
#define rowElementNumber 7
#define Null -1

struct EdgeStructure //边
{
	vertex V1;
	vertex V2;
};
typedef struct EdgeStructure *PtrEdge;

typedef struct AdjNodeStructure *PtrAdjNode; //邻接点
struct AdjNodeStructure
{
	vertex vertexNumber;
	PtrAdjNode Next;
};

struct HeadNode  //头结点
{
	PtrAdjNode AdjNode;
};
typedef struct HeadNode HeadNodeArray[max]; 

struct GraphStructure //图
{
	int VertexNumber; //图的顶点数量
	//int EdgeNumber; //题10不需要体现边的数量信息
	HeadNodeArray HeadNode;//头结点数组
};
typedef struct GraphStructure *ptrGraph;

ptrGraph Graph;

void buildGraph();
void insertEdge(PtrEdge Edge);
void createNoEdgeGraph(int vertexNumber);

vertex downJudge(column i,row j)
{
	//vertex Node=j*rowElementNumber + i;
	if( (j+1)>rowMax )
		return Null;
	else return ( (j+1)*rowElementNumber+i );
}

vertex rightJudge(column i,row j)
{
	vertex Node=j*rowElementNumber + i;
	if( (i+1)>columnMax )
		return Null;
	else return (Node+1);
}

vertex leftJudge(column i,row j)
{
	vertex Node=j*rowElementNumber + i;
	if( (i-1)<0 )
		return Null;
	else return (Node-1);
}

vertex upJudge(column i,row j)
{
	//vertex Node=j*rowElementNumber + i;
	if( (j-1)<0 )
		return Null;
	else return ((j-1)*rowElementNumber+i);
}

void PrintLinkTable()
{
	PtrAdjNode AdjNode;
	
	for(int i=0;i<Graph->VertexNumber;i++)
	{
		cout<<i;
		AdjNode=Graph->HeadNode[i].AdjNode;
		if(!AdjNode) continue;
		while(AdjNode)
		{
			cout<<" "<<AdjNode->vertexNumber;
			AdjNode=AdjNode->Next;
		}
		cout<<endl;
	}
	
	return;
}

int main()
{
	buildGraph();
	
	PrintLinkTable();
	
	return 0;
}

void buildGraph()
{	
	int VertexNumber=max;
	PtrEdge Edge; 
	
	createNoEdgeGraph(VertexNumber);
	
	for(row i=0;i<=rowMax;i++)
	{
		for(column j=0;j<=columnMax;j++)
		{
			if(downJudge(j,i)!=Null) 
			{
				Edge=(PtrEdge)malloc(sizeof(struct EdgeStructure));
				Edge->V1=i*rowElementNumber+j;
				Edge->V2=downJudge(j,i);
				insertEdge(Edge);
			}
			
			if(rightJudge(j,i)!=Null) 
			{
				Edge=(PtrEdge)malloc(sizeof(struct EdgeStructure));
				Edge->V1=i*rowElementNumber+j;
				Edge->V2=rightJudge(j,i);
				insertEdge(Edge);
			}
			
			if(leftJudge(j,i)!=Null) 
			{
				Edge=(PtrEdge)malloc(sizeof(struct EdgeStructure));
				Edge->V1=i*rowElementNumber+j;
				Edge->V2=leftJudge(j,i);
				insertEdge(Edge);
			}
			
			if(upJudge(j,i)!=Null) 
			{
				Edge=(PtrEdge)malloc(sizeof(struct EdgeStructure));
				Edge->V1=i*rowElementNumber+j;
				Edge->V2=upJudge(j,i);
				insertEdge(Edge);
			}			
	
		}
	}
	
	return;
}

void insertEdge(PtrEdge Edge)
{
	PtrAdjNode Node;
	Node=(PtrAdjNode)malloc(sizeof(struct AdjNodeStructure));
	Node->Next=Graph->HeadNode[Edge->V1].AdjNode;
	Node->vertexNumber=Edge->V2;
	Graph->HeadNode[Edge->V1].AdjNode=Node;
	return;
}

void createNoEdgeGraph(int vertexNumber)
{
	Graph=(ptrGraph)malloc(sizeof(struct GraphStructure));
	Graph->VertexNumber=vertexNumber;
	for(int i=0;i<vertexNumber;i++) //创建空的头结点
		Graph->HeadNode[i].AdjNode=NULL;
	return ;
}

参考信息

浙江大学 陈越、何钦铭老师主讲的数据结构

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值