图的创建以及遍历

首先图分为有向图和无向图。

我们先来介绍无向图:

无向图定义:若图中所有的边均满足的两个顶点没有次序关系和方向性,即(v1,v2)和(v2,v1)代表同一条边,则称为无向图。

图所示
无向图就是由结点V={1,2,3,4,5},和边E={(1,2),(1,4),(2,3),(3.4),(3,5),(2,5)},构成的。

我们也不难观察到该图是沿着对角线对称的,即如果图的邻接矩阵是沿对角线对称,便可判断是无向图

 

《图的创建以及遍历》

 无向图的一些概念:

1.完全图
若图中n个结点间所有可能的边均存在,即有
C = n*(n-1)/2条边,则称为完全图。也就是说所有点都连上

2.依附  
   边(V1,V2)依附于顶点V1,V2 

3.子图
若G’ 是图G的子图,则有V(G‘)<=V(G),和E(G’)<=E(G)

4.路径
图中从Vp到Vq的一条路径是指由顶点构成的连续序列Vp,Vi1,Vi2,。。。Vin-1
Vin,Vq,其中(Vp,Vi1),(Vi1,Vi2),….(Vin-1,Vin),(Vin,Vq)均为E(G)的边

5.路径长度
路径所含边得数目即为路径的长度

6.简单路径
指路径上除起点和终点可能相同外,其他顶点都不同。

7.回路和环
起点和终点为同一顶点的简单路径称为回路或环。

8.连通
若从V1到V2有路径可通,则称顶点V1和顶点V2是连通的。

9.连通图
图中任意两个结点都有路径相通,称为连通图a,b,c都是连通图
10.非连通图
只要有两个结点无路径相通,则称为非连通图。 
11。度  
 指无向图中顶点V相关的边得个数 

下面我们来看一下无向图创建的代码:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct node
{
	int nVertex;
	int nEdge;
	int *pMatrix;
}Graph;

Graph *CreateGraph()
{
	Graph *pGraph = NULL;
	pGraph = (Graph*)malloc(sizeof(Graph));

	int nV;
	int nE;

	printf("请输入顶点的个数 和 边数:\n");
	scanf("%d%d",&nV,&nE);

	pGraph->nVertex = nV;
	pGraph->nEdge = nE;

	//根据顶点个数 申请矩阵
	pGraph->pMatrix = (int*)malloc(sizeof(int)*nV*nV);
	memset(pGraph->pMatrix,0,sizeof(int)*nV*nV);

	//根据边的条数 放置边
	int i;
	int v1,v2;

	for(i = 1;i<=nE;i++)
	{
		printf("输入两个顶点确定一条边:\n");
		scanf("%d%d",&v1,&v2);

		if(v1>=1 && v1 <= nV && v2>=1&& v2<= nV && pGraph->pMatrix[(v1-1)*nV + (v2-1)] == 0)
		{
			pGraph->pMatrix[(v1-1)*nV + (v2-1)] = 1;
			pGraph->pMatrix[(v2-1)*nV + (v1-1)] = 1;
		}
		else
		{
			i--;
		}
	}

	return pGraph;
}

    我大概解释一下图的创建的代码

首先我们需要申请一个矩阵,矩阵的大小为图中点的个数的平方,接下来就将用户输入的相应的顶点的位置变为1,因为矩阵实际上在内存里是一段连续的地址空间,所以对应位置需要我们计算出来,(x-1)*顶点个数+(y-1),我们还应该注意的是,如果在循环中没有进入if语句中,还要把i–,保证能边的个数

二,有向图
若图中边得两个顶点存在次序关系和方向性,即 <V1,V2>和 <V2,V1>代表两条不同的边则称为有向图。

图a所示的有向图就是由结点V={1,2,3,4}和边E={<1,2>,<1,3>,<3,4>,<4,1>}构成

《图的创建以及遍历》

