哈夫曼树Huff的创建

①定义以及作用
哈夫曼树:哈夫曼树是字符的编码,目的是为了获取最小的WPL,即最小的代价(表达能力有限,不知道咋说),顾名思义来理解吧,就是为了编码!!!
哈夫曼的创建
哈夫曼树的创建是基于堆来实现的,所以事先需要对堆有所了解,查看上篇博客QAQ。。
哈夫曼树树的建树原理,想必大家都知道,就是根据权值数组来建立的:

过程是:1.从权值数组中挑选出两个最小的权值,建立两个树节点,作为左右儿子,父节点的值为左右儿子值的和。
2.将父节点的权值放入权值数组中,然后从步骤1继续开始,直到权值数组为空。

那么,哪里会用到堆????
①利用堆,来存储权值数组,实现最小权值的获取和新的权值的插入,时间复杂度为logn
------>也许有的童鞋会想 (因为我这个童鞋也在想,QAQ,到底为什么?)

假如我用结构体数组来存储权值,在插入新权值,用二分插入,时间复杂度也是logn呀!!

-------------------大家原谅我的无知,因为堆的实现就是数组TvT!----------------------
②大家应该知道,堆的Insert()插入函数,插入的一个数据data,对于哈夫曼树的创建,则插入的是一个哈夫曼树节点,即如下的一个节点:(也就是平常无奇的一个树节点而已)

typedef struct Huff_Node *huff;
struct Huff_Node{
    huff left; //右儿子
    huff right; //左儿子
    int w; //该节点的权值
};

看到这里,小伙伴们应该知道了,哈夫曼树,其实就是利用堆来搭建起来的(简言之,利用堆来找节点的左儿子和右儿子,然后遍历完数组就完事了!然后整棵树就建立完成,返回根节点,具体看下面代码来深入理解,一言不合就撸代码(→ .→))
Huff树构建
如前面所说,堆存储的哈夫曼节点,故堆heap结构体的定义如下:

typedef struct Heap_Node *heap;
struct Heap_Node{
    huff data; //哈夫曼节点指针变量
    int size;
};

创建空堆heap的代码如下:

heap creat_empty_heap(int n){
    heap tmp = (heap)malloc(sizeof(struct Heap_Node));    
     //开辟大小为n+1个哈夫曼结构体大小的数组  
    tmp->data = (huff)malloc(sizeof(struct Hudd_Node) * (n + 1))
    tmp->size = 0;    
    tmp->data[0].w = -999; //哨兵
    return tmp;
}

向堆中插入huff哈夫曼节点代码如下:

void Insert(heap h,struct Huff_Node hu){ //简单的insert操作,堆的插入操作
    int i= ++h->size;    
    int w = hu.w;    
    for (; h->data[i / 2].w > w;i = i/2){
           h->data[i] = h->data[i / 2];
    }    
    h->data[i] = hu;
}

获取最小堆中权值最小的哈夫曼节点,即根节点:

huff delete_minheap(heap h){
    huff ans = (huff)malloc(sizeof(struct Huff_Node));    
    *ans = h->data[1];    
    struct Huff_Node x=  h->data[h->size--];    
    int parent = 1, child;    
    for (; parent * 2 <= h->size;parent = child){
        child = parent *2;        
        if(child + 1 <=h->size && h->data[child + 1].w < h->data[child].w)            
            child++;        
        if(h->data[child] >= x.w)            
            break;        
        h->data[parent] = h->data[child];
    }    
    h->data[parent] = x;    
    return ans;
}

创建哈夫曼树,过程如下:

1.定义一个huff节点,左儿子为堆中最小权值节点,右儿子为删除最小权值节点后,二次获取的最小权值节点,该huff节点的权值为两儿子节点权值之和。
2.将生成的新的huff节点插入堆中,继续步骤1,进行h->size - 1步,因为最后堆中只剩一个哈夫曼节点,也就是传说总的huff树根节点
3.最后获取堆中最后一个节点,直接原地返回

代码如下:

huff create_huff(heap h){
    huff tmp;    
    int len = h->size;    
    for (int i = 1; i <len; i++){
        tmp = (huff)malloc(sizeof(struct Huff_Node));        
        tmp ->left = delete_minheap(h);        
        tmp ->right = delete_minheap(h);        
        tmp->w = tmp->left->w + tmp->right->w;        
        Insert(h, *tmp);
    }    
    tmp = delete_minheap(h);    
    return tmp;
}

