哈夫曼编码

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

typedef char ElemType;

typedef struct HTNODE{
    ElemType data;//数据域
    struct HTNODE* lchild;//左孩子
    struct HTNODE* rchild;//右孩子
}HtNode,*HtNodePtr;//哈夫曼树节点结构体

typedef struct TREE{
    HtNodePtr root;//哈夫曼树的根节点
}HtTree,*HtTreePtr;

typedef struct HTTABLE{
    ElemType data;
    char* s;//存储数据data的编码
    struct HTTABLELIST* next;
}HtTable,*HtTablePtr;//哈夫曼表的链表的节点

typedef struct HTTABLELIST{
    struct HTTABLE* head;
    struct HTTABLE* tail;
}HtTaLi,*HtTaLiPtr;//哈夫曼表的链表

typedef struct NODE{
    HtNodePtr data;//树节点
    int num;//哈夫曼树节点的权值
    struct NODE* next;
}Node,*NodePtr;//链表节点

typedef struct LIST{
    NodePtr head;//链表头结点
    int size;//链表长度
}List,*ListPtr;//链表

ListPtr Init();//初始化并创建链表

HtTaLiPtr InitTable();//初始化哈夫曼表

void Insert(ListPtr L, char ch, int num);//在链表中插入权值为num,字符为ch的节点,并且它的插入是按权值从大到小的顺序插入的

NodePtr GetFirst(ListPtr L);//得到并删除链表中第一个元素

void InsertNode(ListPtr L, NodePtr node);//按照权值的大小将节点node插入链表中

HtNodePtr CreatTree(ListPtr L);//建立哈夫曼树

void TraverseTree(HtNodePtr Ht, char code[], int k, HtTaLiPtr HtTableList);

void CreatTable(HtTreePtr tree);//创建哈夫曼表

void EnCode(HtTaLiPtr HtTableList);//编码

void DeCode(HtTreePtr tree);//解码

void PrintTree(HtNodePtr Ht, char* s, char* s1, FILE* fp);//先序遍历,凹入形式打印哈夫曼树

void WriteTree(HtTreePtr tree);//把哈夫曼树写到文件中

void TreaseWrite(HtNodePtr Ht, FILE* fp);//以先序遍历的方式把哈夫曼树写到文件中

void PrintCodeFile();// 将文件CodeFile显示在终端上,每行 50 个代码。同时将此字符形式的编码文件写入文件 CodePrin 中。

int main()
{
    ListPtr L = Init();//建立并初始化链表

    puts("读取data.txt数据");
    char p1[4] = { '\0' };
    char p2[4] = { '\0' };
    FILE* fp;
    if ((fp = fopen("C://Users/17681/Desktop/data.txt", "r")) == NULL)
    {
        puts("打开data.txt失败!");
    }
    Insert(L, ' ', 186);
    printf("%c %d  ", ' ', 186);
    while (!feof(fp))
    {
        fscanf(fp, "%s", p1);
        fscanf(fp, "%s", p2);
        printf(" %s %d  ", p1,atoi(p2));
        Insert(L, p1[0], atoi(p2));
    }
    fclose(fp);
    //int n;
    //ListPtr L = Init();//建立并初始化链表
    //puts("请输入字符集大小(为了方便规定不大于256)");
    //scanf("%d", &n);
    //for (int i = 0; i < n; i++)
    //{
    //    printf("请输入第%d个字符\n", i + 1);
    //    char ch;
    //    fflush(stdin);
    //    scanf("%c", &ch);
    //    printf("请输入它的权值\n");
    //    int num;
    //    scanf("%d", &num);
    //    Insert(L, ch, num);
    //}


    HtTreePtr tree = (HtTreePtr)malloc(sizeof(HtTree));
    
    tree->root = CreatTree(L);
    WriteTree(tree);
    HtTaLiPtr HtTableList = InitTable();
    CreatTable(tree, HtTableList);
    
    EnCode(HtTableList);
    DeCode(tree);
    puts("打印代码文件");
    PrintCodeFile();
    puts("先序遍历,凹入形式打印哈夫曼树叶子节点");
    char s[100] = {'\0'};
    FILE* fp1;
    if ((fp1 = fopen("C://Users/17681/Desktop/TreePrint.txt", "w")) == NULL)
    {
        puts("CodeFile.txt文件打开失败!");
    }
    PrintTree(tree->root, s, s, fp1);
    fclose(fp1);
    system("pause");
    return 0;
}