1.完全图
若图中结点间n个有可能的边均存在,即Pn=n*(n-1)条边,称为完全图。
2。依附
边<V1,V2>依附于顶点V1于顶点V2
3。路径
图中从Vp到Vq的一条路径是指由顶点构成的连续序列Vp,Vi1,Vi2,。。。Vin-1
Vin,Vp,其中<Vp,Vi1>,<Vi1,Vi2>,….<Vin-1,Vin>,<Vin,Vq>均为E(G)上的有向边。
4. 强连通
如果每个相异成对顶点Vi和Vj都同时有从Vi到Vj和从Vj到Vi的路径,则称该有向图为强连通。
5.强连通分量
即有向图中的极大强连通子图
6.入度
顶点V的入度是指以V为终点有向边得个数
7.出度
顶点V的出度是指以V为起点有向边的个数。

小结:
1.无向图邻接矩阵的第i行或第i列非0元素的个数其实就是第i个顶点的度
2.有向图邻接矩阵的第i行非0元素的个数其实就是第i个顶点的出度,而第i列非0元素的个数是第i个顶点的入度,即第i个顶点的度是第i行和第i列非0元素个数之和
3.区分无向图和有向图的3个依据是:
(1)  图中各边无箭头的是无向图,边有箭头的是有向图
(2)  图中各边采用()来描述的是无向图,采用<>来描述的是有向图
(3)  图的邻接矩阵若以对角线为对称,若无特别声明就是无向图,不对称的则是有向图。
4.邻接矩阵和邻接表的区别在于:
(1)从空间存储来讲,邻接矩阵适用于边很多的图,邻接表则适用于边不多的图。
(2)从数据结构上讲,邻接矩阵对于图来说是唯一的,而邻接表并不唯一

 

图的遍历
    一。图的深度优先遍历(DFS)
    二。图的广度优先遍历(BFS)

深度优先搜索(DFS)
深度优先搜索在搜索过程中访问某个顶点后,需要递归地访问此顶点的所有未访问过的相邻顶点。
选择一个作为起始顶点,按照如下步骤遍历:
a. 选择起始顶点,申请一个标记数组,将标记数组初始化为0
b. 从该顶点的邻接顶点中选择一个,继续这个过程(即再寻找邻接结点的邻接结点),一直深入下去,直到一个顶点没有邻接结点了,并将标记数组相应位置变为1
c.继续如上操作,如果所有邻接结点往下都访问过了,

代码如下

void MyDFS(Graph *pGraph,int nBegin,int *pMark)
{
	//打印 标记
	printf("%d ",nBegin);
	pMark[nBegin-1] = 1;

	//遍历与当前顶点相关顶点
	int i;
	for(i = 0;i < pGraph->nVertex;i++)
	{
		//相关的 且 未被标记的
		if(pGraph->pMatrix[(nBegin-1)*pGraph->nVertex + i] == 1 && pMark[i] == 0)
		{
			MyDFS(pGraph,i+1,pMark);
		}
	}
}

void DFS(Graph *pGraph,int nBegin)
{
	if(pGraph == NULL )return;

	//申请标记数组
	int *pMark = NULL;
	pMark = (int *)malloc(sizeof(int)*pGraph->nVertex);
	memset(pMark,0,sizeof(int)*pGraph->nVertex);

	MyDFS(pGraph,nBegin,pMark);
	free(pMark);
	pMark = NULL;
}

 首先需要申请一个标记数组,用来标记打印过的顶点,在这里使用的是循环+递归的方法进行遍历,

广度优先搜索(BFS)
广度优先搜索在进一步遍历图中顶点之前,先访问当前顶点的所有邻接结点。
a .首先选择一个顶点作为起始结点,申请一个标记数组
b. 将起始结点放入队列中。
c. 从队列首部选出一个顶点,并找出所有与之邻接的结点,将找到的邻接结点放入队列尾部,将已访问过结点进行标记,
d. 按照同样的方法处理队列中的下一个结点。

代码如下

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

typedef struct node3
{
	int nValue;
	struct node3 *pNext;
}MyQueue;

typedef struct node4
{
	int nCount;
	MyQueue *pHead;
	MyQueue *pTail;
}Queue;

