Compartilhamento de tecnologia

Wen Xin Yi Yan VS iFlytek Spark VS chatgpt (300) - Introdução aos Algoritmos 22.1 4 perguntas

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

4. Dadas várias fotos G = ( V , E ) G=(V,E)G=(V,E)lista vinculada de adjacência (multigrafo é um gráfico que permite arestas repetidas e arestas com loop automático), forneça um tempo de O ( V + E ) O(V+E)O(V+E)algoritmo, usado para calcular o gráfico não direcionado "equivalente" do gráfico G ′ = ( V , E ′ ) G^{'}=(V,E^{'})G=(V,E) representado por uma lista vinculada de adjacência.aqui E ′ E^{'}ESerá EEE As arestas redundantes e as arestas restantes após a exclusão das arestas de auto-loop. A remoção de arestas restantes refere-se à substituição de múltiplas arestas entre dois nós por uma aresta. Se você quiser escrever código, use a linguagem go.

Palavras de Wen Xin:

Representação de lista vinculada de adjacência

Na representação de lista vinculada de adjacência, cada vértice vvvocêocêocêocêocêocêocêocêocêocê Existe uma lista vinculada e cada nó na lista vinculada representa um escravo vvvocêocêocêocêocêocêocêocêocêocê Borda inicial.para calcular GTG^TGE, precisamos percorrer GGG para cada aresta de e invertendo a direção da aresta, adicione a GTG^TGE na lista vinculada correspondente.

Implementação da linguagem Go

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)
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

complexidade de tempo

  • A complexidade de tempo para percorrer cada aresta é O ( E ) O(E)O(E),em EEE é o número de arestas.
  • Para cada aresta, realizamos uma operação de tempo constante (adicionando à lista de adjacências de outro grafo).
  • Portanto, a complexidade total do tempo é O ( E ) O(E)O(E)

Representação da matriz de adjacência

Na representação da matriz de adjacência, usamos um array bidimensional para armazenar informações de arestas, onde matrix[u][v] Indica se existe uma linha de uuvocê chegar vvvocêocêocêocêocêocêocêocêocêocê lado.para calcular GTG^TGE, atravessamos o triângulo superior (ou triângulo inferior, dependendo de seus hábitos de representação matricial) da matriz e invertemos a direção das arestas, ou seja, matrix[u][v] O valor é atribuído amatrixT[v][u]

Implementação da linguagem Go(Versão simplificada, considera apenas existência e não considera pesos de aresta):

// 假设使用二维布尔切片表示邻接矩阵
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函数
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

complexidade de tempo

  • Iterar sobre cada elemento da matriz requer O ( V 2 ) O(V^2)O(V2) tempo, entre os quais VVV é o número de vértices.
  • Portanto, a complexidade total do tempo é O ( V 2 ) O(V^2)O(V2) . Isto pode não ser o mais eficiente quando o número de vértices é muito maior que o número de arestas.

Insira a descrição da imagem aqui

Insira a descrição da imagem aqui

Insira a descrição da imagem aqui

Insira a descrição da imagem aqui

iFlytek Spark:

Para um grafo direcionado representado por uma lista de adjacências, podemos adicionar os vértices adjacentes de cada vértice à lista de adjacências do vértice transposto do novo grafo, percorrendo a lista de adjacências de cada vértice. As etapas específicas são as seguintes:

  1. Crie uma nova lista de adjacências GTG^{T}GE, inicializado como vazio.
  2. Percorra a imagem original GGG cada vértice de vvvocêocêocêocêocêocêocêocêocêocê
  3. Atravessar vértices vvvocêocêocêocêocêocêocêocêocêocê lista vinculada de adjacência, cada vértice adjacente uuvocê Adicionar à nova imagem GTG^{T}GE vértice médio vvvocêocêocêocêocêocêocêocêocêocê na lista vinculada de adjacência.
  4. Voltar para a nova foto GTG^{T}GE

Análise de complexidade de tempo: percorrer cada vértice do gráfico original requer O ( ∣ V ∣ ) O(|V|)O(V) O tempo necessário para percorrer a lista de adjacências de cada vértice é O ( ∣ E ∣ ) O(|E|)O(E) tempo, então a complexidade total do tempo é O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|)O(V+E)

