图1——图的五种存储结构及其初始化

零、说明

  1. 本文中,V代表Vertex,即顶点,E代表Edge,即边。什么Vnum,Enum,firstE都按照这个来理解。
  2. 原理我是按《大话数据结构》来的,我也解释不好这个原理,就不献丑了
  3. 存储方式还远不止这些,有个好像叫前向星,我现在还不会(流下了菜鸡的眼泪)
  4. 本文有很多地方不严谨,后续待修改

一、邻接矩阵

  1. 数据类型
typedef struct 
{
	char Vertex[MAXSIZE];
	int Edge[MAXSIZE][MAXSIZE];
	int Vnum,Enum;
}MGraph;//叫MGraph是因为矩阵(Matrix)

包含顶点表和矩阵两个部分,矩阵的每一个元素都代表某点(行)到某点(列)是否有边存在
2. 初始化

void CreateMGraph(MGraph *M)
{
	int i,j,start,end;
	for(i=0;i<MAXSIZE;i++)
		for(j=0;j<MAXSIZE;j++)
		{
			M->Edge[i][j]=INFINITY;//提前define为65535
		}
	cout<<"请输入图的点数和边数:";
	cin>>M->Vnum>>M->Enum;
	cout<<"请输入各点数据:";
	for (i=0;i<M->Vnum;i++)
	{
		cin>>M->Vertex[i];
	}
	cout<<"请按'始边 终边 权值'的顺序输入图的边(只支持数字序号,且从零开始):\n";
	for (i=0;j<M->Enum;i++)
	{
		cin>>start;
		cin>>end;
		cin>>M->Edge[start][end];
		M->Edge[end][start]=M->Edge[start][end]; //这一行
	}
}

说明几点:
计数从零开始,所以就比如0号点到3号点有边
用在无向图中,如果想用在有向图,上面示意的那一行删掉即可

二、邻接表

0.起因:邻接矩阵直观是直观,但是空间浪费挺多的,联想到前面用链式结构节省空间,用链式结构存储图彳亍不彳亍?
彳亍!

  1. 数据类型(List)
    分三层:首先定义边节点,然后定义图中的节点,节点中有指向一个边的指针(所以不是第一个定义它),最后定义整个图,就是点的数组
typedef struct LEnode
{
	int Vdata;//连接的点序号
	int weight;//该边权值
	struct LEnode *next;//同节点的下一条边
}LEnode;
typedef struct LVnode
{
	int data;
	LEnode *firstE;
}LVnode,lGraph[MAXSIZE];
typedef struct 
{
	int Vnum,Enum;
	lGraph G;
}LGraph;
  1. 初始化
    很容易理解,就是新建一个边,输入,按头插法连接到点上
void CreateLGraph(LGraph *L)
{
	int i,start,end,weight; 
	LEnode *e;
	cout<<"请输入顶点数和边数:";
	cin>>L->Vnum>>L->Enum; 
	cout<<"请输入顶点数据:";
	for (i=0;i<L->Vnum;i++)
	{
		cin>>L->G[i].data;
		L->G[i].firstE=NULL;
	}
	cout<<"请输入边:按'始边 终边 权值'的格式\n";
	//头插法 
	for(i=0;i<L->Enum;i++)//注意,这个是无向图,想用有向图就修改一下
	{
		cin>>start>>end>>weight;
		
		e=new LEnode;
		e->Vdata=end;
		e->weight=weight;
		e->next=L->G[start].firstE;
		L->G[start].firstE=e;
		
		e=new LEnode;
		e->Vdata=start;
		e->weight=weight;
		e->next=L->G[end].firstE;
		L->G[end].firstE=e;
	}
}

三、十字链表(邻接多重表)

A.有向的称为十字链表

  1. 数据类型(Cross)
typedef struct CEnode1
{
	int weight;
	int tailV,headV;
	struct CEnode1 *headnext,*tailnext;//分别指向弧头、弧尾相同的下一条边 
}CEnode1;
typedef struct CVnode1
{
	int data;
	CEnode1 *firstIn,*firstOut;
	//第一条入/出这个点的边(按输入顺序,所以没有严格正确的先后之分,
	//只是代表性地用一下'第一条'这个词罢了)
}CVnode1,cGraph1[MAXSIZE];
typedef struct 
{
	int Vnum,Enum;
	cGraph1 G;
}CGraph1;
  1. 初始化
void CreateCGraph1(CGraph1 *C)//有向图 
{
	int i;
	CEnode1 *e; 
	cout<<"请输入顶点数和边数:";
	cin>>C->Vnum>>C->Enum;
	cout<<"请输入顶点数据:";
	for(i=0;i<C->Vnum;i++)
	{
		cin>>C->G[i].data;
		C->G[i].firstIn=NULL;
		C->G[i].firstOut=NULL;
	}
	cout<<"请输入边:按'始边 终边 权值'的格式\n";
	for(i=0;i<C->Enum;i++)//重点在这个循环,思路和邻接表类似,原理大概就是每条边都存储着下一条相同始/终点的边
	{
		e=new CEnode1;
		cin>>e->tailV>>e->headV>>e->weight;
		e->tailnext=C->G[e->tailV].firstOut;
		C->G[e->tailV].firstOut=e;
		e->headnext=C->G[e->headV].firstIn;
		C->G[e->headV].firstIn=e;
	}
}

B. 无向的称为邻接多重表

  1. 数据类型
    说实话,无向的数据类型和有向的挺像,不过简洁了许多
typedef struct CEnode2
{
	int weight;
	int Vi,Vj;//这条边两端的顶点
	struct CEnode2 *Vinext,*Vjnext;//Vi,Vj连接的下一条边 
}CEnode2;
typedef struct CVnode2
{
	int data;
	CEnode2 *firstE;
}CVnode2,cGraph2[MAXSIZE];
typedef struct
{
	int Vnum,Enum;
	cGraph2 G;
}CGraph2;
  1. 初始化
void CreateCGraph2(CGraph2 *C)//无向图
{
	int i;
	CEnode2 *e;
	cout<<"请输入顶点数和边数:";
	cin>>C->Vnum>>C->Enum;
	cout<<"请输入顶点数据:";
	for(i=0;i<C->Vnum;i++)
	{
		cin>>C->G[i].data;
		C->G[i].firstE=NULL;
	}
	cout<<"请输入边:按'始边 终边 权值'的格式\n";
	for(i=0;i<C->Enum;i++)
	{
		e=new CEnode2;
		cin>>e->Vi>>e->Vj>>e->weight;
		e->Vinext=C->G[e->Vi].firstE;
		C->G[e->Vi].firstE=e;
		e->Vjnext=C->G[e->Vj].firstE;
		C->G[e->Vj].firstE=e;
	}
} 

四、边集数组

  1. 大概类似邻接矩阵的三元组存储法?(矩阵还没写。。。)
  2. 数据类型
typedef struct 
{
	int Vnum,Enum;
	int V[MAXSIZE];
	int E[MAXSIZE][3];
}EGraph;
  1. 初始化
    没什么好说的
void CreateEGraph(EGraph *E)
{
	int i;
	cout<<"请输入顶点数和边数:";
	cin>>E->Vnum>>E->Enum;
	cout<<"请输入顶点数据:";
	for(i=0;i<E->Vnum;i++)
	{
		cin>>E->V[i];
	}
	cout<<"请输入边:按'始边 终边 权值'的格式\n";
	for(i=0;i<E->Enum;i++)
	{
		cin>>E->E[i][0]>>E->E[i][1]>>E->E[i][2];
	}
}
  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值