ListPtr Init()
{
    ListPtr L = (ListPtr)malloc(sizeof(List));
    L->head = (NodePtr)malloc(sizeof(Node));
    L->head->next = NULL;
    L->size = 0;
    return L;
}

HtTaLiPtr InitTable()
{
    HtTaLiPtr HtTableList = (HtTaLiPtr)malloc(sizeof(HtTaLi));
    HtTableList->head = HtTableList->tail = (HtTablePtr)malloc(sizeof(HtTable));
    HtTableList->tail->next = NULL;
    return HtTableList;
}

void Insert(ListPtr L, char ch, int num)
{
    NodePtr newnode = (NodePtr)malloc(sizeof(Node));
    newnode->num = num;
    newnode->data = (HtNodePtr)malloc(sizeof(HtNode));
    newnode->data->data = ch;
    newnode->data->lchild = NULL;
    newnode->data->rchild = NULL;
    NodePtr tempnode = L->head;
    while (tempnode->next != NULL)
    {
        if (newnode->num >= tempnode->next->num)
        {
            tempnode = tempnode->next;
        }
        else
        {
            break;
        }
    }
    newnode->next = tempnode->next;
    tempnode->next = newnode;
    L->size++;
}

NodePtr GetFirst(ListPtr L)
{
    NodePtr node = L->head->next;
    L->head = L->head->next;
    L->size--;
    return node;
}

void InsertNode(ListPtr L, NodePtr node)
{
    NodePtr tempnode = L->head;
    while (tempnode->next != NULL)
    {
        if (node->num >= tempnode->next->num)
        {
            tempnode = tempnode->next;
        }
        else
        {
            break;
        }
    }
    node->next = tempnode->next;
    tempnode->next = node;
    L->size++;
}

HtNodePtr CreatTree(ListPtr L)
{
    NodePtr node1;
    NodePtr node2;
    NodePtr newnode;
    while (L->size > 1)
    {
        node1 = GetFirst(L);
        node2 = GetFirst(L);
    
        newnode = (NodePtr)malloc(sizeof(Node));
        newnode->num = node1->num + node2->num;
        newnode->data = (HtNodePtr)malloc(sizeof(HtNode));
        newnode->data->data = '#';
        newnode->data->lchild = node1->data;
        newnode->data->rchild = node2->data;
        InsertNode(L, newnode);
    }
    return newnode->data;
}

void TraverseTree(HtNodePtr Ht, char code[], int k, HtTaLiPtr HtTableList)
{
    if (Ht->lchild == NULL && Ht->rchild == NULL)
    {
        code[k] = '\0';
        //printf("%s\n", code);
        HtTablePtr newnode = (HtTablePtr)malloc(sizeof(HtTable));
        newnode->next = NULL;
        newnode->data = Ht->data;
        newnode->s = (char*)malloc((strlen(code) + 1) * sizeof(char));
        strcpy(newnode->s, code);
        //printf("%s\n", newnode->s);
        HtTableList->tail->next = newnode;
        HtTableList->tail = newnode;
        return;
    }
    if (Ht->lchild != NULL)
    {
        code[k] = '0';
        TraverseTree(Ht->lchild, code, k + 1, HtTableList);
    }
    if (Ht->rchild != NULL)
    {
        code[k] = '1';
        TraverseTree(Ht->rchild, code, k + 1, HtTableList);
    }
}

void CreatTable(HtTreePtr tree, HtTaLiPtr HtTableList)
{
    int k = 0;
    char code[256] = {'\0'};
    TraverseTree(tree->root, code, k, HtTableList);
}