Para um grafo direcionado representado por uma matriz de adjacência, podemos obter a matriz de adjacência de um novo grafo transpondo a matriz de adjacência do grafo original. As etapas específicas são as seguintes:

  1. Crie um novo com tamanho ∣ V ∣ × ∣ V ∣ |V| vezes |V|V×V matriz GTG^{T}GE, inicializado para uma matriz totalmente zero.
  2. Percorra a matriz de adjacência da imagem original GGG,Vai G [ eu ] [ j ] G[i][j]G[eu][eu] O valor é atribuído a GT [ j ] [ eu ] G^{T}[j][i]GE[eu][eu]
  3. Retorna a matriz de adjacência do novo gráfico GTG^{T}GE

Análise de complexidade de tempo: percorrer a matriz de adjacência do gráfico original requer O ( ∣ V ∣ 2 ) O(|V|^2)O(V2) tempo, então a complexidade total do tempo é O ( ∣ V ∣ 2 ) O(|V|^2)O(V2)

A seguir está o código implementado na linguagem Go:

// 邻接链表表示的有向图转置
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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

360 Cérebro Inteligente:

Representação de lista vinculada de adjacência

Na representação de lista vinculada de adjacência, podemos percorrer diretamente a imagem original GGGA lista de adjacências de cada nó é então adicionada ao novo gráfico após inverter a direção de cada aresta. GTG^{T}GEno nó correspondente.

Implementação do código da linguagem Go:
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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
Análise de complexidade de tempo:
  • Percorra cada nó no gráfico original: O ( ∣ V ∣ ) O(|V|)O(V)
  • Percorra a lista de adjacências de cada nó: O ( ∣ E ∣ ) O(|E|)O(E)

Portanto, a complexidade total do tempo é O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|)O(V+E)

Notação de matriz de adjacência

Na notação de matriz de adjacência, podemos criar uma nova matriz de adjacência e então percorrer a imagem original GGGmatriz de adjacência, cada elemento da matriz ( eu , j ) ( eu, j)(eu,eu)atribuído à nova matriz ( j , eu ) (j, eu)(eu,eu)posição, completando assim a inversão da aresta.

Implementação do código da linguagem Go:
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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
Análise de complexidade de tempo:
  • Crie uma nova matriz de adjacência: O ( ∣ V ∣ 2 ) O(|V|^2)O(V2)
  • Percorra a matriz de adjacência da imagem original: O ( ∣ V ∣ 2 ) O(|V|^2)O(V2)

Portanto, a complexidade total do tempo é O ( ∣ V ∣ 2 ) O(|V|^2)O(V2)

Resumir

Para a representação de lista vinculada de adjacência, a complexidade de tempo do algoritmo de transposição é O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|)O(V+E), e para a representação da matriz de adjacência, a complexidade de tempo do algoritmo de transposição é O ( ∣ V ∣ 2 ) O(|V|^2)O(V2) .Em aplicações práticas, se o gráfico for relativamente esparso (ou seja, ∣ E ∣ |E|Emuito menor que ∣ V ∣ 2 |V|^2V2 ), seria mais eficiente usar a representação de lista vinculada de adjacência.Se o gráfico for denso (ou seja, ∣ E ∣ |E|Eaproximar ∣ V ∣ 2 |V|^2V2), então a representação da matriz de adjacência pode ser mais apropriada.

Palavras claras do espectro da sabedoria:

Na representação gráfica, listas vinculadas de adjacência e matrizes de adjacência são métodos comumente usados. Listas vinculadas de adjacência são usadas para representar grafos não direcionados e direcionados, enquanto matrizes de adjacência são geralmente usadas para representar grafos não direcionados. Para a transposição de um grafo direcionado, podemos operar na lista vinculada de adjacência e na matriz de adjacência separadamente.

Transposição de lista vinculada de adjacência

