笙若 发表于 2019-1-15 08:05

霍夫曼编码的python和c++实现

本帖最后由 笙若 于 2019-1-15 08:17 编辑

最近在学算法,用python和c++各自写了一遍代码,虽然实现的并不是很好,还是贴出来记录一下吧.

```python
class Node:
    def __init__(self, name=None, value=None):
      self._name = name
      self._value = value
      self._left = None
      self._right = None


class HuffmanTree:

    # 根据Huffman树的思想:以叶子节点为基础,根据value排序,反向创建Huffman树
    def __init__(self, char_weights):
      self.a =
      # 将字典中的key和值逐个添加到节点列表a中
      while len(self.a) != 1:
            self.a.sort(key=lambda node: node._value, reverse=True)# 按叶子的值排序
            c = Node(value=(self.a[-1]._value + self.a[-2]._value))
            # 将最小的两个节点的值相加赋给新节点c
            c._left = self.a.pop(-1)
            c._right = self.a.pop(-1)# 删掉最小的两个节点
            self.a.append(c)# 将新节点添加到列表中
      self.root = self.a# 根节点=a中第一个节点
      self.b = list(range(20))# b用来存储字符的二进制序列
      self.d = {}

    # 递归的思想生成编码
    def pre(self, tree, length):
      node = tree
      if (not node):
            return# 树为空则直接返回

      elif node._name:# 当节点是一个字符时进行编码
            str_num = ""
            for i in range(length):
                str_num += str(self.b)
            # print(node._name + '编码为:', str_num)
            self.d = str_num
            return
      # 在找到字符节点前进行递归
      self.b = 0
      self.pre(node._left, length+1)

      self.b = 1
      self.pre(node._right, length+1)

    # 生成霍夫曼编码
    def get_code(self):
      self.pre(self.root, 0)
      print(self.d)
      

def fRead(filename):
    symbolDict = {}
    fl = 0
    f = open(filename, 'r')
    str = f.read()
    f.close()
    for i in str:
      for j, k in symbolDict.items():
            if i == j:
                fl = 1
                k = k + 1
                break
      if fl == 0:
            symbolDict = 1
      else:
            symbolDict = k
    return symbolDict


if __name__ == '__main__':

    dict = fRead('test.py')
    tree = HuffmanTree(dict)
    tree.get_code()

```


顺便吐槽一下vscode真的很严格,写python时连有几个空行都要管.

~~~c++
```
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXBIT 100
#define MAXVALUE 1000
#define MAXLEAF 30
#define MAXNODE MAXLEAF*2-1
typedef struct //定义节点
{
      double weight;
      int parent;
      int lchild;
      int rchild;
      char value;
}HNodeType;
typedef struct //定义编码类型
{
      int bit; //存储01编码的数组
      int start; //编码在数组中开始的位置,从最后往前减小
}HCodeType;
HNodeType HuffNode; //定义一个足够大的节点数组
HCodeType HuffCode;
void HuffmanTree (HNodeType HuffNode,int n) //构造霍夫曼树
{
      int i,j,x1,x2;
      double m1,m2;
      for(i=0;i<2*n-1;i++) //初始化节点数据
      {
                HuffNode.weight = 0;
                HuffNode.parent = -1;
                HuffNode.lchild = -1;
                HuffNode.rchild = -1;
      }
      for(i=0;i<n;i++) //输入节点数据
      {
                cout<<"please input the value and weight of leaf node "<<i+1<<endl;
                cin>>HuffNode.value>>HuffNode.weight;
      }
      for(i=0;i<n-1;i++) //循环合并n-1次
      {
                m1=m2=MAXVALUE;
                x1=x2=0;
                for(j=0;j<n+i;j++) //在已有的节点里找权重最小的且没有parent的节点
                {
                        if(HuffNode.weight<m1&&HuffNode.parent==-1)
                        {
                              m2=m1;
                              x2=x1;
                              m1=HuffNode.weight;
                              x1=j;
                        }
                        else if (HuffNode.weight<m2&&HuffNode.parent==-1)
                        {
                              m2=HuffNode.weight;
                              x2=j;
                        }
                } //最后m1,m2为最新权重节点的权重,x1,x2为其位置
                HuffNode.parent=n+i;
                HuffNode.parent=n+i;
                HuffNode.weight=m1+m2;
                HuffNode.lchild=x1;
                HuffNode.rchild=x2;
                cout<<"x1.weight and x2.weight in round "<<i+1<<"\t"<<HuffNode.weight<<"\t"<<HuffNode.weight<<endl;
      }
}
void HuffmanCode(HCodeType HuffCode,int n) //对生成的树进行编码
{
      HCodeType cd; //临时结构体
      int i,j,c,p;
      for(i=0;i<n;i++)
      {
                cd.start=n-1;
                c=i;
                p=HuffNode.parent; //p为遍历过程中每个节点的parent值
                while(p!=-1) //如果未到根节点
                {
                        if(HuffNode.lchild==c) //为parent的左节点则在该处编码为0
                              cd.bit=0;
                        else
                              cd.bit=1;
                        cd.start--; //编码长度加1,start位置减1
                        c=p;
                        p=HuffNode.parent;
                }
                for(j=cd.start+1;j<n;j++)
                        HuffCode.bit=cd.bit;
                HuffCode.start=cd.start; //将临时变量复制到编码结构体
      }
}
int main()
{
      int i,j,n;
      cout<<""<<endl;
      cin>>n;
      HuffmanTree(HuffNode,n);
      HuffmanCode(HuffCode,n);
      for(i=0;i<n;i++)
      {
                cout<<HuffNode.value<<" :Huffman code is: ";
                for(j=HuffCode.start+1;j<n;j++)
                        cout<<HuffCode.bit;
                cout<<endl;
      }
      return 0;
}
```
~~~


然后python写起来简单多了.

笙若 发表于 2019-4-23 21:54

Fris 发表于 2019-4-23 17:22
第12行应该是:
self.a =

感谢大佬提醒,不过因为并没有超出dict的作用域,所以像我那么写也是可以正确运行的吧

Fris 发表于 2019-4-24 07:57

笙若 发表于 2019-4-23 21:54
感谢大佬提醒,不过因为并没有超出dict的作用域,所以像我那么写也是可以正确运行的吧

当前例子可以运行,但作为独立模块被其他模块调用就会出问题

wikiyc 发表于 2019-1-15 08:31

收藏了,顺道坐个沙发

chenmg 发表于 2019-1-15 08:42

可以,很强

565266718 发表于 2019-1-15 09:25

可以,很强

rbgaoshou 发表于 2019-1-15 09:43

学些学习是必要的!

观井映天 发表于 2019-1-15 09:44

python写起来简单,但是提高水平的还是c++

笙若 发表于 2019-1-15 09:49

观井映天 发表于 2019-1-15 09:44
python写起来简单,但是提高水平的还是c++

应该说侧重点不同吧,python水平高了也很厉害的

hackysh 发表于 2019-1-15 09:52

越简单的东西,集成的越多,然后运行效率越低,

快乐就对了呀 发表于 2019-1-15 19:02

学习一哈

hillman323 发表于 2019-1-16 13:52

厉害,学习下
页: [1] 2
查看完整版本: 霍夫曼编码的python和c++实现