void q_Init(Queue **pQueue)
{
	*pQueue = (Queue*)malloc(sizeof(Queue));
	(*pQueue)->pHead = NULL;
	(*pQueue)->pTail = NULL;
	(*pQueue)->nCount = 0;
}

void q_Push(Queue *pQueue,int nNum)
{
	if(pQueue == NULL)return;

	MyQueue *pTemp = NULL;
	pTemp = (MyQueue*)malloc(sizeof(MyQueue));
	pTemp->nValue = nNum;
	pTemp->pNext = NULL;

	if(pQueue->pHead == NULL)
	{
		pQueue->pHead = pTemp;
	}
	else
	{
		pQueue->pTail->pNext = pTemp;
	}
	pQueue->pTail = pTemp;
	pQueue->nCount++;
}

int q_Pop(Queue *pQueue)
{
	if(pQueue == NULL || pQueue->nCount == 0)return -1;

	MyQueue *pDel = NULL;
	int nNum;
	pDel = pQueue->pHead;
	nNum = pDel->nValue;

	pQueue->pHead = pQueue->pHead->pNext;
	free(pDel);
	pDel = NULL;

	pQueue->nCount--;
	if(pQueue->nCount == 0)
	{
		pQueue->pTail = NULL;
	}
	return nNum;
}

int q_IsEmpty(Queue *pQueue)
{
	if(pQueue == NULL)return -1;
	return pQueue->nCount ? 0:1;
}

typedef struct node
{
	int nVertex;
	int nEdge;
	int *pMatrix;
}Graph;

Graph *CreateGraph()
{
	Graph *pGraph = NULL;
	pGraph = (Graph*)malloc(sizeof(Graph));

	int nV;
	int nE;

	printf("请输入顶点的个数 和 边数:\n");
	scanf("%d%d",&nV,&nE);

	pGraph->nVertex = nV;
	pGraph->nEdge = nE;

	//根据顶点个数 申请矩阵
	pGraph->pMatrix = (int*)malloc(sizeof(int)*nV*nV);
	memset(pGraph->pMatrix,0,sizeof(int)*nV*nV);

	//根据边的条数 放置边
	int i;
	int v1,v2;

	for(i = 1;i<=nE;i++)
	{
		printf("输入两个顶点确定一条边:\n");
		scanf("%d%d",&v1,&v2);

		if(v1>=1 && v1 <= nV && v2>=1&& v2<= nV && pGraph->pMatrix[(v1-1)*nV + (v2-1)] == 0)
		{
			pGraph->pMatrix[(v1-1)*nV + (v2-1)] = 1;
			pGraph->pMatrix[(v2-1)*nV + (v1-1)] = 1;
		}
		else
		{
			i--;
		}
	}

	return pGraph;
}


void BFS(Graph *pGraph ,int nBegin)
{
	if(pGraph == NULL)return;

	//辅助队列
	Queue *pQueue = NULL;
	q_Init(&pQueue);

	//标记数组
	int *pMark = NULL;
	pMark = (int*)malloc(sizeof(int)*pGraph->nVertex);
	memset(pMark,0,sizeof(int)*pGraph->nVertex);

	// 入队 标记
	q_Push(pQueue,nBegin);
	pMark[nBegin-1] = 1;

	while(!q_IsEmpty(pQueue))
	{
		//弹出
		nBegin = q_Pop(pQueue);
		printf("%d ",nBegin);

		//将其未被标记的 有关联的顶点入队 
		int i;
		for(i = 0;i<pGraph->nVertex;i++)
		{
			if(pGraph->pMatrix[(nBegin-1)*pGraph->nVertex + i] == 1 && pMark[i] == 0)
			{
				//入队 标记
				q_Push(pQueue,i+1);
				pMark[i] = 1;
			}
		}
	}
}

int main()
{
	Graph *pGraph = NULL;
	pGraph = CreateGraph();
	BFS(pGraph,1);
	return 0;
}

 

 

    原文作者:数据结构之图
    原文地址: https://blog.csdn.net/aaa_cainiao_66666/article/details/81510327
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