技術共有

Wen Xin Yi Yan VS iFlytek Spark VS chatgpt (300) -- アルゴリズム入門 22.1 4 つの質問

2024-07-12

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

4. 複数の写真を与える G = ( V , E ) G = ( V , E )=(,)隣接リンク リスト (マルチグラフは、繰り返しエッジと自己ループ エッジを許可するグラフです)、時間を与えてください。 O ( V + E ) O(V + E)(+)グラフの「等価な」無向グラフを計算するために使用されるアルゴリズム G ′ = ( V , E ′ ) G^{'}=(V,E^{'})=(,)隣接リンクリストで表されます。ここ E ′ E^{'}そうなる EE自己ループ エッジ内の冗長エッジと削除後の残りのエッジ。残りのエッジを削除するとは、2 つのノード間の複数のエッジを 1 つのエッジに置き換えることを指します。コードを書きたい場合は、go 言語を使用してください。

ウェン・シンの言葉:

隣接リンクリスト表現

隣接リンクリスト表現では、各頂点は vv リンク リストがあり、リンク リスト内の各ノードがスレーブを表します。 vv スタートエッジ。計算するために うわーT、横断する必要があります GG の各エッジに対して、エッジの方向を反転して、に追加します。 うわーT 対応するリンクリストにあります。

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

時間の複雑さ

  • 各エッジを横断する時間計算量は次のとおりです。 O ( E ) O(E)()、で EE エッジの数です。
  • 各エッジに対して、定数時間操作 (別のグラフの隣接リストに追加) を実行します。
  • したがって、合計時間計算量は次のようになります。 O ( E ) O(E)()

隣接行列表現

隣接行列表現では、エッジ情報を格納するために 2 次元配列を使用します。 matrix[u][v] からの行があるかどうかを示します。 うぅあなた 到着 vv 側。計算するために うわーT、行列の上の三角形 (行列表現の習慣に応じて、下の三角形) をトラバースし、エッジの方向を反転します。 matrix[u][v] 値が割り当てられるのは、matrixT[v][u]

Go言語の実装(簡易バージョン。存在のみを考慮し、エッジの重みは考慮しません):

// 假设使用二维布尔切片表示邻接矩阵
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

時間の複雑さ

  • 行列の各要素を反復処理するには、 O ( V 2 ) O(V^2)(2) 時間、そのうち VV 頂点の数です。
  • したがって、合計時間計算量は次のようになります。 O ( V 2 ) O(V^2)(2) 。頂点の数がエッジの数よりはるかに多い場合、これは最も効率的ではない可能性があります。

ここに画像の説明を挿入します

ここに画像の説明を挿入します

ここに画像の説明を挿入します

ここに画像の説明を挿入します

iFlytek スパーク:

隣接リストによって表される有向グラフの場合、各頂点の隣接リストをトラバースすることによって、各頂点の隣接頂点を新しいグラフの転置された頂点の隣接リストに追加できます。具体的な手順は次のとおりです。

  1. 新しい隣接リストを作成する GTG^{T}T、空に初期化されます。
  2. 元の画像をトラバースする GG のすべての頂点 vv
  3. 頂点をトラバースする vv 隣接リンク リスト、各隣接頂点 うぅあなた 新しい画像に追加 GTG^{T}T 中間頂点 vv 隣接リンクリスト内。
  4. 新しい画像に戻る GTG^{T}T

時間計算量分析: 元のグラフの各頂点を横断するには、 O ( ∣ V ∣ ) O(|V|)() 各頂点の隣接リストを走査するのに必要な時間は次のとおりです。 O ( ∣ E ∣ ) O(|E|)() したがって、合計時間計算量は次のようになります。 O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|)(+)

隣接行列で表される有向グラフの場合、元のグラフの隣接行列を転置することで新しいグラフの隣接行列を取得できます。具体的な手順は次のとおりです。

  1. サイズを指定して新しいものを作成する ∣ V ∣ × ∣ V ∣ |V| 倍 |V|× マトリックス GTG^{T}T、すべてゼロの行列に初期化されます。
  2. 元の画像の隣接行列を走査します。 GG、意思 G [ i ] [ j ] G[i][j][][じゅう] 値が割り当てられるのは、 GT [ j ] [ i ] G^{T}[j][i]T[じゅう][]
  3. 新しいグラフの隣接行列を返します。 GTG^{T}T

時間計算量分析: 元のグラフの隣接行列を走査するには、 O ( ∣ V ∣ 2 ) O(|V|^2)(2) したがって、合計時間計算量は次のようになります。 O ( ∣ V ∣ 2 ) O(|V|^2)(2)

以下は 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 のインテリジェントな頭脳:

隣接リンクリスト表現

