关于哈夫曼编码和有向图源点到某点的最短路径的体悟

这星期的算法课上学到了这两个的算法思想,感觉自己听懂了,下来自己编代码的时候却无从下手,哈夫曼编码本来想用python的字典来写,可是字典无法嵌套,然后想着用数组写,数组虽然能嵌套,可是解嵌套又写不了。。。没办法上网搜了别人写的,用了类,emmm,牛批。
哈夫曼编码就是想在表示字符时,频率高的字符用少点位数表示,频率低的用多点,这样可以减小平均编码位数,从而减小总的编码位数。
哈夫曼编码的思想大致是将所有的字符分别看作节点,在这些节点里选取两个频率最小的两个,组成一个节点(同时这两个节点就不能单独存在了,即“消失了”或者说“合体了”),最小的是左节点,次小的是右节点,然后把这个节点加入之前那一堆节点中,然后重复这个步骤使只剩下一个节点(即成树,我的理解就是嵌套完成)。获取字符编码(我理解就是解嵌套)时,从树顶开始,左节点标0(或1),右节点标1(或0)。
代码:

class node:
    def __init__(self, name, freq):
        self.name = name
        self.left = None
        self.right = None
        self.father = None
        self.freq = freq

    def is_left(self):
        return self.father.left == self

def create_node(shuju):
    data = []
    for i in shuju:
        data.append([i, shuju[i]])
    return [node(str, name) for str, name in data]

def HFM(Node):
    Node_1 = Node[:]
    while len(Node_1) > 1:
        Node_1.sort(key=lambda x: x.freq)
        node_left = Node_1.pop(0)
        node_right = Node_1.pop(0)
        node_father = node(None, node_left.freq + node_right.freq)
        node_father.left = node_left
        node_father.right = node_right
        node_left.father = node_father
        node_right.father = node_father
        Node_1.append(node_father)
    Node_1[0].father = None
    return Node_1[0]

# def BM(Node, name):
#     s = ''
#     for i in Node:
#         if i.name == name:
#             while i.father != None:
#                 if i.is_left():
#                     s = '0' + s
#                 else:
#                     s = '1' + s
#                 i = i.father
#     return s

def BMS(Node):
    codes = {}
    for i in Node:
        name = i.name
        codes[name] = ''
        while i.father != None:
            if i.is_left():
                codes[name] = '0' + codes[name]
            else:
                codes[name] = '1' + codes[name]
            i = i.father
    return codes

def main():
    shuju = {'A': 0.4, 'B': 0.1, 'C': 0.2, 'D': 0.15, '_': 0.15}
    Node = create_node(shuju)
    HFM(Node)
    s = BMS(Node)
    print(s)

if __name__ == '__main__':
    main()

然后是那个有向图源点到某点的最短路径,本来我觉得这个应该很好写,但是也是感觉编码无从下手,想了半天先写哈夫曼去了,哈夫曼写完了我感觉这个用类应该好写点,然后也用类写了。
这个问题就是有一堆点,知道某点到某点距离和方向,问从某一点(源点)出发,到某一点(终点)的路程最短走法。
算法思想是贪心算法,每次都选取最短的路径,从源点开始,记录所有点(只能通过源点)此时到源点的最小距离,选出其中路径最短的那个点,然后记录所有点(只通过源点和这个点)能到达的点及此时到源点的最小距离,选出其中路径最短的那个点,然后记录所有点(只通过这三个点)此时到源点的最小距离,重复这个步骤直至遍历所有点。
正式点说就是记录s集合和t-s集合,s是已经遍历的点,t是指所有点。


```python

```python

```python

```python
class Top:
    def __init__(self, name):
        self.name = name
        self.father = None
        self.min_d = float('inf')

def create_tree(shuju):
    data = []
    set1 = set()
    for i in shuju:
        set1.add(i[0])
        set1.add(i[1])
    for j in set1:
        data.append(j)
    return [Top(name) for name in data]

def zuiduan(yuandian, tree, shuju):
    tree_1 = tree.copy()
    for i in tree_1:
        if i.name == yuandian:
            i.min_d = 0
    while len(tree_1) != 0:
        tree_1.sort(key=lambda x: x.min_d)
        top = tree_1.pop(0)
        for j in shuju:
            if j[0] == top.name:
                for k in tree:
                    if k.name == j[1]:
                        if k.min_d > top.min_d + shuju[j]:
                            k.father = top
                            k.min_d = top.min_d + shuju[j]
    return tree

def lujing(tree, zhongdian):
    lu = ''
    for i in tree:
        if i.name == zhongdian:
            while i.father != None:
                lu = '从%s走到%s,' % (i.father.name, i.name) + lu
                i = i.father
            break
    lu = lu[:-1]
    print(lu)

def main():
    # shuju = {(1, 2): 10, (1, 4): 30, (1, 5): 100, (2, 3): 50, (3, 5): 10, (4, 3): 20,
    #          (4, 5): 60}
    shuju = {(1, 2): 1, (1, 3): 2, (2, 4): 3, (3, 4): 1}
    tree = create_tree(shuju)
    # zuiduan(1, tree, shuju)
    # for i in tree:
    #     print(i.name)
    #     print(i.min_d)

    tree_min = zuiduan(1, tree, shuju)
    lujing(tree_min, 4)

if __name__ == '__main__':
    main()


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值