哈夫曼树(huffman)--最优二叉树的编码实现

最优二叉树,真可谓二叉树中的精品,下面就记录下之前总结的关于最优二叉树的压缩与解压缩编码的实现。希望再回首时,记忆犹存:


#ifndef _HEAD_H_
#define _HEAD_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define N 4
#define MAX 100

#if 0
#define A 0
#define B 1
#define C 2
#define D 3
#else
enum {A,B,C,D};
#endif

//哈夫曼树结点类型
typedef struct huffman_node
{
    //结点权值,字符出现的频率作为权值
    int w;
    //结点的字符,只有叶结点有字符有意义
    char c;
    //结点的编码
    char code[10];
    struct huffman_node *lchild;
    struct huffman_node *rchild;
}huffnode_t;

//链表结点中存储的数据元素类型(哈夫曼树的结点的首地址)
typedef huffnode_t *data_t;

//链表结点的类型
typedef struct node
{
    data_t data;
    struct node *next;
}linknode_t;

//链式队列队列头的类型
typedef struct 
{
    linknode_t *front;
    linknode_t *rear; 
<span style="font-family: Arial, Helvetica, sans-serif;">}linkqueue_t;</span>
//链式队列操作
extern linkqueue_t *create_empty_linkqueue();//创建空的队列
extern int is_emtpy_linkqueue(linkqueue_t *q);//判空队列
extern int enter_linkqueue(linkqueue_t *q,data_t data);//入队
extern data_t delete_linkqueue(linkqueue_t *q);//出队

#endif</span></strong>
<span style="font-size:18px;"><strong>
</strong></span>
<span style="font-size:18px;"><strong>
</strong></span>
<span style="font-size:18px;"><strong>// 
 //再来把队列的各种寒暑表实现下 
#include "head.h"

//队列的创建
linkqueue_t *create_empty_linkqueue()
{
    linknode_t *head = NULL;
    linkqueue_t *q = NULL;

    head = (linknode_t *)malloc(sizeof(linknode_t));
    head->next = NULL;

    q = (linkqueue_t *)malloc(sizeof(linkqueue_t));
    q->front = q->rear = head;

    return q;
}
//队列的判空
int is_emtpy_linkqueue(linkqueue_t *q)
{
    return q->front == q->rear;
}

//入队
int enter_linkqueue(linkqueue_t *q,data_t data)
{
    linknode_t *temp = NULL;

    temp = (linknode_t *)malloc(sizeof(linknode_t));
    temp->data = data;

    temp->next = q->rear->next;
    q->rear->next = temp;

    q->rear = temp;

    return 0;
}
//出队
data_t delete_linkqueue(linkqueue_t *q)
{
    linknode_t *temp = NULL;

    temp = q->front;
    q->front = temp->next;

    free(temp);
    temp = NULL;

    return q->front->data;
}

#if 0
int main()
{
    linkqueue_t *q = NULL;
    int i = 0;

    q = create_empty_linkqueue();

    for(i = 0;i < 10;i++)
    {
        enter_linkqueue(q,i);
    }

    while(!is_emtpy_linkqueue(q))
    {
        printf("%-3d",delete_linkqueue(q));
    }
    putchar('\n');

    return 0;
}
#endif
<span style="font-size:18px;">//好了,说完队列的函数实现,下面就说下,huffman编码的具体实现 </span>

#include "head.h"


//给哈夫曼节点赋初始值
huffnode_t *alloc_huffman_node(char c,int w)
{
    huffnode_t *root = NULL;//动态分配一个哈夫曼节点
    root = (huffnode_t *)malloc(sizeof(huffnode_t));
    memset(root,0,sizeof(huffnode_t));//初始化的操作 可以man menset看下具体的用法

    root->c = c;
    root->w = w;
    root->rchild = root->lchild = NULL;//先让左右指针制空

    return root;//返回节点的首地址
}

//队列的 有序 入队
int enter_order_linkqueue(linkqueue_t *q,data_t data)
{
    linknode_t *temp = NULL;
    linknode_t *p = q->front;

    temp = (linknode_t *)malloc(sizeof(linknode_t));
    temp->data = data;

    while(p->next && p->next->data->w < data->w)
    {
        p = p->next;
    }

    //链表新结点在链表尾插入
    if(p->next == NULL)
    {
        //更新队列尾指针
        q->rear = temp;
    }
    
    temp->next = p->next;
    p->next = temp;

    return 0;
}

//输出节点的函数
int print_linklist(linknode_t *head)
{
    linknode_t *p = head->next;

    while(p)
    {
        printf("(%c:%d) ",p->data->c,p->data->w);

        p = p->next;
    }
    putchar('\n');

    return 0;
}
//创建哈夫曼队列
linkqueue_t *create_huffman_queue(int freq[],int n)
{
	//算法思想:
    //1.创建空的队列
    //2.循环创建n个哈夫曼树的结点
    /* 分配哈夫曼树结点,填入字符和权值
     *  huffnode_t *alloc_huffman_node(char c,int w);
     *      root = alloc_huffman_node('A',freq[A]);
     *  每分配一个哈夫曼树结点,将其首地址root有序入队(链表的有序插入,队列尾指针更新)
     *  int enter_order_linkqueue(linkqueue_t *q,data_t data);
     *      enter_order_linkqueue(q,root);
     * */
    //3.输出队列中链表的所有结点数据
    /*  int print_linklist(linknode_t *head);
     * */
    //4.返回huffman队列首地址
	//
	//算法实现
    linkqueue_t *q = NULL;
    huffnode_t *root = NULL;
    int i = 0;

    q = create_empty_linkqueue();

    for(i = 0;i < n;i++)
    {
        root = alloc_huffman_node('A' + i,freq[A + i]);
        enter_order_linkqueue(q,root);
    }

    print_linklist(q->front);

    return q;
}

