2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
In der Darstellung der verknüpften Adjazenzliste ist jeder Scheitelpunkt vvgegen Es gibt eine verknüpfte Liste und jeder Knoten in der verknüpften Liste repräsentiert einen Slave vvgegen Startkante.um zu berechnen GTG^TGT, wir müssen durchqueren GGG Für jede Kante von addieren Sie zu, indem Sie die Richtung der Kante umkehren GTG^TGT in der entsprechenden verlinkten Liste.
Go-Sprachimplementierung:
package main
import (
"fmt"
)
// Graph 使用邻接链表表示
type Graph struct {
vertices int
adjList map[int][]int
}
// NewGraph 创建一个新的图
func NewGraph(vertices int) *Graph {
return &Graph{
vertices: vertices,
adjList: make(map[int][]int),
}
}
// AddEdge 添加一条边到图中
func (g *Graph) AddEdge(u, v int) {
g.adjList[u] = append(g.adjList[u], v)
}
// Transpose 计算图的转置
func (g *Graph) Transpose() *Graph {
gT := NewGraph(g.vertices)
for u, adj := range g.adjList {
for _, v := range adj {
gT.AddEdge(v, u) // 反转边的方向
}
}
return gT
}
func main() {
g := NewGraph(4)
g.AddEdge(0, 1)
g.AddEdge(0, 2)
g.AddEdge(1, 2)
g.AddEdge(2, 0)
g.AddEdge(2, 3)
gT := g.Transpose()
fmt.Println("Original Graph:")
for u, adj := range g.adjList {
fmt.Printf("%d -> %vn", u, adj)
}
fmt.Println("nTransposed Graph:")
for u, adj := range gT.adjList {
fmt.Printf("%d -> %vn", u, adj)
}
}
Zeitkomplexität:
In der Darstellung der Adjazenzmatrix verwenden wir ein zweidimensionales Array zum Speichern von Kanteninformationen matrix[u][v]
Gibt an, ob eine Zeile von vorhanden ist uuSie ankommen vvgegen Seite.um zu berechnen GTG^TGT, wir durchqueren das obere Dreieck (oder das untere Dreieck, abhängig von Ihren Matrixdarstellungsgewohnheiten) der Matrix und kehren die Richtung der Kanten um, d. h. matrix[u][v]
Der Wert wird zugewiesenmatrixT[v][u]
。
Go-Sprachimplementierung(Vereinfachte Version, berücksichtigt nur die Existenz und berücksichtigt nicht die Kantengewichte):
// 假设使用二维布尔切片表示邻接矩阵
type GraphMatrix [][]bool
// Transpose 计算图的转置
func (g GraphMatrix) Transpose() GraphMatrix {
n := len(g)
gT := make(GraphMatrix, n)
for i := range gT {
gT[i] = make([]bool, n)
}
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
gT[j][i] = g[i][j] // 反转边的方向
}
}
return gT
}
// 注意:这里没有完整的GraphMatrix类型实现,因为示例仅关注Transpose函数
Zeitkomplexität:
Für einen gerichteten Graphen, der durch eine Adjazenzliste dargestellt wird, können wir die benachbarten Scheitelpunkte jedes Scheitelpunkts zur Adjazenzliste des transponierten Scheitelpunkts des neuen Graphen hinzufügen, indem wir die Adjazenzliste jedes Scheitelpunkts durchlaufen. Konkrete Schritte sind wie folgt:
Zeitkomplexitätsanalyse: Das Durchlaufen jedes Scheitelpunkts des Originaldiagramms erfordert O ( ∣ V ∣ ) O(|V|)Ö(∣V∣) Die zum Durchlaufen der Adjazenzliste jedes Scheitelpunkts erforderliche Zeit beträgt O ( ∣ E ∣ ) O(|E|)Ö(∣E∣) Zeit, also ist die gesamte Zeitkomplexität O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|)Ö(∣V∣+∣E∣)。
Für einen gerichteten Graphen, der durch eine Adjazenzmatrix dargestellt wird, können wir die Adjazenzmatrix eines neuen Graphen erhalten, indem wir die Adjazenzmatrix des ursprünglichen Graphen transponieren. Konkrete Schritte sind wie folgt:
Zeitkomplexitätsanalyse: Das Durchlaufen der Adjazenzmatrix des Originaldiagramms erfordert O ( ∣ V ∣ 2 ) O(|V|^2)Ö(∣V∣2) Zeit, also ist die gesamte Zeitkomplexität O ( ∣ V ∣ 2 ) O(|V|^2)Ö(∣V∣2)。
Das Folgende ist der in der Go-Sprache implementierte Code:
// 邻接链表表示的有向图转置
func transposeAdjList(G map[int][]int) map[int][]int {
GT := make(map[int][]int)
for v, neighbors := range G {
for _, u := range neighbors {
GT[u] = append(GT[u], v)
}
}
return GT
}
// 邻接矩阵表示的有向图转置
func transposeAdjMatrix(G [][]int) [][]int {
n := len(G)
GT := make([][]int, n)
for i := range GT {
GT[i] = make([]int, n)
}
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
GT[j][i] = G[i][j]
}
}
return GT
}
In der Darstellung der verknüpften Adjazenzliste können wir das Originalbild direkt durchlaufen GGGDie Adjazenzliste jedes Knotens wird dann dem neuen Diagramm hinzugefügt, nachdem die Richtung jeder Kante umgekehrt wurde. GTG^{T}GTauf dem entsprechenden Knoten.
type Graph struct {
Vertices []*Node // 存储图中所有节点的指针
}
type Node struct {
Value int
Adjacent []*Node // 存储与该节点相邻的所有节点的指针
}
func (g *Graph) Transpose() *Graph {
transposed := &Graph{make([]*Node, len(g.Vertices))}
for i, node := range g.Vertices {
transposed.Vertices[i] = &Node{node.Value, make([]*Node, 0)}
}
for _, node := range g.Vertices {
for _, adj := range node.Adjacent {
// 将边反向添加到转置图中
transposed.Vertices[adj.Value].Adjacent = append(transposed.Vertices[adj.Value].Adjacent, transposed.Vertices[node.Value])
}
}
return transposed
}
Daher beträgt die Gesamtzeitkomplexität O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|)Ö(∣V∣+∣E∣)。
In der Adjazenzmatrix-Notation können wir eine neue Adjazenzmatrix erstellen und dann das Originalbild durchlaufen GGGAdjazenzmatrix, jedes Element in der Matrix ( ich , j ) ( ich , j )(ichchchch,J)der neuen Matrix zugeordnet (j, ich) (j, ich)(J,ichchchch)Position und vervollständigt damit die Umkehrung der Kante.
type MatrixGraph struct {
Matrix [][]bool // 存储邻接矩阵
}
func (mg *MatrixGraph) Transpose() *MatrixGraph {
transposed := &MatrixGraph{make([][]bool, len(mg.Matrix))}
for i := range mg.Matrix {
transposed.Matrix[i] = make([]bool, len(mg.Matrix))
for j := range mg.Matrix[i] {
// 将边反向赋值到转置矩阵中
transposed.Matrix[i][j] = mg.Matrix[j][i]
}
}
return transposed
}
Daher beträgt die Gesamtzeitkomplexität O ( ∣ V ∣ 2 ) O(|V|^2)Ö(∣V∣2)。
Für die Darstellung der Adjazenz-verknüpften Liste beträgt die zeitliche Komplexität des Transponierungsalgorithmus O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|)Ö(∣V∣+∣E∣)und für die Darstellung der Adjazenzmatrix beträgt die zeitliche Komplexität des Transponierungsalgorithmus O ( ∣ V ∣ 2 ) O(|V|^2)Ö(∣V∣2) .In praktischen Anwendungen gilt: Wenn der Graph relativ dünn besetzt ist (d. h. ∣ E ∣ |E|∣E∣viel kleiner als ∣ V ∣ 2 |V|^2∣V∣2 ), wäre es effizienter, die Adjazenz-verknüpfte Listendarstellung zu verwenden.Wenn der Graph dicht ist (d. h. ∣ E ∣ |E|∣E∣nahe ∣ V ∣ 2 |V|^2∣V∣2), dann ist die Adjazenzmatrixdarstellung möglicherweise angemessener.
Bei der Diagrammdarstellung sind verknüpfte Adjazenzlisten und Adjazenzmatrizen häufig verwendete Methoden. Adjazenzverknüpfte Listen werden zur Darstellung ungerichteter und gerichteter Graphen verwendet, während Adjazenzmatrizen normalerweise zur Darstellung ungerichteter Graphen verwendet werden. Für die Transponierung eines gerichteten Graphen können wir die verknüpfte Adjazenzliste und die Adjazenzmatrix separat bearbeiten.
Für einen gerichteten Graphen, der durch eine verknüpfte Adjazenzliste dargestellt wird, kann die Transponierung des Graphen erreicht werden, indem jeder Scheitelpunkt des Originalgraphen durchlaufen und die ausgehenden Kanten des Originalgraphen in eingehende Kanten umgewandelt werden.
package main
import (
"fmt"
)
// 定义图的顶点结构
type Vertex struct {
Name string
Edges []*Vertex
Visited bool
}
// 计算图的转置
func Transpose(g *Vertex) {
for _, v := range g.Edges {
// 遍历顶点v的所有出边
for _, w := range v.Edges {
// 在原图中查找顶点w指向顶点v的边,并反转
for i, e := range w.Edges {
if e == v {
w.Edges[i] = v
break
}
}
}
}
}
func main() {
// 创建顶点
a := &Vertex{Name: "A"}
b := &Vertex{Name: "B"}
c := &Vertex{Name: "C"}
// 建立有向图关系
a.Edges = []*Vertex{b, c}
b.Edges = []*Vertex{a}
c.Edges = []*Vertex{a}
// 打印原图
fmt.Println("原图:")
PrintGraph(a)
// 计算转置图
Transpose(a)
// 打印转置图
fmt.Println("转置图:")
PrintGraph(a)
}
// PrintGraph 用于打印图的邻接链表表示
func PrintGraph(g *Vertex) {
g.Visited = true
for _, v := range g.Edges {
if !v.Visited {
fmt.Println(g.Name, "->", v.Name)
PrintGraph(v)
}
}
}
Bei einem gerichteten Graphen, der durch eine Adjazenzmatrix dargestellt wird, kann die Transponierung des Graphen erreicht werden, indem jede Zeile des ursprünglichen Graphen in die entsprechende Spalte des neuen Graphen umgewandelt wird.
package main
import (
"fmt"
)
// 计算邻接矩阵的转置
func TransposeMatrix(mat [][]int) [][]int {
transposed := make([][]int, len(mat[0]))
for i := range transposed {
transposed[i] = make([]int, len(mat))
}
for i, row := range mat {
for j, val := range row {
if val == 1 {
transposed[j][i] = 1
}
}
}
return transposed
}
func main() {
// 创建邻接矩阵
originalMatrix := [][]int{
{0, 1, 1},
{0, 0, 1},
{1, 0, 0},
}
// 计算转置矩阵
transposedMatrix := TransposeMatrix(originalMatrix)
// 打印转置矩阵
fmt.Println("转置矩阵:")
for _, row := range transposedMatrix {
fmt.Println(row)
}
}
Für die Transposition einer adjazenzverknüpften Liste beträgt die zeitliche Komplexität des Algorithmus O(E), wobei E die Anzahl der Kanten im Diagramm ist. Dies liegt daran, dass jede Kante einmal durchlaufen werden muss.
Für die Transponierung der Adjazenzmatrix beträgt die zeitliche Komplexität des Algorithmus O(V^2), wobei V die Anzahl der Eckpunkte im Diagramm ist. Dies liegt daran, dass jedes Matrixelement einmal durchlaufen werden muss und die Größe der Matrix V×V beträgt.
Diese Algorithmen sind alle effizient und laufen
Implementierung eines Algorithmus zur Berechnung eines gerichteten Graphen GGG Umsetzung von GTG^{T}GT können wir die beiden Darstellungen der verknüpften Adjazenzliste bzw. der Adjazenzmatrix verarbeiten. Im Folgenden werde ich die Algorithmen für diese beiden Fälle beschreiben und Codebeispiele in der Go-Sprache bereitstellen.
newAdjList
Wird zum Speichern des transponierten Diagramms verwendet.adjList
。(u, v)
, füge es hinzu newAdjList[v]
Mitte.newAdjList
。type Graph struct {
vertices []*Vertex
}
type Vertex struct {
key int
adjacent []*Vertex
}
func (g *Graph) Transpose() *Graph {
gt := &Graph{make([]*Vertex, len(g.vertices))}
for i := range g.vertices {
gt.vertices[i] = &Vertex{key: i}
}
for _, u := range g.vertices {
for _, v := range u.adjacent {
// Add edge (v, u) to the transpose graph.
gt.vertices[v.key].adjacent = append(gt.vertices[v.key].adjacent, gt.vertices[u.key])
}
}
return gt
}
Die Laufzeit dieses Algorithmus beträgt O(|V| + |E|), wobei |V| die Anzahl der Eckpunkte und |E| die Anzahl der Kanten ist. Dies liegt daran, dass wir alle Eckpunkte und Kanten einmal durchlaufen müssen.
newAdjMatrix
Wird zum Speichern des transponierten Diagramms verwendet.adjMatrix
。adjMatrix[i][j]
, weisen Sie es zu newAdjMatrix[j][i]
。newAdjMatrix
。type Graph struct {
matrix [][]bool
}
func (g *Graph) Transpose() *Graph {
gt := &Graph{make([][]bool, len(g.matrix))}
for i := range gt.matrix {
gt.matrix[i] = make([]bool, len(g.matrix))
}
for i := range g.matrix {
for j := range g.matrix[i] {
// Copy the adjacency values with swapped indices.
gt.matrix[j][i] = g.matrix[i][j]
}
}
return gt
}
Die Laufzeit dieses Algorithmus beträgt O(|V|^2), wobei |V| die Anzahl der Eckpunkte ist. Dies liegt daran, dass wir die gesamte Adjazenzmatrix durchlaufen müssen und die Größe der Adjazenzmatrix |V|
Das obige Codebeispiel ist nur der Kernteil des Algorithmus. In tatsächlichen Anwendungen müssen möglicherweise weitere Funktionen wie Fehlerbehandlung, Eingabe und Ausgabe hinzugefügt werden. Darüber hinaus wird zur Vereinfachung des Codes davon ausgegangen, dass es im Diagramm keine wiederholten Kanten gibt und die Scheitelpunktnummern beginnend bei 0 fortlaufend nummeriert sind.
Das Folgende ist ein in der Go-Sprache geschriebener Algorithmus zur Berechnung von G^T aus Diagramm G, und die entsprechenden Darstellungsmethoden für verknüpfte Adjazenzlisten und Adjazenzmatrixen sind ebenfalls angegeben:
package main
import "fmt"
// 图的节点结构体
type Node struct {
Value int // 节点的值
Next *Node // 下一个节点指针
}
// 邻接链表表示法的图结构体
type Graph struct {
Vertices []*Node // 图中所有节点的数组
}
// 添加有向边到邻接链表
func (g *Graph) AddEdge(u, v int) {
newNode := &Node{Value: v}
if g.Vertices[u] == nil {
g.Vertices[u] = newNode
} else {
curr := g.Vertices[u]
for curr.Next != nil {
curr = curr.Next
}
curr.Next = newNode
}
}
// 输出邻接链表表示的图信息
func (g *Graph) Print() {
for i, node := range g.Vertices {
fmt.Printf("顶点 %d:", i)
for node != nil {
fmt.Printf("%d ", node.Value)
node = node.Next
}
fmt.Println()
}
}
// 获取图 G 的转置图 G^T 的邻接链表表示法
func GetTranspose(g *Graph) *Graph {
transpose := &Graph{
Vertices: make([]*Node, len(g.Vertices)),
}
for i, node := range g.Vertices {
for node != nil {
v := node.Value
// 在转置图中添加反向边
transpose.AddEdge(v, i)
node = node.Next
}
}
return transpose
}
// 输出邻接链表表示的转置图信息
func PrintTranspose(g *Graph) {
fmt.Println("转置图 G^T:")
g.Print()
}
// 邻接矩阵表示法的图结构体
type Matrix struct {
Vertices [][]int // 邻接矩阵,存储边的连接关系(0 表示无边,1 表示有边)
}
// 初始化邻接矩阵表示的图
func InitMatrix(numVertices int) *Matrix {
matrix := &Matrix{
Vertices: make([][]int, numVertices),
}
for i := range matrix.Vertices {
matrix.Vertices[i] = make([]int, numVertices)
}
return matrix
}
// 添加有向边到邻接矩阵
func (m *Matrix) AddEdge(u, v int) {
m.Vertices[u][v] = 1
}
// 获取图 G 的转置图 G^T 的邻接矩阵表示法
func GetTransposeMatrix(m *Matrix) *Matrix {
numRows := len(m.Vertices)
numCols := len(m.Vertices[0])
transpose := InitMatrix(numRows)
for i := 0; i < numRows; i++ {
for j := 0; j < numCols; j++ {
if m.Vertices[i][j] == 1 {
// 在转置矩阵中添加反向边
transpose.AddEdge(j, i)
}
}
}
return transpose
}
// 输出邻接矩阵表示的转置图信息
func PrintTransposeMatrix(m *Matrix) {
numRows := len(m.Vertices)
numCols := len(m.Vertices[0])
fmt.Println("转置图 G^T:")
for i := 0; i < numRows; i++ {
fmt.Printf("顶点 %d:", i)
for j := 0; j < numCols; j++ {
if m.Vertices[i][j] == 1 {
fmt.Printf("%d ", j)
}
}
fmt.Println()
}
}
func main() {
// 邻接链表表示的有向图 G
g := &Graph{
Vertices: make([]*Node, 4),
}
g.AddEdge(0, 1)
g.AddEdge(1, 2)
g.AddEdge(2, 3)
g.AddEdge(3, 1)
// 输出原始图 G 的邻接链表表示法
fmt.Println("原始图 G:")
g.Print()
// 获取转置图 G^T 的邻接链表表示法并输出
transpose := GetTranspose(g)
PrintTranspose(transpose)
// 邻接矩阵表示的有向图 G
m := InitMatrix(4)
m.AddEdge(0, 1)
m.AddEdge(1, 2)
m.AddEdge(2, 3)
m.AddEdge(3, 1)
// 输出原始图 G 的邻接矩阵表示法
fmt.Println("原始图 G:")
for _, row := range m.Vertices {
fmt.Println(row)
}
// 获取转置图 G^T 的邻接矩阵表示法并输出
transposeMatrix := GetTransposeMatrix(m)
PrintTransposeMatrix(transposeMatrix)
}
Die zeitliche Komplexität dieses Algorithmus beträgt O(V + E), wobei V die Anzahl der Eckpunkte und E die Anzahl der Kanten ist. Der Konstruktionsprozess des transponierten Diagramms erfordert das Durchlaufen aller Kanten des ursprünglichen Diagramms und das umgekehrte Hinzufügen zum transponierten Diagramm, sodass die Gesamtzeitkomplexität proportional zur Anzahl der Scheitelpunkte und Kanten ist.
Transponierte Graphen gerichteter Graphen können durch zwei Hauptdatenstrukturen dargestellt werden: Adjazenzverknüpfte Listen und Adjazenzmatrizen. Im Folgenden werde ich die Algorithmen in diesen beiden Fällen vorstellen und Beispielcode in der Go-Sprache bereitstellen.
Für einen Graphen, der durch eine verknüpfte Adjazenzliste dargestellt wird, können wir den Graphen transponieren, indem wir die Adjazenzliste jedes Scheitelpunkts durchlaufen und dann jedem Adjazenzpunkt eine umgekehrte Kante hinzufügen. Die zeitliche Komplexität dieser Methode beträgt O(V + E), wobei V die Anzahl der Eckpunkte und E die Anzahl der Kanten ist.
type Vertex struct {
Value int
Adj []Vertex
}
func transposeGraph(graph []Vertex) []Vertex {
transposed := make([]Vertex, len(graph))
for _, v := range graph {
for _, adjV := range v.Adj {
// 为邻接点添加反向边
found := false
for _, tV := range transposed[adjV.Value].Adj {
if tV.Value == v.Value {
found = true
break
}
}
if !found {
transposed[adjV.Value].Adj = append(transposed[adjV.Value].Adj, v)
}
}
}
return transposed
}
Für einen Graphen, der durch eine Adjazenzmatrix dargestellt wird, können wir die Transponierung implementieren, indem wir die Zeilen und Spalten der Matrix vertauschen. Die zeitliche Komplexität dieser Methode beträgt O(V^2).
func transposeMatrix(matrix [][]int) [][]int {
n := len(matrix)
transposed := make([][]int, n)
for i := 0; i < n; i++ {
transposed[i] = make([]int, n)
for j := 0; j < n; j++ {
transposed[i][j] = matrix[j][i]
}
}
return transposed
}
In praktischen Anwendungen hängt die Wahl des zu wählenden Algorithmus von der Sparsität des Diagramms und dem verfügbaren Speicher ab. Bei dünn besetzten Diagrammen können Adjazenzverknüpfungslisten speichereffizienter sein; bei dichten Diagrammen sind Adjazenzmatrizen möglicherweise effizienter.
Einen gerichteten Graphen berechnen G = (V, E) G=(V,E)G=(V,E) Umsetzung von GT = (V, ET) G^T=(V,E^T)GT=(V,ET), können wir entsprechende Algorithmen für die beiden Darstellungsmethoden Adjazenzverknüpfte Liste bzw. Adjazenzmatrix angeben und deren Laufzeit analysieren.
type Edge struct {
dest int
}
type AdjacencyList struct {
edges map[int][]Edge
}
func TransposeGraph(graph AdjacencyList) AdjacencyList {
transposed := AdjacencyList{edges: make(map[int][]Edge)}
for u, neighbors := range graph.edges {
for _, edge := range neighbors {
v := edge.dest
transposed.edges[v] = append(transposed.edges[v], Edge{dest: u})
}
}
return transposed
}
func main() {
// 示例图的邻接链表表示
graph := AdjacencyList{edges: map[int][]Edge{
0: {{dest: 1}},
1: {{dest: 2}},
2: {{dest: 0}},
}}
// 计算转置图
transposedGraph := TransposeGraph(graph)
// 打印转置图的邻接链表
for u, neighbors := range transposedGraph.edges {
fmt.Printf("Node %d -> Nodes: ", u)
for _, edge := range neighbors {
fmt.Printf("%d ", edge.dest)
}
fmt.Println()
}
}
In diesem Code definieren wir a Edge
Struktur zur Darstellung von Kanten und aAdjacencyList
Struktur zur Darstellung einer verknüpften Adjazenzliste.TransposeGraph
Die Funktion akzeptiert aAdjacencyList
Typparameter und gibt eine adjazenzverkettete Listendarstellung seines transponierten Diagramms zurück.existierenmain
Mit dieser Funktion erstellen wir ein Beispieldiagramm, berechnen das transponierte Diagramm und drucken es aus.