隣接リンクリスト表現では、元の画像を直接走査できます。 GG次に、各エッジの方向を反転した後、各ノードの隣接リストが新しいグラフに追加されます。 GTG^{T}T対応するノード上で。

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
時間計算量の分析:
  • 元のグラフの各ノードを走査します。 O ( ∣ V ∣ ) O(|V|)()
  • 各ノードの隣接リストを調べます。 O ( ∣ E ∣ ) O(|E|)()

したがって、合計時間計算量は次のようになります。 O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|)(+)

隣接行列の表記法

隣接行列表記では、新しい隣接行列を作成し、元の画像を走査することができます。 GG隣接行列、行列内の各要素 ( 私 、 j ) ( 私 、 j )(,じゅう)新しいマトリックスに割り当てられる ( j , i ) ( j , i ) の(じゅう,)位置を調整し、エッジの反転を完了します。

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
時間計算量の分析:
  • 新しい隣接行列を作成します。 O ( ∣ V ∣ 2 ) O(|V|^2)(2)
  • 元のイメージの隣接行列を走査します。 O ( ∣ V ∣ 2 ) O(|V|^2)(2)

したがって、合計時間計算量は次のようになります。 O ( ∣ V ∣ 2 ) O(|V|^2)(2)

要約する

隣接リンク リスト表現の場合、転置アルゴリズムの時間計算量は次のようになります。 O ( ∣ V ∣ + ∣ E ∣ ) O(|V| + |E|)(+)、隣接行列表現の場合、転置アルゴリズムの時間計算量は次のようになります。 O ( ∣ V ∣ 2 ) O(|V|^2)(2) 。実際のアプリケーションでは、グラフが比較的まばらな場合 (つまり、 ∣ E ∣ |E|よりもはるかに小さい ∣ V ∣ 2 |V|^22 )、隣接リンク リスト表現を使用する方が効率的です。グラフが密な場合 (つまり、 ∣ E ∣ |E|近く ∣ V ∣ 2 |V|^22) の場合、隣接行列表現の方が適切である可能性があります。

知恵のスペクトルの明確な言葉:

グラフ表現では、隣接リンク リストと隣接行列の両方が一般的に使用される方法です。隣接リンク リストは無向グラフと有向グラフを表すために使用されますが、隣接行列は通常、無向グラフを表すために使用されます。有向グラフの転置では、隣接リンク リストと隣接行列を個別に操作できます。

隣接リンクリストの転置

隣接リンクリストによって表される有向グラフの場合、グラフの転置は、元のグラフの各頂点をトラバースし、元のグラフの出力エッジを入力エッジに変更することによって実現できます。

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

隣接行列の転置

隣接行列で表される有向グラフの場合、元のグラフの各行を新しいグラフの対応する列に変換することで、グラフの転置を実現できます。

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

アルゴリズム実行時間分析

  1. 隣接リンク リストの転置の場合、アルゴリズムの時間計算量は O(E) です。ここで、E はグラフ内のエッジの数です。これは、各エッジを 1 回横断する必要があるためです。

  2. 隣接行列の転置の場合、アルゴリズムの時間計算量は O(V^2) です。ここで、V はグラフ内の頂点の数です。これは、各行列要素を 1 回走査する必要があり、行列のサイズが V×V であるためです。
    これらのアルゴリズムはすべて効率的で実行されます。

天宮:

有向グラフを計算するアルゴリズムを実装するには GG の転置 GTG^{T}T 、隣接リンク リストと隣接行列の 2 つの表現をそれぞれ処理できます。以下では、これら 2 つの場合のアルゴリズムをそれぞれ説明し、Go 言語でのコード例を示します。

隣接リンクリスト表現

アルゴリズムのステップ:
  1. 新しい隣接リストを作成する newAdjList 転置されたグラフを保存するために使用されます。
  2. 元のイメージの隣接リンク リストを走査します。 adjList
  3. 各エッジごとに (u, v)に追加します newAdjList[v] 真ん中。
  4. 新しい隣接リストを返します。 newAdjList
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
実行時間分析:

このアルゴリズムの実行時間は O(|V| + |E|) です。ここで、|V| は頂点の数、|E| はエッジの数です。これは、すべての頂点とエッジを一度走査する必要があるためです。

隣接行列の表記法

アルゴリズムのステップ:
  1. 新しい隣接マトリックスを作成する newAdjMatrix 転置されたグラフを保存するために使用されます。
  2. 元の画像の隣接行列を走査します。 adjMatrix
  3. 要素ごとに adjMatrix[i][j]に割り当てます newAdjMatrix[j][i]
  4. 新しい隣接行列を返します。 newAdjMatrix
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
実行時間分析:

このアルゴリズムの実行時間は O(|V|^2) です。ここで、|V| は頂点の数です。これは、隣接行列全体を走査する必要があり、隣接行列のサイズが |V| x |V| であるためです。

