Go语言 大话数据结构——图

1、名词解释:

  • 图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。在图中的数据元素,我们称之为顶点(Vertex),顶点集合有穷非空。在图中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边集可以是空的。

  • 图按照边的有无方向分为无向图和有向图。无向图由顶点和边组成,有向图由顶点和弧构成。弧有弧尾和弧头之分,带箭头一端为弧头。

  • 图按照边或弧的多少分稀疏图和稠密图。如果图中的任意两个顶点之间都存在边叫做完全图,有向的叫有向完全图。若无重复的边或顶点到自身的边则叫简单图。

  • 图中顶点之间有邻接点、依附的概念。无向图顶点的边数叫做度。有向图顶点分为入度和出度。

  • 图上的边或弧带有权则称为网。

  • 图中顶点间存在路径,两顶点存在路径则说明是连通的,如果路径最终回到起始点则称为环,当中不重复的叫简单路径。若任意两顶点都是连通的,则图就是连通图,有向则称为强连通图。图中有子图,若子图极大连通则就是连通分量,有向的则称为强连通分量。

  • 无向图中连通且n个顶点n-1条边称为生成树。有向图中一顶点入度为0其余顶点入度为1的叫有向树。一个有向图由若干棵有向树构成生成森林。

2、图的存储结构—-邻接矩阵

图的邻接矩阵的表示方式需要两个数组来表示图的信息,一个一维数组表示每个数据元素的信息,一个二维数组(邻接矩阵)表示图中的边或者弧的信息。

如果图有n个顶点,那么邻接矩阵就是一个n*n的方阵,方阵中每个元素的值的计算公式如下: 
这里写图片描述

邻接矩阵表示图的具体示例如下图所示:

首先给个无向图的实例:

这里写图片描述

下面是一个有向图的实例: 
这里写图片描述

OK,到这里为止,我们给出一个无向图的邻接矩阵和一个有向图的邻接矩阵,我们可以从这两个邻接矩阵得出一些结论:

  • 无向图的邻接矩阵都是沿对角线对称的
  • 要知道无向图中某个顶点的度,其实就是这个顶点vi在邻接矩阵中第i行或(第i列)的元素之和;
  • 对于有向图,要知道某个顶点的出度,其实就是这个顶点vi在邻接矩阵中第i行的元素之和,如果要知道某个顶点的入度,那就是第i列的元素之和。

但是,如果我们需要表示的图是一个网的时候,例如假设有个图有n个顶点,同样该网的邻接矩阵也是一个n*n的方阵,只是方阵元素的值的计算方式不同,如下图所示: 
这里写图片描述

这里的wij表示两个顶点vi和vj边上的权值。无穷大表示一个计算机允许的、大于所有边上权值的值,也就是一个不可能的极限值。下面是具体示例,表示的一个有向网的图和邻接矩阵:

这里写图片描述

这里写图片描述

实例代码:

package main

import (
	"fmt"
)

type VertexType string //定义顶点的数据类型
type EdgeType int      //边的类型
const MAXVEX = 100     //最大的顶点数
const MAXVALUE = 65535 //无效数 (无穷大,也就是说此边不同)

type MGraph struct {
	vexs           [MAXVEX]VertexType  //定义一个数组,保存对应的顶点,可以保存65535个顶点
	arc            [MAXVEX][MAXVEX]int //定义一个二维数组,保存顶点对应的边,二维数组可以保存[65535][65535]
	numVer, numEdg int                 //边的数量,顶点的数量
	isTrav         [MAXVEX] bool       //设定某个节点是否遍历过,主要用于节点的遍历
	GType          byte                //定义图的类型,0:无向图  1:有向图
}