主函数如下:

int main(){
    int n,data;    
    heap h;    
    huff hu;    
    cin >> n;    
    h = creat_empty_heap(n);    
    for (int i = 1; i<=n; i++){
        cin>>data;
        hu = (huff)malloc(sizeof(struct Huff_Node));        
        hu->w = data;        
        hu->left = NULL;        
        hu->right = NULL;        
        Insert(h, *hu);    
    }    
    hu = create_huff(p);    
    return 0;
}
好的,下面是C语言实现输入n个叶子结点的权值构造哈夫曼树;根据哈夫曼树构造哈夫曼编码,并对密文完成解码工作的代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> // 哈夫曼树的节点 typedef struct huff_node { int weight; // 权值 int parent; // 父节点 int lchild; // 左子节点 int rchild; // 右子节点 } HuffNode; // 哈夫曼编码的结构体 typedef struct huff_code { char ch; // 字符 char code[256]; // 编码 } HuffCode; // 从哈夫曼树的叶子节点向上搜索,生成哈夫曼编码 void generate_huff_code(HuffNode* huff_tree, HuffCode* huff_code, int n) { char code[256]; int parent, i, j; for (i = 0; i < n; i++) { // 从叶子节点向上搜索 parent = huff_tree[i].parent; j = i; // 生成哈夫曼编码 while (parent != -1) { if (huff_tree[parent].lchild == j) { strcat(code, "0"); } else { strcat(code, "1"); } j = parent; parent = huff_tree[parent].parent; } // 将编码反转 int len = strlen(code); for (j = 0; j < len; j++) { huff_code[i].code[j] = code[len - j - 1]; } huff_code[i].code[len] = '\0'; strcpy(code, ""); } } // 构建哈夫曼树 void create_huff_tree(HuffNode* huff_tree, int* weight, int n) { int i, j, min1, min2; // 初始化哈夫曼树 for (i = 0; i < 2 * n - 1; i++) { huff_tree[i].weight = 0; huff_tree[i].parent = -1; huff_tree[i].lchild = -1; huff_tree[i].rchild = -1; } // 构建哈夫曼树 for (i = 0; i < n; i++) { huff_tree[i].weight = weight[i]; } for (i = 0; i < n - 1; i++) { min1 = min2 = 0; for (j = 0; j < n + i; j++) { if (huff_tree[j].parent == -1) { // 找到两个权值最小的节点 if (huff_tree[j].weight < huff_tree[min1].weight) { min2 = min1; min1 = j; } else if (huff_tree[j].weight < huff_tree[min2].weight) { min2 = j; } } } // 合并两个节点 huff_tree[n + i].weight = huff_tree[min1].weight + huff_tree[min2].weight; huff_tree[n + i].lchild = min1; huff_tree[n + i].rchild = min2; huff_tree[min1].parent = n + i; huff_tree[min2].parent = n + i; } } // 对密文进行解码 void decode_huff_code(HuffNode* huff_tree, char* code) { int i, p = 2 * strlen(code) - 2; for (i = 0; i < strlen(code); i++) { if (code[i] == '0') { p = huff_tree[p].lchild; } else { p = huff_tree[p].rchild; } if (huff_tree[p].lchild == -1 && huff_tree[p].rchild == -1) { printf("%c", (char) huff_tree[p].weight); p = 2 * strlen(code) - 2; } } } int main() { int n, i; printf("请输入叶子节点的个数n:"); scanf("%d", &n); int* weight = (int*) malloc(n * sizeof(int)); printf("请输入%d个叶子节点的权值:", n); for (i = 0; i < n; i++) { scanf("%d", &weight[i]); } // 构建哈夫曼树 HuffNode* huff_tree = (HuffNode*) malloc((2 * n - 1) * sizeof(HuffNode)); create_huff_tree(huff_tree, weight, n); // 生成哈夫曼编码 HuffCode* huff_code = (HuffCode*) malloc(n * sizeof(HuffCode)); generate_huff_code(huff_tree, huff_code, n); // 输出哈夫曼编码 printf("哈夫曼编码如下:\n"); for (i = 0; i < n; i++) { printf("%c:%s\n", (char) huff_tree[i].weight, huff_code[i].code); } // 对密文进行解码 char code[256]; printf("请输入密文:"); scanf("%s", code); decode_huff_code(huff_tree, code); printf("\n"); return 0; } ``` 希望这个代码可以帮助你了解哈夫曼树和哈夫曼编码的实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值