Para um grafo direcionado representado por uma lista vinculada de adjacência, a transposição do grafo pode ser alcançada atravessando cada vértice do grafo original e modificando as arestas de saída do grafo original em arestas de entrada.

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)
		}
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

Transposição da matriz de adjacência

Para um gráfico direcionado representado por uma matriz de adjacência, a transposição do gráfico pode ser alcançada transformando cada linha do gráfico original na coluna correspondente do novo gráfico.

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)
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

Análise do tempo de execução do algoritmo

  1. Para a transposição de uma lista vinculada de adjacência, a complexidade de tempo do algoritmo é O(E), onde E é o número de arestas no grafo. Isso ocorre porque cada aresta precisa ser percorrida uma vez.

  2. Para a transposição da matriz de adjacência, a complexidade de tempo do algoritmo é O(V^2), onde V é o número de vértices no gráfico. Isso ocorre porque cada elemento da matriz precisa ser percorrido uma vez e o tamanho da matriz é V×V.
    Esses algoritmos são todos eficientes e executados

Tiangong:

Para implementar um algoritmo para calcular um gráfico direcionado GGG transposição de GTG^{T}GE , podemos processar as duas representações da lista vinculada de adjacência e da matriz de adjacência, respectivamente. Abaixo descreverei os algoritmos para esses dois casos, respectivamente, e fornecerei exemplos de código na linguagem Go.

Representação de lista vinculada de adjacência

Etapas do algoritmo:
  1. Crie uma nova lista de adjacências newAdjList Usado para armazenar o gráfico transposto.
  2. Percorra a lista vinculada de adjacência da imagem original adjList
  3. para cada borda (u, v), adicione-o a newAdjList[v] meio.
  4. Retorna a nova lista de adjacências newAdjList
Exemplo de código de idioma Go:
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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
Análise do tempo de execução:

O tempo de execução deste algoritmo é O(|V| + |E|), onde |V| é o número de vértices e |E| é o número de arestas. Isso ocorre porque precisamos percorrer todos os vértices e arestas uma vez.

Notação de matriz de adjacência

Etapas do algoritmo:
  1. Crie uma nova matriz de adjacência newAdjMatrix Usado para armazenar o gráfico transposto.
  2. Percorra a matriz de adjacência da imagem original adjMatrix
  3. para cada elemento adjMatrix[i][j], atribua-o a newAdjMatrix[j][i]
  4. Retorna a nova matriz de adjacência newAdjMatrix
Exemplo de código de idioma Go:
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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
Análise do tempo de execução:

O tempo de execução deste algoritmo é O(|V|^2), onde |V| é o número de vértices. Isso ocorre porque precisamos percorrer toda a matriz de adjacência, e o tamanho da matriz de adjacência é |V| x |V|.

O exemplo de código acima é apenas a parte central do algoritmo. Em aplicações reais, outras funções, como tratamento de erros, entrada e saída, podem precisar ser adicionadas. Além disso, para simplificar o código, assume-se que não há arestas repetidas no gráfico e os números dos vértices são numerados consecutivamente a partir de 0.

bate-papogpt:

A seguir está um algoritmo escrito em linguagem Go para calcular G ^ T do gráfico G, e a lista vinculada de adjacência correspondente e os métodos de representação da matriz de adjacência também são fornecidos:

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)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164

A complexidade de tempo deste algoritmo é O(V + E), onde V é o número de vértices e E é o número de arestas. O processo de construção do grafo transposto requer percorrer todas as arestas do grafo original e adicioná-las ao grafo transposto ao contrário, de forma que a complexidade total do tempo seja proporcional ao número de vértices e arestas.

Kimi:

Gráficos transpostos de gráficos direcionados podem ser representados por duas estruturas de dados principais: listas vinculadas de adjacência e matrizes de adjacência. Abaixo apresentarei os algoritmos nesses dois casos, respectivamente, e fornecerei código de exemplo na linguagem Go.

Representação de lista vinculada de adjacência

Para um gráfico representado por uma lista vinculada de adjacência, podemos transpor o gráfico percorrendo a lista de adjacência de cada vértice e então adicionando uma aresta reversa a cada ponto de adjacência. A complexidade de tempo deste método é O(V + E), onde V é o número de vértices e E é o número de arestas.

