Go的数据结构与实现【Graph】

news/2024/5/24 7:30:36

介绍

图是网络结构的表示。现实世界中有大量图谱示例,互联网和社交图谱就是经典示例。图基本上是一组由边连接的节点。

实现

实现思路

图形数据结构将实现这些方法:

AddNode():添加一个节点到图里
AddEdge():添加一条边到图里
Print():打印图结构
图结构定义为:


type Graph struct {sync.RWMutexnodes []*Nodeedges map[Node][]*Node
}

节点定义为:

import "fmt"type T stringtype Node struct {value T
}// Print a node
func (n *Node) Print() string {return fmt.Sprintf("%v", n.value)
}

这里将实现一个无向图,这意味着从A到B添加一条边也会从B到A添加一条边。

func NewGraph() *Graph {g := &Graph{nodes: []*Node{},edges: make(map[Node][]*Node),}return g
}// AddNode adds a node to the graph
func (g *Graph) AddNode(n *Node) {g.Lock()g.nodes = append(g.nodes, n)g.Unlock()
}// AddEdge adds an edge to the graph
func (g *Graph) AddEdge(n1, n2 *Node) {g.Lock()defer g.Unlock()if g.edges == nil {g.edges = make(map[Node][]*Node)}g.edges[*n1] = append(g.edges[*n1], n2)g.edges[*n2] = append(g.edges[*n2], n1)
}// Print whole graph
func (g *Graph) Print() {g.Lock()defer g.Unlock()ret := ""for i := 0; i < len(g.nodes); i++ {ret += g.nodes[i].Print() + " -> "neighborhood := g.edges[*g.nodes[i]]for j := 0; j < len(neighborhood); j++ {ret += neighborhood[j].Print() + " "}ret += "\n"}fmt.Println(ret)
}

单元测试

这是一个测试,运行时将填充图结构并打印:

import "testing"var (nA = &Node{"A"}nB = &Node{"B"}nC = &Node{"C"}nD = &Node{"D"}nE = &Node{"E"}nF = &Node{"F"}
)func InitGraph() *Graph {g := NewGraph()g.AddNode(nA)g.AddNode(nB)g.AddNode(nC)g.AddNode(nD)g.AddNode(nE)g.AddNode(nF)g.AddEdge(nA, nB)g.AddEdge(nA, nC)g.AddEdge(nB, nE)g.AddEdge(nC, nE)g.AddEdge(nE, nF)g.AddEdge(nD, nA)return g
}func TestGraph_Print(t *testing.T) {g := InitGraph()g.Print()
}

输出:

A -> B C D 
B -> A E 
C -> A E 
D -> A 
E -> B C F 
F -> E --- PASS: TestGraph_Print (0.00s)
PASS

遍历

BFS(广度优先搜索)是最广为人知的遍历图的算法之一。从一个节点开始,它首先遍历其所有直接链接的节点,然后处理链接到这些节点的节点,依此类推。

它是使用队列实现的,我们可以用之前实现的队列数据结构来辅助完成这个算法:

// Traverse implements the BFS traversing algorithm
func (g *Graph) Traverse(f func(*Node)) {g.RLock()q := NewNodeQueue()n := g.nodes[0]q.Enqueue(n)visited := make(map[*Node]bool)for {if q.IsEmpty() {break}node, _ := q.Dequeue()visited[node] = truenear := g.edges[*node]for i := 0; i < len(near); i++ {j := near[i]if !visited[j] {q.Enqueue(j)visited[j] = true}}if f != nil {f(node)}}g.RUnlock()
}

我们对算法进行测试:

func TestGraph_Traverse(t *testing.T) {g := InitGraph()g.Traverse(func(n *Node) {fmt.Printf("%v\n", n.value)})
}

输出结果:

A
B
C
D
E
F
--- PASS: TestGraph_Traverse (0.00s)
PASS

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.tangninghui.cn.cn/item-12592.htm

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

基于深度学习的端到端自动驾驶的最新进展:调研综述

基于深度学习的端到端自动驾驶的最新进展&#xff1a;调研综述 附赠自动驾驶学习资料和量产经验&#xff1a;链接 论文链接&#xff1a;https://arxiv.org/pdf/2307.04370.pdf 调研链接&#xff1a;https://github.com/Pranav-chib/ 摘要 本文介绍了基于深度学习的端到端自…

Kubernetes(K8s)技术解析

1. K8s简介 Kubernetes&#xff08;简称K8s&#xff09;是一个开源的容器编排平台&#xff0c;旨在简化容器化应用程序的部署、扩展和管理。为开发者和运维人员提供了丰富的功能和灵活的解决方案&#xff0c;帮助他们更轻松地构建、部署和管理云原生应用程序。以下是关于Kubern…

vue3表单参数校验+正则表达式

这里我们要实现在form表单中对表单项添加参数校验。 校验要求 我们的表单中有用户名、密码、电话号码、邮箱这四个项。 我们设置用户名为3到20位的非空字符 密码为3到25位非空字符 电话号码就用目前用的电话号码正则表达式&#xff0c;要求手机号码以 1 开头&#xff0c;第…

TCP/IP协议、HTTP协议和FTP协议等网络协议包简介

文章目录 一、常见的网络协议二、TCP/IP协议1、TCP/IP协议模型被划分为四个层次2、TCP/IP五层模型3、TCP/IP七层模型 三、FTP网络协议四、Http网络协议1、Http网络协议简介2、Http网络协议的内容3、HTTP请求协议包组成4、HTTP响应协议包组成 一、常见的网络协议 常见的网络协议…

idea改vm参数后没法重启

背景 Idea2023修改了编译器compiler内存&#xff0c;maven的run time内存&#xff0c;idea安装目录下idea64.exe.vmoptions选项的jvm内存参数后导致idea启动时没有任何反应&#xff0c;也没有任何日志输出 idea2023没法重启 导致idea2023没法重启的操作步骤如下 1.修改idea的…

增加网站搜索引擎排名的6个准则

怎样提高网站排名首页 在竞争激烈的网络世界中&#xff0c;网站的排名对于吸引流量和提升曝光至关重要。登上搜索引擎结果页面的首页&#xff0c;意味着更多的曝光和点击率。以下是一些方法&#xff0c;可以帮助您提高网站在搜索引擎中的排名&#xff0c;让其跻身首页&#xf…