Use python to implement Dijkstra's algorithm

The implementation of the Dijkstra's Algorithm:

def dijkstra(g, s):
    from priority_queue import PriorityQueue, less_than

    result = []
    class Record:
        def __init__(self, v, parent = -1, cost = WEIGHT_LIMIT):
            self.vertex = v 
            self.parent = parent 
            self.cost = cost
        def __lt__(self, other):
            return self.cost < other.cost
        def get_key(self):
            return self.vertex
        key = property(get_key)

    n = len(g)
    sequence = [Record(i) for i in range(n)]
    sequence[s].cost = 0
    pq = PriorityQueue(less_than, sequence)
    while pq:
        u = pq.pop()
        for v in g.adj(u.vertex):
            nc = u.cost + v.weight
            try:
                if nc < pq[v.vertex].cost:
                    pq.modify(v.vertex, Record(v.vertex, u.vertex, nc))
            except IndexError:
                pass
        result.append(u)
    return result

def print_shortest_path_tree(result, s):
    def get_shortest_path(dic, v, cache):
        ret = cache[v]
        if len(ret) == 0:
            r = dic[v]
            if r.parent != -1:
                pret = get_shortest_path(dic, r.parent, cache)
                ret = "%s->%s" % (pret, v)
            else:
                ret = str(v)
            cache[v] = ret
        return ret
    n = len(result)
    dic = {result[i].vertex: result[i] for i in range(n)}
    cache = ["" for i in range(n)]
    i = n - 1
    while i >= 0:
        get_shortest_path(dic, i, cache)
        i -= 1
    for i in range(n):
        if i != s:
            print("%s: %s" % (cache[i], dic[i].cost))

The class WeightedGraph:

class WeightedGraph:
    class Edge:
        def __init__(self, v, w):
            self.vertex = v
            self.weight = w
        def __repr__(self):
            return "%s(%s)" % (self.vertex, self.weight)

    def __init__(self, v):
        self.vertices = [None for i in range(v)]
        self.empty_list = []

    def add_edge(self, u, v, w = 1):
        l = self.vertices[u]
        e = WeightedGraph.Edge(v, w)
        if l != None:
            l.append(e)
        else:
            l = [e]
            self.vertices[u] = l

    def __bool__(self):
        return len(self.vertices) > 0
    __nonzero__ = __bool__

    def __len__(self):
        return len(self.vertices)

    def number_of_edges(self):
        e = 0
        for l in self.vertices:
            e += len(l)
        return e

    def adj(self, v):
        l = self.vertices[v]
        if l == None:
            l = self.empty_list
        return l

    def __repr__(self):
        ret = ""
        v = len(self.vertices)
        i = 0
        while i < v:
            if self.vertices[i]:
                if len(ret) > 0:
                    ret += "\n"
                ret += ("%s: %s" % (i, self.vertices[i]))
            i += 1
        return ret

The class PriorityQueue:

from __future__ import print_function

import copy

def less_than(a,  b): return a < b
def big_than(a, b): return a > b

def get_key(v):
    ret = None
    if isinstance(v, int) or isinstance(v, float) or isinstance(v, str):
        ret = v
    elif isinstance(v, list) or isinstance(v, tuple):
        ret = v[0]
    else:
        ret = v.key
    return ret

def sink(sequence, i, comparator, positions):
    n = len(sequence)
    if i >= 0 and i < n:
        while True:
            c = (i + 1) * 2
            r = i
            if c < n and comparator(sequence[c], sequence[r]):
                r = c
            c -= 1
            if c < n and comparator(sequence[c], sequence[r]):
                r = c
            if r != i:
                if positions != None:
                    positions[get_key(sequence[i])] = r
                    positions[get_key(sequence[r])] = i
                sequence[i], sequence[r] = sequence[r], sequence[i]
                i = r
            else:
                break

def rise(sequence, i, comparator, positions):
    n = len(sequence)
    if i >= 0 and i < n:
        while i != 0:
            p = (i - 1) // 2
            if comparator(sequence[i], sequence[p]):
                if positions != None:
                    positions[get_key(sequence[i])] = p
                    positions[get_key(sequence[p])] = i
                sequence[i], sequence[p] = sequence[p], sequence[i]
                i = p
            else:
                break

def make_heap(sequence, comparator):
    n = len(sequence)
    i = 1
    while i < n:
        rise(sequence, i, comparator, None)
        i += 1
    return sequence

class PriorityQueue:
    def __init__(self, comparator, sequence):
        self.comparator = comparator
        self.elements = make_heap(sequence, self.comparator)
        self.positions = {get_key(self.elements[i]): i for i in range(len(self.elements))}

    def __len__(self):
        return len(self.elements)

    def __bool__(self):
        return len(self.elements) > 0
    __nonzero__ = __bool__

    def __repr__(self):
        return str(self.elements)

    def top(self):
        if self.elements:
            return self.elements[0]
        raise IndexError("The priority queue is empty")

    def pop(self):
        ret = None
        n = len(self.elements)
        if n > 0:
            ret = self.elements[0]
            if n > 1:
                self.elements[0] = self.elements[n - 1]
                self.elements.pop(-1)
                sink(self.elements, 0, self.comparator, self.positions)
            else:
                self.elements = []
        else:
            raise IndexError("The priority queue is empty")
        return ret

    def modify(self, key, value):
        i = self.positions.get(key)
        if i != None:
            old_value = self.elements[i]
            self.elements[i] = value
            del self.positions[key]
            self.positions[get_key(value)] = i
            if self.comparator(old_value, value):
                sink(self.elements, i, self.comparator, self.positions)
            else:
                rise(self.elements, i, self.comparator, self.positions)
        else:
            raise IndexError("The specific element %s is not in the priority queue" % key)

    def __getitem__(self, key):
        i = self.positions.get(key)
        if i != None:
            return self.elements[i]
        else:
            raise IndexError("The specific element %s is not in the priority queue" % key)
            
if __name__ == "__main__":
    sequence = [7, 2, 5, 8, 1, 0, 3, 9]
    pq = PriorityQueue(less_than, copy.copy(sequence))
    result = []
    while pq:
        e = pq.pop()
        result.append(e)
    assert result == sorted(sequence)

    pq = PriorityQueue(less_than, copy.copy(sequence))
    pq.modify(0, -1)
    print(pq)
    pq.modify(9, -2)
    print(pq)
    pq.modify(-2, 10)
    print(pq)
    pq.modify(-1, 20)
    print(pq)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值