基本的图运算

本文涉及的产品
无影云电脑企业版,8核16GB 120小时 1个月
轻量应用服务器 2vCPU 4GiB,适用于搭建Web应用/小程序
轻量应用服务器 2vCPU 4GiB,适用于网站搭建
简介: 【5月更文挑战第7天】这段内容描述了一个图数据结构的实现,包括`Graph`和`Vertex`结构体。`Graph`包含顶点字典,顶点数和边数,顶点合边的操作。`Vertex`结构为邻接关系管理有ID、邻接关系、颜色、距离等属性,并能添加、删除邻接点。

1 图

图算法多种多样种,任何一种算法都有应用的适合场景。 它常见的应用场景是社交网络,金融风险,网络安全,网页排序、社群发现和计算最短路径等等。

以下是一个基本图计算的函数的实现。

  • 包括以下属性,

    我们定义一个图,它的大小最大

    var (
      max_size = 65535个边 
      )
    
  • 属性:

          Vertices  顶点总数
          NumVertices  顶点总数
          NumEdge  边总数
    

函数, 将顶点vert 加入图中,addEdge(fromVert,toVert) 添加有向边:

        AddVertex(vert) 
  • 函数, 添加带优先级的有向边

          AddEdge(fromVert, toVert, weight)
    

函数,查找名称为 vKey 的顶点,getVertices() 返回图中所有顶点列表

        GetVertex(vKey)  

函数,按照vert in graph 的语句形式,返回顶点是否在图中 true/false

因此结构体为:

    type Graph struct {
        Vertices    map[string]*Vertex
        NumVertices int
        NumEdge     int
    }
  • 顶点结构为:

     type Vertex struct {
          Id          string
          ConnectedTo map[string]int
          Color       string
          Dist        int
          Pred        string
          Disc        int
          Fin         int
      }
    

添加顶点, 并返回被添加的顶点

        func (gp *Graph) AddVertex(key string) *Vertex {
            if gp.NumEdge >= max_size {
                panic("too much edge or vertex.")
            }
            gp.NumVertices += 1
            NewVertex := MakeVertex(key)
            gp.Vertices[key] = NewVertex
            return NewVertex
        }

获取顶点信息

    func (gp *Graph) GetVertex(key string) *Vertex {
        return gp.Vertices[key]
    }

顶点是否存在该图中,通过顶点id判断

    func (gp *Graph) Contains(key string) bool {
        return gp.Vertices[key] != nil
    }

添加顶点到图中。使用顶点结构体的方法,添加邻接边

    func (gp *Graph) AddEdge(start, end string, cost int) {

        var nv *Vertex
        if !gp.Contains(start) {
            nv = gp.AddVertex(start)
        }

        if !gp.Contains(end) {
            nv = gp.AddVertex(end)
        }

        rst := gp.Vertices[start].AddNeighbor(gp.Vertices[end], cost)
        if rst {
            gp.NumEdge += 1
        }

    }

获取顶点名称的 列表集, 和值集

    func (gp *Graph) GetVertices() ([]string, []*Vertex) {
        var keys []string
        var vers []*Vertex
        for k, v := range gp.Vertices {
            keys = append(keys, k)
            vers = append(vers, v)
        }
        return keys, vers
    }

2 图的顶点

添加顶点邻居,顶点对象一个字典的key,设置边和权重信息

func (vt *Vertex) AddNeighbor(nbr *Vertex, weight int) bool {

    if nbr == nil {
        return false
    }
    if vt.ConnectedTo[nbr.Id] != 0 {
        return false
    }
    vt.ConnectedTo[nbr.Id] = weight

    return true
}

移除该顶点的一个邻接顶点

func (vt *Vertex) DelNeighbor(nbr *Vertex) {
    delete(vt.ConnectedTo, nbr.Id)
}

设置颜色 设置距离 前置 时间 完成点

func (vt *Vertex) SetColor(color string) {
    vt.Color = color
}




func (vt *Vertex) SetDistance(d int) {
    vt.Dist = d
}



func (vt *Vertex) SetPred(p string) {
    vt.Pred = p
}



func (vt *Vertex) SetDiscovery(dtime int) {
    vt.Disc = dtime
}



func (vt *Vertex) SetFinish(ftime int) {
    vt.Fin = ftime
}



func (vt *Vertex) GetFinish(ftime int) int {
    return vt.Fin
}

获取检测 前置 权重,成本 顶点颜色

func (vt *Vertex) GetDiscovery() int {
    return vt.Disc
}



func (vt *Vertex) GetPred() string {
    return vt.Pred
}



func (vt *Vertex) GetDistance() int {
    return vt.Dist
}



