哈夫曼树建立,编码,解码完整代码

这里我用的实例为:
a-z以及空格的权值为:64 13 22 32 103 21 15 47 57 1 5 32 20 57 63 15 1 48 51 80 23 8 18 1 16 1 168
哈夫曼树的结构定义

typedef struct {
    int weight;
    int parent, left, right;
}Htnode, * Huffmantree;
typedef char** Huffmancode;

建立哈夫曼树

void select(Huffmantree a, int k, int& s1, int& s2) {//挑选两个最小的叶子
    for (int i = 0; i < k; i++) {
        if (a[i].parent == -1) {///选出一个第一个没有父子节点的
            s1 = i;
            break;
        }
    }
    for (int i = 0; i < k; i++) {
        if (a[i].parent == -1 && a[s1].weight > a[i].weight) {//找到没有父节点中,值最小的节点
            s1 = i;
        }
    }
    a[s1].parent = 1;//当被选后,这个节点的的父节点应该标记为有
    for (int i = 0; i < k; i++) {
        if (a[i].parent == -1 && i != s1) {//同理s1,但注意不能和s1重合
            s2 = i;
            break;
        }
    }
    for (int i = 0; i < k; i++) {
        if (a[i].parent == -1 && a[s2].weight > a[i].weight) {
            s2 = i;
        }
    }
    a[s2].parent = 1;
}
void creatHuffmantree(Huffmantree& ht, int n) {//建立权值
    int s1 = 0, s2 = 0;
    if (n <= 1)
        return;
    int m = 2 * n - 1;
    ht = new Htnode[m + 1];
    for (int i = 0; i < m; i++) {//初始化各个节点,没有标记为-1,
        ht[i].parent = -1;
        ht[i].left = -1;
        ht[i].right = -1;
        ht[i].weight = 0;
    }
    for (int i = 0; i < n; i++) {
        //cout<
        cin >> ht[i].weight;//给出各个节点的权值
        //cout<
    }
    for (int i = n; i < m; i++) {
        select(ht, i, s1, s2);//选出前i个节点中最小的两个叶子节点
        ht[s1].parent = i;//两个叶子节点的父节点为i
        ht[s2].parent = i;
        ht[i].left = s1;//s1,s2 分别为只有子节点
        ht[i].right = s2;
        ht[i].weight = ht[s1].weight + ht[s2].weight;//父节点的权值变为左右节点权值之和
        //cout << char(i + 'a') << " " << ht[i].left << " " << ht[i].right << " " << ht[i].weight << endl;
    }
}

哈夫曼树编码

void creatHuffmancode(Huffmantree HT, Huffmancode& HC, int n)
{
    //用来保存指向每个赫夫曼编码串的指针
    HC = (Huffmancode)malloc(n * sizeof(char*));
   

    //临时空间,用来保存每次求得的赫夫曼编码串
    //对于有n个叶子节点的赫夫曼树,各叶子节点的编码长度最长不超过n-1
    //外加一个'\0'结束符,因此分配的数组长度最长为n即可
    char* code = (char*)malloc(n * sizeof(char));
    if (!code)
    {
        printf("code malloc faild!");
        exit(-1);
    }

    code[n - 1] = '\0';  //编码结束符,亦是字符数组的结束标志
                         //求每个字符的赫夫曼编码
    int i;
    for (i = 0; i < n; i++)
    {
        int current = i;           //定义当前访问的节点
        int father = HT[i].parent; //当前节点的父节点
        int start = n - 1;           //每次编码的位置,初始为编码结束符的位置
                                     //从叶子节点遍历赫夫曼树直到根节点
        while (father != -1)
        {
            if (HT[father].left == current)   //如果是左孩子,则编码为0
                code[--start] = '0';
            else                              //如果是右孩子,则编码为1
                code[--start] = '1';
            current = father;
            father = HT[father].parent;
        }

        //为第i个字符的编码串分配存储空间
        HC[i] = (char*)malloc((n - start) * sizeof(char));

        //将编码串从code复制到HC
        strcpy(HC[i], code + start);
    }
    for (int i = 0; i < n; ++i) {
        if (i == 26) {
            cout << " :";
        }
        else
        cout << char('a' + i) << ":";
        printf("%s\n", HC[i]);
    }
    free(code); //释放保存编码串的临时空间
}

哈夫曼树解码

void encode(string s) {//字符变编码
    int len = s.size();
    //64 13 22 32 103 21 15 47 57 1 5 32 20 57 63 15 1 48 51 80 23 8 18 1 16 1 168 
    for (int i = 0; i < len; i++) {
        if (s[i] == ' ')
        {
            cout << hc[26];
            //cout<<"i:"<
            //continue;
        }
        else {//输出对应字符的编码
            int x = s[i] - 'a';
            cout << hc[x];
        } //cout<
    }
}
void decode(string s) {//编码变为字符
    // int len=s.size();
    string ans = "";
    string ts = "";
    string temp[27];
    //把char变为string类型,后面字符匹配方便
    for (int i = 0; i < 27; i++) {
        int len = strlen(hc[i]);
        for (int j = 0; j < len; j++) {
            temp[i] += hc[i][j];
        }
    }
    for (int i = 0; i < s.size(); i++)
    {
        ts += s[i];//一直读取后面的编码直到有字符与其对应
        for (int j = 0; j < 27; j++)//每次都和编码进行匹配,因为哈夫曼编码一定没有前缀重合
        {
            if (ts == temp[j])//匹配成功,将目标字符串清空
            {

                ts = "";//将前面的清空,继续寻找下一组匹配的编码
                if (j != 26)
                {
                    ans += j + 'a';
                }

                else if (j == 26)
                {
                    ans += ' ';
                }
            }
        }
        //cout<
    }
    cout << ans << endl;
}

你可能感兴趣的:(哈夫曼树建立,编码,解码完整代码)