//判断队列中是否只剩下一个数据元素
int is_one_node(linkqueue_t *q)
{
    return q->front->next == q->rear;
}

//结合队列创建哈夫曼树
huffnode_t *create_huffman_tree(linkqueue_t *q)
{
	//算法实现
    //1.循环判断队列是否只有一个数据结点
    //2.若不只一个,出队两次,先出队的作为左孩子,后出队的作为右孩子
    //3.创建huffman树的结点,字符存'\0',权值为左右孩子权值之和
    //4.先出队的结点首地址存入新结点lchild,后出队结点首地址存入新结点的rchild
    //5.将新huffman结点首地址有序入队
    //6.重复1~5,若队列中只有一个数据结点,过程结束
    //7.将最后一个队列中数据结点(创建好的huffman树根结点首地址)出队返回
    
    huffnode_t *ltree = NULL,
               *rtree = NULL;
    huffnode_t *root = NULL;

    while(!is_one_node(q))
    {
        ltree = delete_linkqueue(q);
        rtree = delete_linkqueue(q);

        root = alloc_huffman_node('\0',ltree->w + rtree->w);
        root->lchild = ltree;
        root->rchild = rtree;

        enter_order_linkqueue(q,root);
    }

    return delete_linkqueue(q);
}

char *code_addr[N];//code_addr[A] 存 'A'编码首地址
//                   code_addr[B] 存 'B'编码首地址

//层次遍历哈弗曼树
int level_travese(huffnode_t *root)
{
    linkqueue_t *q = NULL;
    huffnode_t *tmp = NULL;
    char *addr = NULL;

    q = create_empty_linkqueue();

    enter_linkqueue(q,root);

    while(!is_emtpy_linkqueue(q))
    {
        tmp = delete_linkqueue(q);

        printf("(%c:%d) ",tmp->c,tmp->w);

        if(tmp->lchild != NULL)
        {
            strcpy(tmp->lchild->code,tmp->code);
            strcat(tmp->lchild->code,"0");
            enter_linkqueue(q,tmp->lchild);
        }
        if(tmp->rchild != NULL)
        {
            strcpy(tmp->rchild->code,tmp->code);
            strcat(tmp->rchild->code,"1");
            enter_linkqueue(q,tmp->rchild);
        }

        if(tmp->lchild == NULL && tmp->rchild == NULL)
        {
            addr = tmp->code;

            switch(tmp->c)
            {
            case 'A':
                code_addr[A] = addr;
                break;
            case 'B':
                code_addr[B] = addr;
                break;
            case 'C':
                code_addr[C] = addr;
                break;
            case 'D':
                code_addr[D] = addr;
                break;
            }
        }
    }

    putchar('\n');

    free(q->front);
    free(q);

    return 0;
}

//统计字母出现的频率函数的实现
int count_freq(char *p,int freq[])
{
    while(*p)
    {
        switch(*p)
        {
        case 'A':
            freq[A]++;
            break;
        case 'B':
            freq[B]++;
            break;
        case 'C':
            freq[C]++;
            break;
        case 'D':
            freq[D]++;
            break;
        }
        p++;
    }

    return 0;
}

//压缩函数
int compress(char *p,char encode[])
{
    while(*p)
    {
        switch(*p)
        {
        case 'A':
            strcat(encode,code_addr[A]);
            break;
        case 'B':
            strcat(encode,code_addr[B]);
            break;
        case 'C':
            strcat(encode,code_addr[C]);
            break;
        case 'D':
            strcat(encode,code_addr[D]);
            break;
        }
        p++;
    }

    return 0;
}
//解压缩函数
int uncompress(char *p,huffnode_t *root)
{
    huffnode_t *p_node = root;

    while(*p)
    {
        if(*p == '0')
        {
            p_node = p_node->lchild;
        }

        if(*p == '1')
        {
            p_node = p_node->rchild;
        }

        if(p_node->lchild == NULL && p_node->rchild == NULL)
        {
            printf("%c",p_node->c); 
            p_node = root;
        }
        
        p++;
    }
    putchar('\n');

    return 0;
}

//主函数实现
int main()
{
    int i = 0;
    //             A B C D
    int freq[N] = {0};// = {7,2,4,5};//'A'的频率在freq[A]中保存
    linkqueue_t *q = NULL;
    huffnode_t *root = NULL;
    char buf[MAX] = {0};
    char encode[3 * MAX] = {0};

    printf("Input text:");
    scanf("%99[ABCD]",buf);

    puts(buf);

    count_freq(buf,freq);

    //构造出huffman队列
    q = create_huffman_queue(freq,N);
    

    //构造huffman树
    root = create_huffman_tree(q);
    
    //通过层次遍历获得huffman编码
    level_travese(root);

    for(i = 0;i < N;i++)
    {
        printf("%c:%s\n",'A' + i,code_addr[i]);
    }


    //压缩
   
    compress(buf,encode); 

    puts(encode);

    
    //解压缩
    uncompress(encode,root);

    return 0;
}

以上就是创建的所有过程了,当然其中有些地方还需要进一步的改进,等有时间了再慢慢的研究吧,

毕竟是想做开发的,而不是专门的研究数据结构的,其实数据结构真的很妙不可言,需要长时间慢慢的品味

大牛们当初是怎样想到的!


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值