func (vt *Vertex) GetColor() string {
    return vt.Color
}

返回该顶点的连接的全部key,@param item = key 返回全部key

func (vt *Vertex) GetConnections(item string) []int {
    var keys []string
    var vts []int
    for k, v := range vt.ConnectedTo {
        keys = append(keys, k)
        vts = append(vts, v)
    }
    return vts

}

返回该顶点边的 全部 权重信息

func (vt *Vertex) GetAllWeights(nbrKey string) []int {
    var weights []int
    for _, w := range vt.ConnectedTo {
        weights = append(weights, w)
    }
    return weights
}

返回该顶点到某个边的信息

func (vt *Vertex) GetWeight(nbrKey string) int {
    return vt.ConnectedTo[nbrKey]
}

返回该顶点的基本信息

func (vt *Vertex) GetStr(nbr string) string {
    return fmt.Sprintf("%v:color:%v:disc:%v:fin:%v:dist:%v:connect and weight info:%v:pred:%v",
        vt.Id, vt.Color, vt.Disc, vt.Fin, vt.Dist, vt.ConnectedTo, vt.Pred)
}

返回该顶点的ID

func (vt *Vertex) GetId() string {
    return vt.Id
}

3 使用图计算类

首先添加两个顶点,然后设置顶点1的 权重成本 2,

再重复添加该顶点1 到顶点2 的成本1

新增从顶点1 一条边 到顶点3 成本2

新增 顶点1 添加一条边 到顶点4 成本1

新增顶点2 添加一条边 到顶点3 成本2

新增顶点2 添加一条边 到顶点4 成本3

新增 顶点3 添加一条边 到顶点4 成本4

新增 顶点2 添加一条边 到顶点1 成本2

设置顶点3 距离为4

设置顶点2 距离为3

显示基本信息:

 顶点总数:%v, 边总数:%v, \n顶点1的信息:%v", Gp.NumVertices, Gp.NumEdge, Gp.GetVertex 

此时该图应该有4个顶点,7个边。 如下所示:

image.png

然后删除顶点1的一条到顶点2的边,那么还剩下 6条边。

完整代码如下:

func TestSetup(t *testing.T) {

Gp := MakeGraph()
Gp.AddVertex(fmt.Sprintf("%v", 1))
Gp.AddVertex(fmt.Sprintf("%v", 2))

Gp.Vertices[fmt.Sprintf("%v", 1)].SetDistance(2)

//顶点1 添加一条边 到顶点2 成本1
Gp.AddEdge(fmt.Sprintf("%v", 1), fmt.Sprintf("%v", 2), 1)
//重复添加一条边 到顶点2
Gp.AddEdge(fmt.Sprintf("%v", 1), fmt.Sprintf("%v", 2), 1)
//添加一条边 到顶点3  成本2
Gp.AddEdge(fmt.Sprintf("%v", 1), fmt.Sprintf("%v", 3), 2)
//顶点1 添加一条边 到顶点4  成本1
Gp.AddEdge(fmt.Sprintf("%v", 1), fmt.Sprintf("%v", 4), 1)
//顶点2 添加一条边 到顶点3  成本2
Gp.AddEdge(fmt.Sprintf("%v", 2), fmt.Sprintf("%v", 3), 2)
//顶点2 添加一条边 到顶点4  成本3
Gp.AddEdge(fmt.Sprintf("%v", 2), fmt.Sprintf("%v", 4), 3)
//顶点3 添加一条边 到顶点4  成本4
Gp.AddEdge(fmt.Sprintf("%v", 3), fmt.Sprintf("%v", 4), 4)
//顶点2 添加一条边 到顶点1  成本2
Gp.AddEdge(fmt.Sprintf("%v", 2), fmt.Sprintf("%v", 1), 2)

//设置顶点3 距离为4
Gp.Vertices[fmt.Sprintf("3")].SetDistance(4)
//设置顶点2 距离为3
Gp.Vertices[fmt.Sprintf("2")].SetDistance(3)  

if Gp.NumVertices != 4 || Gp.NumEdge != 7 {
    t.Fatalf("vertices number should be 4, have:%v, edge number should be 7   have:%v \n", Gp.NumVertices, Gp.NumEdge)
}

vert := Gp.GetVertex(fmt.Sprintf("1"))

new_color := "blcak"
vert.SetColor(new_color)

if nc := vert.GetColor(); nc != new_color {
    t.Fatalf("color set fail hope:%v, have:%v \n", new_color, nc)
}

//删除
vert.DelNeighbor(Gp.GetVertex(fmt.Sprintf("2")))
Gp.NumEdge -= 1
if Gp.NumVertices != 4 || Gp.NumEdge != 6 {
    t.Fatalf("vertices number should be 4, have:%v, edge number should be 7   have:%v \n", Gp.NumVertices, Gp.NumEdge)
}

4 小结:

完成基本图的使用,可以帮助我们理解矩阵服务。图计算现在也是一门利用人工智能提取、理解、解析、总结学习现实世界中的事物关联的技术。

完整代码如下连接:

github.com/hahamx/utools/utils/queues/Graph

目录
相关文章
|
计算机视觉 Python
解决 NoneType‘ object has no attribute ‘astype’ 问题
解决 NoneType‘ object has no attribute ‘astype’ 问题
349 0
|
11月前
|
人工智能 安全 Cloud Native
|
监控 druid Java
干掉Druid?揭秘HikariCP为何如此迅猛
【8月更文挑战第18天】在Java应用开发中,数据库连接池作为提升数据库访问性能的关键组件,其重要性不言而喻。长期以来,Druid以其强大的监控、扩展性和稳定性,在业界赢得了广泛的认可与应用。然而,近年来,一个名为HikariCP的轻量级连接池逐渐崭露头角,以其惊人的速度和低资源消耗,挑战着Druid的霸主地位。今天,我们就来深入探讨,HikariCP为何能够如此迅速地“干掉”传统连接池,成为新的性能标杆。
599 4
|
消息中间件 Linux 测试技术
【xenomai3内核解析】系列文章大纲
该博客系列详细解析了Linux实时操作系统框架Xenomai,包括实时操作系统的概念、Linux为何非实时、嵌入式实时Linux方案等。内容涵盖Xenomai内核构建、组件结构、源码介绍、实时性测试及接口应用。此外,深入探讨了双核基石IPipe、系统调用、时间子系统、任务管理、同步与互斥、内存管理、信号处理、实时IPC、POSIX IPC、实时驱动模型RTDM、Rtnet、用户态实时库libcobalt和实时性能优化等方面。适合对Linux实时系统感兴趣的读者学习研究。
400 0
【xenomai3内核解析】系列文章大纲
|
JavaScript 前端开发
新建全局代码片段==》输入自定义文件名称
要在文本编辑器中创建和使用自定义代码片段,请按照以下步骤操作:首先通过设置菜单进入用户代码片段选项,并新建一个全局代码片段文件,输入自定义文件名。随后,在新创建的文件中定义代码片段,包括指定片段名称、适用范围、触发前缀、代码主体及描述。例如,“myscript”片段可设置前缀为“myscript”,并在各类文件中自动生成`<script>`标签。通过这种方式,可以快速插入常用的代码结构,提高编程效率。
107 1
|
开发框架 网络架构 开发者
【Uniapp 专栏】Uniapp 高级特性的深入探索与应用
【5月更文挑战第16天】Uniapp是一款跨平台开发框架,提供条件编译(针对不同平台优化)、动态路由(运行时动态管理)、分包机制(提升加载速度)和状态管理(结合Vuex优化数据流)等高级特性。它支持组件化开发和国际化,助力创建高效、创新应用,满足复杂业务需求,提升用户体验。随着技术进步,Uniapp将继续引入更多优秀特性。
349 1
【Uniapp 专栏】Uniapp 高级特性的深入探索与应用
|
消息中间件 监控 数据管理
构建强大的分布式系统:微服务与架构设计的关键考虑因素
构建强大的分布式系统需要深思熟虑的架构设计和关键考虑因素。微服务架构作为一种实现分布式系统的方式,提供了许多优势,但也伴随着挑战。通过合理的服务边界定义、通信协议选择、数据管理与一致性、容错性与监控、部署和自动化以及安全性措施,可以更好地构建和维护分布式系统。最终,成功的分布式系统将为用户提供高可用性、可伸缩性和灵活性的应用程序体验。
810 1
构建强大的分布式系统:微服务与架构设计的关键考虑因素
|
消息中间件 负载均衡 监控
基于kafka项目之Keepalived高可用详细介绍
基于kafka项目之Keepalived高可用详细介绍
|
存储 缓存 监控
构建高效的Java缓存策略
【4月更文挑战第18天】本文探讨了如何构建高效的Java缓存策略,强调缓存可提升系统响应和吞吐量。关键因素包括缓存位置、粒度、失效与更新策略、并发管理、序列化及选择合适库(如Ehcache、Guava Cache、Caffeine)。最佳实践包括明确需求、选择合适解决方案、监控调整及避免常见陷阱。缓存优化是一个持续过程,需根据需求变化不断优化。
259 5

热门文章

最新文章