Código de amostra da linguagem Go:
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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

Representação da matriz de adjacência

Para um gráfico representado por uma matriz de adjacência, podemos implementar a transposta trocando as linhas e colunas da matriz. A complexidade de tempo deste método é O(V^2).

Código de amostra da linguagem Go:
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
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

Análise de Algoritmos

  • lista de adjacências : O algoritmo precisa percorrer a lista de adjacências de cada vértice e, para cada aresta, uma aresta reversa precisa ser adicionada à lista de adjacências do ponto adjacente. Se o comprimento médio da lista de vizinhos for k, a complexidade de tempo do algoritmo é O(V + E * k). Na pior das hipóteses, k pode estar próximo de V e a complexidade do tempo é próxima de O(V^2). Na melhor das hipóteses, k está próximo de 1 e a complexidade de tempo está próxima de O(E).
  • matriz de adjacência : O algoritmo precisa passar por cada elemento da matriz e trocar as linhas e colunas. Como a matriz é VxV, a complexidade do tempo é O(V^2).

Em aplicações práticas, qual algoritmo escolher depende da dispersão do gráfico e da memória disponível. Para gráficos esparsos, listas vinculadas de adjacência podem ser mais eficientes em termos de memória; para gráficos densos, matrizes de adjacência podem ser mais eficientes;

Huyuan:

Para calcular um gráfico direcionado G = ( V , E ) G=(V,E)G=(V,E) transposição de GT = ( V , ET ) G^T=(V,E^T)GE=(V,EE), podemos fornecer algoritmos correspondentes para os dois métodos de representação de lista vinculada de adjacência e matriz de adjacência, respectivamente, e analisar seu tempo de execução.

Representação de lista vinculada de adjacência

Descrição do algoritmo
  1. Inicialize uma lista de adjacências vazia para armazenar as arestas do grafo transposto.
  2. Percorra a imagem original GGG de todos os nós.
  3. para cada nó uuvocê, percorre todos os nós vizinhos em sua lista de adjacências vvvocêocêocêocêocêocêocêocêocêocê
  4. Adicione uma nova lista de adjacências de vvvocêocêocêocêocêocêocêocêocêocê chegar uuvocê lado.
  5. Depois de completar a travessia, a nova lista vinculada de adjacência é o grafo transposto GTG^TGE
Análise de tempo de execução
  • complexidade de tempo: O ( ∣ E ∣ ) O(|E|)O(E),em ∣ E ∣ |E|E é o número de lados da imagem original. Porque precisamos percorrer cada aresta duas vezes (uma para ler e outra para escrever).

Notação de matriz de adjacência

Descrição do algoritmo
  1. Inicialize uma matriz de adjacência do mesmo tamanho do gráfico original para armazenar as arestas do gráfico transposto.
  2. Percorra a imagem original GGG matriz de adjacência.
  3. Para cada elemento diferente de zero na matriz (ou seja, há uma aresta ( você , v ) ( você, v)(você,vocêocêocêocêocêocêocêocêocêocê)), posição correspondente na matriz de adjacência do grafo transposto (v, você) (v, você)(vocêocêocêocêocêocêocêocêocêocê,você) Defina como um elemento diferente de zero.
  4. Após completar o percurso, a nova matriz de adjacência é o grafo transposto GTG^TGE
Análise de tempo de execução
  • complexidade de tempo: O ( ∣ V ∣ 2 ) O(|V|^2)O(V2),em ∣ V ∣ |V|V é o número de nós no gráfico original. Porque precisamos percorrer toda a matriz de adjacência.

Implementação da linguagem Go (representação de lista vinculada adjacente)

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()
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

Neste código, definimos um Edge estrutura para representar arestas, e umaAdjacencyList Estrutura para representar uma lista vinculada de adjacência.TransposeGraph A função aceita umAdjacencyList parâmetro de tipo e retorna uma representação de lista vinculada de adjacência de seu gráfico transposto.existirmain função, criamos um gráfico de exemplo, calculamos e imprimimos seu gráfico transposto.