void EnCode(HtTaLiPtr HtTableList)
{
    fflush(stdin);
    HtTablePtr node;
    //puts("请输入字符串,最长30");
    FILE* fp;
    FILE* fp1;
    if ((fp = fopen("C://Users/17681/Desktop/ToBeTran.txt", "r")) == NULL)
    {
        puts("ToBeTran.txt文件打开失败!");
    }
    if ((fp1 = fopen("C://Users/17681/Desktop/CodeFile.txt", "w")) == NULL)
    {
        puts("odeFile.txt文件打开失败!");
    }
    char ch = fgetc(fp);
    while (!feof(fp))
    {
        
            node = HtTableList->head->next;
            while (node != NULL)
            {
                if (ch == node->data)
                {
                    fprintf(fp1,"%s\n", node->s);
                    break;
                }
                else
                {
                    node = node->next;
                }
            }
            ch = fgetc(fp);
    }
    fclose(fp);
    fclose(fp1);
    
}

void PrintTree(HtNodePtr Ht,char* s, char* s1, FILE* fp)
{
    if (Ht == NULL)
    {
        return;
    }
    
    printf("%s%c\n", s1, Ht->data);
    fprintf(fp, "%s%c\n", s1, Ht->data);
    for (int i = 0; i < 2; i++)
    {
        *s = ' ';
        s++;
    }
    PrintTree(Ht->lchild, s, s1, fp);
    PrintTree(Ht->rchild, s, s1, fp);
}


void DeCode(HtTreePtr tree)
{
    FILE* fp;
    if ((fp = fopen("C://Users/17681/Desktop/CodeFile.txt", "r")) == NULL)
    {
        puts("CodeFile.txt文件打开失败!");
    }
    FILE* fp1;
    if ((fp1 = fopen("C://Users/17681/Desktop/TextFile.txt", "w")) == NULL)
    {
        puts("TextFile.txt文件打开失败!");
    }
    HtNodePtr node = tree->root;
    fflush(stdin);
    char ch[256];
    fscanf(fp, "%s", ch);
    while (!feof(fp))
    {
        
        for (int i = 0; i < strlen(ch); i++)
        {
            if (node->lchild == NULL && node->rchild == NULL)
            {
                fprintf(fp1, "%c", node->data);
                //printf("%c", node->data);
                node = tree->root;
            }
            if (ch[i] == '0')
            {
                node = node->lchild;
            }
            if (ch[i] == '1')
            {
                node = node->rchild;
            }
        }
        
        fscanf(fp, "%s", ch);
    }
    fprintf(fp1, "%c", node->data);
    fclose(fp);
    fclose(fp1);
}

void WriteTree(HtTreePtr tree)
{
    FILE* fp;
    if ((fp = fopen("C://Users/17681/Desktop/hfmTree.txt","ab+")) == NULL)
    {
        puts("hfmTree.txt文件打开失败!");
        return;
    }
    TreaseWrite(tree->root, fp);
    fclose(fp);
    puts("哈夫曼树写入文件");
    
}

void TreaseWrite(HtNodePtr Ht, FILE* fp)
{
    if (Ht == NULL)
    {
        return;
    }
    if ((fwrite(Ht, sizeof(HtNode), 1, fp) != 1))
    {
        puts("哈夫曼树写入文件失败!");
    }
    TreaseWrite(Ht->lchild,fp);
    TreaseWrite(Ht->rchild,fp);
}

void PrintCodeFile()
{
    FILE* fp;
    FILE* fp1;
    if ((fp = fopen("C://Users/17681/Desktop/CodeFile.txt", "r")) == NULL)
    {
        puts("CodeFile.txt文件打开失败!");
    }

    if ((fp1 = fopen("C://Users/17681/Desktop/CodePrin.txt", "w")) == NULL)
    {
        puts("CodePrin文件打开失败!");
    }
    char* s = (char*)malloc(sizeof(char) * 30);
    fscanf(fp, "%s", s);
    while (!feof(fp))
    {
        printf("%s", s);
        fprintf(fp1,"%s", s);
        fscanf(fp, "%s", s);
    }
    
    fclose(fp);
    fclose(fp1);

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值