哈弗曼树的建立、编码与部分代码解释

今天就来回顾一下二叉树,其实在大二上专业课的时候就做过一次哈弗曼树的编码了,这次只做简单的复习,因此忽略掉其中对文本的转换,只实现了哈弗曼树的构建和节点编码。

在哈弗曼树构建的过程中,一个很重要的点就是这个树的规模到底有多大。
对于完全二叉树有性质:

\[n0 = n2+1; \]

其中n0指的是叶子节点,即儿子节点的个数为0,n2指的是有两个儿子节点的节点。

而对于哈弗曼树,它是由每两个节点得到一个新节点逐渐构建而成的,因此只有节点数为0或者为2的节点,而且我们需要编码的字符一定都是叶子节点。因此,如果我们需要编码的字符有n个,即叶子节点的个数n0=n,我们可以推得:

\[\begin{align} &n0 + n1 + n2 \\ &= n + 0 + n - 1 \\&= 2 * n -1; \end{align} \]

因此我们可以知道我们要开的存放树的节点空间要多大。

字符编码的时候要注意主要思想是从叶子节点往根节点走,因此我们在设计结构体的时候需要有存放parent的下标的变量。这样子在查找编码的过程中,只需要从叶子节点开始,走到根节点即可。

其他的不详细解释,大概的流程是:

  • 先对所有的元素做初始化,动态数组中的前n个元素存放着我们需要编码的字符及对应信息,因此可以先对这些节点的weight或者data赋值。
  • 动态数组中n+1到2n-1的元素就是我们在哈弗曼树构建过程中新增的节点
  • 找到数据中的前两个权重最小的元素,并创建一个新的节点,对这个节点赋值
  • 字符编码

具体实现代码如下:


#include<iostream>
#include<vector>
#include<string>
#define M 65535
using namespace std;

typedef struct HuffTreeNode{
    int left;
    int right;
    int weight;
    int parent;

}HuffTreeNode, *HuffTreeP;

typedef struct HuffTreeCode{

    int data;
    char* code;

}HuffTreeCode, *HuffTreeCodeP;


void buildTree(HuffTreeP & HuffTree, int n){
    int m , t, i;
    //int arr[7] = {1,2,4,5,6,7,9};
  
     //n0 = n, 共有2n-1个节点
    m = 2 * n - 1;
    HuffTree  = (HuffTreeP)malloc((2 * n - 1)* sizeof(HuffTreeNode));
    // init leaf node

    for(i = 0; i < n; i++){
        cin >> t;
        //t = arr[i];
        HuffTree[i].parent = -1;
        HuffTree[i].right = -1;
        HuffTree[i].left = -1;
        HuffTree[i].weight = t;
    }
    // init other nodes
    for(i = n; i < m; i++){
        HuffTree[i].parent = -1;
        HuffTree[i].right = -1;
        HuffTree[i].left = -1;
        HuffTree[i].weight = M;
    }

    int min1, min2 , index1 = -1, index2 = -1;
    for(int i = n; i < m; i++){
        //find two biggest value
        min1 = M;
        min2 = min1;
        for(int j = 0; j < m ; j++){

            if(HuffTree[j].parent != -1){
                continue;
            }
            if(HuffTree[j].weight <= min1 && HuffTree[j].weight < min2){
                min2 = min1;
                min1 = HuffTree[j].weight;
                index2 = index1;
                index1 = j;
                
            }else if(HuffTree[j].weight >= min1 && HuffTree[j].weight < min2){
                min2 = HuffTree[j].weight;
                index2 = j;
   
            }

        }

        //构建这两个子节点的父节点
        HuffTree[index1].parent = i;
        HuffTree[index2].parent = i;
        HuffTree[i].left = index1;
        HuffTree[i].right = index2;
        HuffTree[i].weight = min1 + min2;

        cout << "min1=" << min1 << " min2=" << min2 << endl;
        
    }


}

void reverse(char* & s, int m){

    char* sTemp = (char * )malloc((m+1) * sizeof(char));
    int i = 0;
    cout << "s=" << s << endl;
    while(m >= 0){
        sTemp[i++] = s[m--];
    }
    s = sTemp;
}

void encode(HuffTreeP HuffTree, HuffTreeCodeP & codeTree, int n){
    //parent = -1为根节点
    codeTree = (HuffTreeCodeP)malloc(n* sizeof(HuffTreeCode));
    char * s = (char*)malloc((n+1) * sizeof(char));
    //string s = "";
    int j = 0, p = 0, m = 0;
    for(int i = 0; i < n; i++){
        m = 0;
        j = i;
        while(j < 2 * n - 2){
            p = HuffTree[j].parent;
            
            if(HuffTree[p].left == j){
                s[m]= '0';
            }else{
                s[m]= '1';
            }
            j = p;
            m++;
        
        }
                cout << "data=" << codeTree[i].data << " code=" << s << endl;
        reverse(s, m);
        codeTree[i].code = s;
        codeTree[i].data = HuffTree[i].weight;

    }

}

void printCode(HuffTreeCodeP codeTree, int n){
    for(int i = 0; i < n; i++){
        cout << "data: " << codeTree[i].data << " code: " << codeTree[i].code << endl;
    }

}

int main()
{
    int n;
    cin >> n;
// n = 7;
    HuffTreeP HuffTree;
    HuffTreeCodeP codeTree;
    buildTree(HuffTree, n);
    encode(HuffTree, codeTree, n);
    printCode(codeTree, n);
    
}

posted @ 2020-03-31 02:04  c_y_yuan  阅读(355)  评论(0编辑  收藏  举报