diff --git a/diagram/topologic_set.go b/diagram/topologic_set.go index 2373f45..a5e6f53 100644 --- a/diagram/topologic_set.go +++ b/diagram/topologic_set.go @@ -1,54 +1,151 @@ package diagram import ( + "errors" "fmt" + "sync" + + "github.com/gofrs/uuid" ) // Graph represents a topological structure using an adjacency list type Graph struct { - vertices map[string][]string + 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 -// TODO 修改结构为map[uuid][]orm.Topologic -func NewGraph() *Graph { +func NewGraph(root uuid.UUID) *Graph { return &Graph{ - vertices: make(map[string][]string), + rootVertex: root, + freeVertexs: make(map[string]struct{}), + verticeLinks: make(map[string][]uuid.UUID), + backLinks: make(map[string][]uuid.UUID), } } -// AddVertex adds a vertex to the graph -func (g *Graph) AddVertex(vertex string) { - if _, exists := g.vertices[vertex]; !exists { - g.vertices[vertex] = []string{} +// AddNode adds a node to the graph +func (g *Graph) AddNode(vertex string) { + if _, exists := g.verticeLinks[vertex]; !exists { + g.verticeLinks[vertex] = []uuid.UUID{} } } -// AddEdge adds an edge between two vertices -func (g *Graph) AddEdge(from, to string) { - g.AddVertex(from) - g.AddVertex(to) - g.vertices[from] = append(g.vertices[from], to) +// 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() { - for vertex, edges := range g.vertices { + g.RLock() // 读锁 + defer g.RUnlock() + for vertex, edges := range g.verticeLinks { fmt.Printf("%s -> %v\n", vertex, edges) } } -func main() { - graph := NewGraph() +// func main() { +// graph := NewGraph() - // Add vertices 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") +// // 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() -} +// // Print the graph +// graph.PrintGraph() +// }