/*
	创建图:
*/
func createMGraph(mg *MGraph) {

	fmt.Println("请输入顶点数:")
	fmt.Scan(&mg.numVer)
	for i := 0; i < mg.numVer; i++ {
		fmt.Printf("请输入第%d个顶点:\n", i+1)
		var tempChar VertexType
		fmt.Scan(&tempChar)
		mg.vexs[i] = tempChar
		//fmt.Print("\n输入的内容为:", mg.vexs[i])

	}
	//顶点组成边,初始化
	for i := 0; i < mg.numVer; i++ {
		for j := 0; j < mg.numVer; j++ {
			mg.arc[i][j] = MAXVALUE

		}

	}
	fmt.Println("请输入边数:")
	fmt.Scan(&mg.numEdg)
	for i := 0; i < mg.numEdg; i++ {
		//fmt.Println("请分别输入坐标E(i,j)以及权重")
		fmt.Printf("请输入第%d条边的坐标E(i,j)以及权重\n",i+1)
		var i, j, weight int
		fmt.Scan(&i)
		fmt.Scan(&j)
		fmt.Scan(&weight)
		mg.arc[i][j] = weight
		if mg.GType == 0 {
			mg.arc[j][i] = weight //无向图:数据依据对角线对称
		}

		//fmt.Printf("输入的权重为:%d", mg.arc[i][j])
	}

	/*for i := 0; i < mg.numVer; i++ {
		for j := i; j < mg.numVer; j++ {
			fmt.Println("----------")
			fmt.Println(mg.arc[i][j])
			//fmt.Println(mg.arc[j][i])
		}
	}

	for i := 0; i < mg.numEdg; i++ {
		fmt.Println(mg.vexs[i])
	}*/
}

/*
	清空图:1)清空边对应的权重   2)清空顶点组成的数组
*/
func ClearGraph(mg *MGraph) {
	for i := 0; i < mg.numVer; i++ {
		for j := 0; j < i; j++ {
			mg.arc[i][j] = MAXVALUE
		}
	}
	for i := 0; i < mg.numVer; i++ {
		mg.vexs[i] = ""
	}
}
func ShowGraph(mg *MGraph) {
	fmt.Println()
	for i := 0; i < mg.numVer; i++ {
		fmt.Printf("\t\t%s", mg.vexs[i])
	}
	fmt.Println()
	for i := 0; i < mg.numVer; i++ {
		fmt.Printf("%s\t\t", mg.vexs[i])
		for j := 0; j < mg.numVer; j++ {
			if mg.arc[i][j] == MAXVALUE {
				fmt.Printf("%s\t\t", "Z")
			} else {
				fmt.Printf("%d\t\t", mg.arc[i][j])
			}
		}
		fmt.Println()
	}

}

/*
图的遍历:遍历图就是逐个访问图中的所有节点
深度优先遍历算法思想:
1)从数组isTrav中选择一个未被遍历的顶点V(Vi),将其标记为true,表示已经访问过。
2)从Vi的一个未被访问的邻接点出发进行深度优先遍历;
3)重复 2),直至图中的所用和Vi有路径相通的顶点都被访问过。
4)重复1)-3)的操作,直到图中所用节点都被访问过
*/

/*
	fun:从第 n个节点开始,深度遍历图
*/
func DeepTraOne(mg *MGraph, n int) {
	mg.isTrav[n] = true
	fmt.Print("---->",mg.vexs[n])
	for i:=0;i<mg.numVer;i++{
		if mg.arc[n][i]!=MAXVALUE&&mg.isTrav[n]!=true {
			DeepTraOne(mg,i)
		}
	}
}
/*
	fun:通过 DeepTraOne()函数,遍历所有的节点
*/
func DeepTraGraph(mg *MGraph)  {
	//清除遍历标志位
	for i:=0;i<mg.numVer;i++{
		mg.isTrav[i]=false
	}

	for i:=0;i<mg.numVer;i++{
		if mg.isTrav[i]==false {
			DeepTraOne(mg,i)
		}
	}
	fmt.Println()

}
func main() {

	mg := MGraph{}
	createMGraph(&mg)
	ShowGraph(&mg)
	fmt.Println("遍历图:")
	DeepTraGraph(&mg)

}

运行效果:

注:图的类型没有设置,默认为无向图。如果要设置,添加   mg.GType=1即可。

猜你喜欢

转载自blog.csdn.net/weixin_42117918/article/details/81983286