• 跑骚时刻


    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <conio.h>
    #pragma warning(disable:4996)
    
    typedef struct HuffmanTree
    {
        int weight;//权值
        int parent;//父节点
        int left;//左子树
        int right;//右子树
    };
    
    typedef char *HuffmanCode;//Huffmancode编码
    
    //从1-x个节点选择parent节点为0,权重最小的两个节点
    void SelectNode(HuffmanTree *ht, int n, int *bt1, int *bt2){
        int i;
        HuffmanTree *ht1, *ht2, *t;
        ht1 = ht2 = NULL;//初始化两个节点为空
        for (i = 1; i <= n; ++i)//循环处理1-n个节点(包括叶节点和非叶节点)
        {
            if (!ht[i].parent)//父节点为空(节点的parent为0)
            {
                if (ht1 == NULL)//节点指针1为空
                {
                    ht1 = ht + i;//指向第i个节点
                    continue;//继续循环
                }
                if (ht2 == NULL)
                {
                    ht2 = ht + i;
                    if (ht1->weight > ht2->weight)//比较两个值的权重,使ht1指向权值大的
                    {
                        t = ht2;
                        ht2 = ht1;
                        ht1 = t;
                    }
                    continue;//继续循环
                }
                if (ht1 && ht2)//若两个值都有效
                {
                    if (ht[i].weight <= ht1->weight)//第i个节点权重小于ht1指向的节点
                    {
                        ht2 = ht1;//ht2保存ht1,因为这时ht1指向的节点成为第2小的
                        ht1 = ht + i;
                    }
                    else if (ht[i].weight < ht2->weight)//若第i个节点权重小于ht2指向的权重
                    {
                        ht2 = ht + i;
                    }
                }
            }
        }
        if (ht1 > ht2)//增加比较,使二叉树左侧为叶节点
        {
            *bt2 = ht1 - ht;
            *bt1 = ht2 - ht;
        }
        else
        {
            *bt1 = ht1 - ht;
            *bt2 = ht2 - ht;
        }
    }
    
    void CreateTree(HuffmanTree *ht, int n, int *w){
        int i, m = 2 * n - 1;//总的节点总数
        int bt1, bt2;//二叉树节点序与
        if (n <= 1)//只有一个节点就无法创建
        {
            return;
        }
        for (i = 0; i <= n; ++i)//初始化节点
        {
            ht[i].weight = w[i - 1];
            ht[i].parent = 0;
            ht[i].left = 0;
            ht[i].right = 0;
        }
        for (; i <= m; ++i)//初始化后序节点
        {
            ht[i].weight = 0;
            ht[i].parent = 0;
            ht[i].left = 0;
            ht[i].right = 0;
        }
        for (i = n + 1; i <= m; ++i)//逐个计算非叶节点,创建Huffman树
        {
            SelectNode(ht, i - 1, &bt1, &bt2);
            ht[bt1].parent = i;
            ht[bt2].parent = i;
            ht[i].left = bt1;
            ht[i].right = bt2;
            ht[i].weight = ht[bt1].weight + ht[bt2].weight;
        }
    }
    
    //
    void HuffmanCoding(HuffmanTree *ht, int n, HuffmanCode *hc){
        char *cd;
        int start, i;
        int current, parent;
        cd = (char*)malloc(sizeof(char)*n);//用来临时存放一个字符编码的结果
        cd[n - 1] = '';//设置字符串结束标志
        for (i = 1; i <= n; i++)
        {
            start = n - 1;
            current = i;
            parent = ht[current].parent;//获取当前节点的父节点;
            while (parent)
            {
                if (current == ht[parent].left)//若该节点的父节点是做左子树
                {
                    cd[--start] = '0';//设置编码为0
                }
                else//若该节点是父节点的右子树
                {
                    cd[--start] = '1';//设置编码为1
                }
                current = parent;//设置当前节点指向父节点
                parent = ht[parent].parent;//获取当前节点的父节点序号;
            }
            hc[i - 1] = (char*)malloc(sizeof(char)*(n - start));
            strcpy(hc[i - 1], &cd[start]);//复制生成生成的编码
        }
        free(cd);//释放编码占用的字符
    }
    
    void Encode(HuffmanCode *hc, char *alphabet, char *str, char *code){
        //将一个字符串转换为Huffman编码
        //hc为Huffman编码表,alphabet为对应的字母表,str为需要转换的字符串,code返回转换的结果
        int len = 0, i = 0, j;
        code[0] = '';
        while (str[i])
        {
            j = 0;
            while (alphabet[j] != str[i])
            {
                j++;
            }
            strcpy(code + len, hc[j]);//将对应字母的Huffman编码复制code指定位置
            len = len + strlen(hc[j]);//累加字符串长度
            i++;
        }
        code[len] = '';
    }
    
    void Decode(HuffmanTree *ht, int m, char *code, char *alphabet, char *decode){
        //将一个huffman编码组成的字符串转换为明文字符串
        //ht为huffman二叉树,m为字符数量,alphabet为对应的字母表,str需转换的字符串
        int position = 0, i, j = 0;
        m = 2 * m - 1;
        while (code[position])//字符串未结束
        {
            for (i = m; ht[i].left && ht[i].right; position++)
            {
                if (code[position] == '0')//编码位为0
                {
                    i = ht[i].left;
                }
                else
                {
                    i = ht[i].right;//处理右子树
                }
            }
            decode[j] = alphabet[i - 1];//得到一个字母
            j++;//处理下一个字符
        }
        decode[j] = '';//字符串结尾
    }
    
    //主函数
    int main(void){
        int i, n = 4, m;
        char test[] = "DBDACDADCCDBDCBADBCABABA";
        char code[100], code1[100];
        char alphabet[] = { 'A', 'B', 'C', 'D', };//四个字符
        int w[] = { '5', '7', '2', '13' };//四个字符的权重
        HuffmanTree *ht;
        HuffmanCode *hc;
        m = 2 * n - 1;
        ht = (HuffmanTree *)malloc((m + 1)*sizeof(HuffmanTree));//申请内存,保存赫夫曼树
        if (!ht)
        {
            printf("内存分配失败!");
            exit(0);
        }
        hc = (HuffmanCode *)malloc(n*sizeof(char*));
        if (!hc)
        {
            printf("分配内存失败!");
            exit(0);
        }
        //创建赫夫曼树
        CreateTree(ht, n, w);
        HuffmanCoding(ht, n, hc);//根据赫夫曼树生成的赫夫曼编码
        for (i = 1; i <= n; i++)
        {
            printf("字母:%c,权重:%d,编码为:%s
    ", alphabet[i - 1], ht[i].weight, hc[i - 1]);
        }
        Encode(hc, alphabet, test, code);//根据赫夫曼编码生成编码字符串
        printf("
    字符串:
    %s
    转换后为:
    %s
    ", test, code);
    
        Decode(ht, n, code, alphabet, code1);//根据编码字符串生成解码后的字符串
        printf("
    编码:
    %s
    转换后为:
    %s
    ", code, code1);
        _getch();
        return 0;
    }
  • 相关阅读:
    js中return、return true、return false的区别
    flask,中间键
    flask,自定义中间件
    flask,闪现
    flask获取前端发送过来的数据
    flask中的如何将后端写前端的代码设置session
    flask中的正则匹配
    flask中的四剑客 及其他参数
    支付宝接口
    flasks框架简介
  • 原文地址:https://www.cnblogs.com/oncoy/p/3862414.html
Copyright © 2020-2023  润新知