modelRT/diagram/topologic_set.go

152 lines
3.5 KiB
Go
Raw Normal View History

package diagram
import (
"errors"
"fmt"
"sync"
"github.com/gofrs/uuid"
)
// Graph represents a topological structure using an adjacency list
type Graph struct {
sync.RWMutex
// 根节点
rootVertex uuid.UUID
// 游离节点
freeVertexs map[string]struct{}
verticeLinks map[string][]uuid.UUID
// 存储多个上级节点同时指向同一下级节点的情况,key为下级节点,value为上级节点集合
backLinks map[string][]uuid.UUID
}
// NewGraph creates a new graph
func NewGraph(root uuid.UUID) *Graph {
return &Graph{
rootVertex: root,
freeVertexs: make(map[string]struct{}),
verticeLinks: make(map[string][]uuid.UUID),
backLinks: make(map[string][]uuid.UUID),
}
}
// AddNode adds a node to the graph
func (g *Graph) AddNode(vertex string) {
if _, exists := g.verticeLinks[vertex]; !exists {
g.verticeLinks[vertex] = []uuid.UUID{}
}
}
// CreateBackLink adds a node to the graph
func (g *Graph) CreateBackLink(vertex string) {
if _, exists := g.backLinks[vertex]; !exists {
g.backLinks[vertex] = []uuid.UUID{}
}
}
// AddEdge adds an edge between two verticeLinks
func (g *Graph) AddEdge(from, to uuid.UUID) {
g.Lock()
defer g.Unlock()
fromKey := from.String()
toKey := to.String()
g.CreateBackLink(toKey)
g.backLinks[toKey] = append(g.backLinks[toKey], from)
g.AddNode(fromKey)
g.AddNode(toKey)
g.verticeLinks[fromKey] = append(g.verticeLinks[fromKey], to)
// 创建新的拓扑信息时,如果被链接的点已经存在于游离节点中
// 则将其移除
if _, exist := g.freeVertexs[toKey]; exist {
delete(g.freeVertexs, toKey)
}
}
// DelNode delete a node to the graph
func (g *Graph) DelNode(vertex string) error {
childNodes, exists := g.verticeLinks[vertex]
if exists {
if len(childNodes) > 1 {
return errors.New("delete node failed,that vertex contains more than one child node")
}
delete(g.verticeLinks, vertex)
}
parentNodes, exists := g.backLinks[vertex]
if exists {
if len(parentNodes) > 1 {
return errors.New("delete node failed,that vertex contains more than one parent node")
}
delete(g.backLinks, vertex)
} else {
return errors.New("that vertex don't have parent node")
}
return nil
}
// DelEdge delete an edge between two verticeLinks
func (g *Graph) DelEdge(from, to uuid.UUID) error {
g.Lock()
defer g.Unlock()
toKey := to.String()
var fromKeys []uuid.UUID
if _, exist := g.backLinks[toKey]; exist {
fromKeys = g.backLinks[toKey]
} else {
fromKeys = []uuid.UUID{from}
}
childvertex := g.verticeLinks[toKey]
err := g.DelNode(toKey)
if err != nil {
return fmt.Errorf("delete edge failed: %w", err)
}
for _, fromUUID := range fromKeys {
fromKey := fromUUID.String()
var delIndex int
for index, vertex := range g.verticeLinks[fromKey] {
if vertex == to {
delIndex = index
}
}
vertex := g.verticeLinks[fromKey]
copy(vertex[delIndex:], vertex[delIndex+1:])
vertex = vertex[:len(vertex)-1]
g.verticeLinks[fromKey] = vertex
}
fromKey := from.String()
g.verticeLinks[fromKey] = append(g.verticeLinks[fromKey], childvertex...)
return nil
}
// PrintGraph prints the graph in adjacency list format
func (g *Graph) PrintGraph() {
g.RLock() // 读锁
defer g.RUnlock()
for vertex, edges := range g.verticeLinks {
fmt.Printf("%s -> %v\n", vertex, edges)
}
}
// func main() {
// graph := NewGraph()
// // Add verticeLinks and edges
// graph.AddEdge("A", "B")
// graph.AddEdge("A", "C")
// graph.AddEdge("B", "D")
// graph.AddEdge("C", "D")
// graph.AddEdge("C", "E")
// graph.AddEdge("E", "F")
// // Print the graph
// graph.PrintGraph()
// }