上記のコード例はアルゴリズムのコア部分にすぎません。実際のアプリケーションでは、エラー処理、入出力などの他の機能を追加する必要がある場合があります。また、コードを簡略化するために、グラフ内に繰り返しエッジはなく、頂点番号は 0 から始まる連続した番号が付けられていると仮定します。

チャットポイント:

以下は、グラフ G から G^T を計算するために Go 言語で書かれたアルゴリズムであり、対応する隣接リンク リストと隣接行列の表現方法も示されています。

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

このアルゴリズムの時間計算量は O(V + E) です。ここで、V は頂点の数、E はエッジの数です。転置グラフの構築プロセスでは、元のグラフのすべてのエッジをたどり、それらを転置グラフに逆に追加する必要があるため、合計の時間の複雑さは頂点とエッジの数に比例します。

キミ:

有向グラフの転置グラフは、隣接リンク リストと隣接行列という 2 つの主要なデータ構造で表すことができます。以下では、これら 2 つの場合のアルゴリズムをそれぞれ紹介し、Go 言語のサンプルコードを提供します。

隣接リンクリスト表現

隣接リンク リストで表されるグラフの場合、各頂点の隣接リストを走査し、各隣接点に逆エッジを追加することで、グラフを転置できます。この方法の時間計算量は O(V + E) です。ここで、V は頂点の数、E はエッジの数です。

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

隣接行列表現

隣接行列で表されるグラフの場合、行列の行と列を交換することで転置を実装できます。この方法の時間計算量は O(V^2) です。

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

アルゴリズムの分析

  • 隣接リスト : アルゴリズムは各頂点の隣接リストをトラバースする必要があり、エッジごとに、隣接点の隣接リストに逆エッジを追加する必要があります。隣接リストの平均長が k の場合、アルゴリズムの時間計算量は O(V + E * k) です。最悪の場合、k は V に近くなり、時間計算量は O(V^2) に近くなります。最良の場合、k は 1 に近く、時間計算量は O(E) に近くなります。
  • 隣接行列 : アルゴリズムは行列の各要素を調べて、行と列を交換する必要があります。行列は VxV なので、時間計算量は O(V^2) です。

実際のアプリケーションでは、どのアルゴリズムを選択するかは、グラフのスパース性と利用可能なメモリによって決まります。疎なグラフの場合は、隣接リンク リストの方がメモリ効率が高く、密なグラフの場合は、隣接行列の方が効率的である可能性があります。

フンユアン:

有向グラフを計算するには G = ( V , E ) G = ( V , E )=(,) の転置 GT = ( V 、 ET ) G^T = ( V 、 E^T )T=(,T), 隣接リンク リストと隣接行列の 2 つの表現方法にそれぞれ対応するアルゴリズムを与え、その実行時間を分析できます。

隣接リンクリスト表現

アルゴリズムの説明
  1. 空の隣接リストを初期化して、転置されたグラフのエッジを保存します。
  2. 元の画像をトラバースする GG すべてのノードの。
  3. 各ノードごとに うぅあなた、隣接リスト内のすべての隣接ノードを走査します。 vv
  4. 新しい隣接リストを次から追加します vv 到着 うぅあなた 側。
  5. トラバーサルが完了すると、新しい隣接リンク リストは転置されたグラフになります。 うわーT
実行時間分析
  • 時間計算量: O ( ∣ E ∣ ) O(|E|)()、で ∣ E ∣ |E| 元の画像の辺の数です。各エッジを 2 回 (読み取りで 1 回、書き込みで 1 回) トラバースする必要があるためです。

隣接行列の表記法

アルゴリズムの説明
  1. 元のグラフと同じサイズの隣接行列を初期化して、転置されたグラフのエッジを格納します。
  2. 元の画像をトラバースする GG 隣接行列。
  3. 行列内のすべての非ゼロ要素に対して (つまり、エッジが存在します) ( u , v ) (u , v)(あなた,))、転置グラフの隣接行列内の対応する位置 ( v , u ) ( v , u ) (v , u )(,あなた) ゼロ以外の要素に設定します。
  4. 走査が完了すると、新しい隣接行列は転置されたグラフになります。 うわーT
実行時間分析
  • 時間計算量: O ( ∣ V ∣ 2 ) O(|V|^2)(2)、で ∣ V ∣ |V| 元のグラフ内のノードの数です。隣接行列全体を走査する必要があるためです。

Go言語実装(隣接リンクリスト表現)

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

このコードでは、 Edge エッジを表す構造と、AdjacencyList 隣接リンクリストを表す構造。TransposeGraph この関数は、AdjacencyList type パラメータを使用して、転置されたグラフの隣接リンク リスト表現を返します。存在するmain 関数を使用して、グラフの例を作成し、その転置グラフを計算して印刷します。