图算法 Graph Dijkstra Prim

Dijkstra's Algorithm(迪杰斯特拉算法)是一种图论算法,由荷兰计算机科学家Edsger W. Dijkstra于1956年提出。它用于解决单源最短路径问题,即在带权重的有向图中,找到从给定源节点到其他所有节点的最短路径。该算法适用于无负权重边的图。

Dijkstra's Algorithm的基本思想是贪心算法,它从源节点开始,每次选择与当前已知最短路径集合相邻的具有最小权重边的节点,并更新这些节点的最短路径长度。这个过程重复进行,直到找到从源节点到所有其他节点的最短路径。

Dijkstra's Algorithm的基本步骤如下:

创建一个集合S,用于存储已确定最短路径的节点。
创建一个距离数组dist,存储从源节点到其他各个节点的最短路径长度。初始化源节点的距离为0,其他节点的距离为无穷大(表示尚未找到路径)。
当集合S中未包含所有节点时:
a. 从尚未处理的节点中选取距离最小的节点u(不在S中)。
b. 将节点u加入集合S。
c. 遍历u的所有邻接节点v。如果通过u到v的路径比当前已知的从源节点到v的路径更短,更新dist[v]。
当算法结束时,距离数组dist包含了从源节点到图中所有其他节点的最短路径长度。如果需要找到实际的路径,可以在算法过程中记录每个节点的前驱节点,并在最后通过回溯前驱节点来找到完整的路径。

Dijkstra's Algorithm在时间复杂度方面较高。使用优先队列来优化查找距离最小的节点时,算法的时间复杂度为O(|V|^2),其中|V|表示图中节点的数量。对于稀疏图,可以通过使用二叉堆、斐波那契堆等高级数据结构将时间复杂度降低到O(|V|log|V| + |E|),其中|E|表示图中边的数量。

struct Graph {
    let vertices: Int
    var adjacencyList: [[(Int, Int)]]

    init(vertices: Int) {
        self.vertices = vertices
        adjacencyList = Array(repeating: [], count: vertices)
    }

    mutating func addEdge(_ source: Int, _ destination: Int, _ weight: Int) {
        adjacencyList[source].append((destination, weight))
    }
}

func dijkstra(graph: Graph, source: Int) -> [Int] {
    var distances = Array(repeating: Int.max, count: graph.vertices)
    distances[source] = 0

    var visited = Array(repeating: false, count: graph.vertices)
    for _ in 0..<graph.vertices {
        var minDistance = Int.max
        var minIndex = -1

        for index in 0..<graph.vertices {
            if !visited[index] && distances[index] < minDistance {
                minDistance = distances[index]
                minIndex = index
            }
        }

        guard minIndex != -1 else { break }

        visited[minIndex] = true
        for (neighbor, weight) in graph.adjacencyList[minIndex] {
            let newDistance = distances[minIndex] + weight
            if newDistance < distances[neighbor] {
                distances[neighbor] = newDistance
            }
        }
    }

    return distances
}
var graph = Graph(vertices: 5)

graph.addEdge(0, 1, 10)
graph.addEdge(0, 2, 5)
graph.addEdge(1, 3, 1)
graph.addEdge(1, 2, 2)
graph.addEdge(2, 1, 3)
graph.addEdge(2, 3, 9)
graph.addEdge(2, 4, 2)
graph.addEdge(3, 4, 4)
graph.addEdge(4, 3, 6)
graph.addEdge(4, 0, 7)

let shortestDistances = dijkstra(graph: graph, source: 0)

print("Shortest distances from source vertex 0: \(shortestDistances)")
// Shortest distances from source vertex 0: [0, 8, 5, 9, 7]

Prim's Algorithm(普里姆算法)是一种用于解决图的最小生成树问题的算法。最小生成树是一个无向连通图的子图,它包括图中所有的顶点和部分边,使得子图形成一棵树,并且边的权重之和最小。Prim's Algorithm由捷克数学家Vojtěch Jarník于1930年提出,美国计算机科学家Robert C. Prim于1957年独立发现了该算法。

Prim's Algorithm基于贪心策略。它从任意一个顶点开始,逐步将顶点添加到生成树中,每次添加的顶点是与已经在树中的顶点相邻并且具有最小权重边的顶点。该过程一直持续到所有顶点都被添加到生成树中。

Prim's Algorithm的基本步骤如下:

初始化一个集合visited,用于存储已经添加到最小生成树中的顶点。
从任意一个顶点开始,将其添加到visited集合中。
当visited集合中的顶点数量小于图中顶点的数量时:
a. 查找具有最小权重的边,使得该边连接已在visited中的顶点和不在visited中的顶点。
b. 将该边以及与其相连的顶点添加到最小生成树中,并将该顶点添加到visited集合中。
当算法结束时,得到的最小生成树包含了图中所有顶点和一部分边,使得生成树的边的权重之和最小。

Prim's Algorithm在时间复杂度方面较高。使用优先队列来优化查找具有最小权重的边时,算法的时间复杂度为O(|V|^2),其中|V|表示图中顶点的数量。对于稀疏图,可以通过使用二叉堆、斐波那契堆等高级数据结构将时间复杂度降低到O(|V|log|V| + |E|),其中|E|表示图中边的数量。

struct Graph {
    let vertices: Int
    var adjacencyList: [[(Int, Int)]]

    init(vertices: Int) {
        self.vertices = vertices
        adjacencyList = Array(repeating: [], count: vertices)
    }

    mutating func addEdge(_ source: Int, _ destination: Int, _ weight: Int) {
        adjacencyList[source].append((destination, weight))
        adjacencyList[destination].append((source, weight))
    }
}

func prim(graph: Graph) -> Int {
    var visited = Array(repeating: false, count: graph.vertices)
    visited[0] = true
    var minCost = 0

    for _ in 1..<graph.vertices {
        var minWeight = Int.max
        var minSource = -1
        var minDestination = -1

        for source in 0..<graph.vertices where visited[source] {
            for (destination, weight) in graph.adjacencyList[source] where !visited[destination] {
                if weight < minWeight {
                    minWeight = weight
                    minSource = source
                    minDestination = destination
                }
            }
        }

        if minSource != -1 && minDestination != -1 {
            visited[minDestination] = true
            minCost += minWeight
        }
    }

    return minCost
}
var graph = Graph(vertices: 5)

graph.addEdge(0, 1, 2)
graph.addEdge(0, 3, 6)
graph.addEdge(1, 2, 3)
graph.addEdge(1, 3, 8)
graph.addEdge(1, 4, 5)
graph.addEdge(2, 4, 7)
graph.addEdge(3, 4, 9)

let minimumCost = prim(graph: graph)

print("Minimum cost of the minimum spanning tree: \(minimumCost)")
// Minimum cost of the minimum spanning tree: 16

github仓库地址 https://github.com/SunZhiC/DataStructuresInSwift

References

Data Structures & Algorithms in Swift by Matthijs Hollemans.
https://github.com/apple/swift-algorithms
https://github.com/raywenderlich/swift-algorithm-club

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342